checker: do not allow nil sum types init

pull/9544/head
Alexander Medvednikov 2021-03-31 11:13:15 +03:00
parent dcab79146b
commit 6f318be96c
34 changed files with 133 additions and 61 deletions

View File

@ -0,0 +1,5 @@
module builtin
struct string {
len int
}

View File

@ -12,25 +12,25 @@ pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl
pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral | pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral |
CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall |
ComptimeSelector | ConcatExpr | DumpExpr | EnumVal | FloatLiteral | GoExpr | Ident | ComptimeSelector | ConcatExpr | DumpExpr | EmptyExpr | EnumVal | FloatLiteral | GoExpr |
IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr |
MapInit | MatchExpr | NodeError | None | OffsetOf | OrExpr | ParExpr | PostfixExpr | MapInit | MatchExpr | NodeError | None | OffsetOf | OrExpr | ParExpr | PostfixExpr |
PrefixExpr | RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | PrefixExpr | RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral |
StringLiteral | StructInit | Type | TypeOf | UnsafeExpr StringLiteral | StructInit | Type | TypeOf | UnsafeExpr
pub type Stmt = AsmStmt | AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | pub type Stmt = AsmStmt | AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl |
DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | DeferStmt | EmptyStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt |
GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | NodeError | GlobalDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module |
Return | SqlStmt | StructDecl | TypeDecl NodeError | Return | SqlStmt | StructDecl | TypeDecl
// NB: when you add a new Expr or Stmt type with a .pos field, remember to update // NB: when you add a new Expr or Stmt type with a .pos field, remember to update
// the .position() token.Position methods too. // the .position() token.Position methods too.
pub type ScopeObject = AsmRegister | ConstField | GlobalField | Var pub type ScopeObject = AsmRegister | ConstField | GlobalField | Var
// TOOD: replace table.Param // TODO: replace table.Param
pub type Node = CallArg | ConstField | EnumField | Expr | Field | File | GlobalField | pub type Node = CallArg | ConstField | EnumField | Expr | Field | File | GlobalField |
IfBranch | MatchBranch | ScopeObject | SelectBranch | Stmt | StructField | StructInitField | IfBranch | MatchBranch | NodeError | ScopeObject | SelectBranch | Stmt | StructField |
table.Param StructInitField | table.Param
pub struct Type { pub struct Type {
pub: pub:
@ -38,6 +38,21 @@ pub:
pos token.Position pos token.Position
} }
pub struct EmptyExpr {}
pub fn empty_expr() Expr {
return EmptyExpr{}
}
pub struct EmptyStmt {
pub:
pos token.Position
}
pub fn empty_stmt() Stmt {
return EmptyStmt{}
}
// `{stmts}` or `unsafe {stmts}` // `{stmts}` or `unsafe {stmts}`
pub struct Block { pub struct Block {
pub: pub:
@ -1431,6 +1446,10 @@ pub fn (expr Expr) position() token.Position {
AnonFn { AnonFn {
return expr.decl.pos return expr.decl.pos
} }
EmptyExpr {
println('compiler bug, unhandled EmptyExpr position()')
return token.Position{}
}
NodeError, ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr, NodeError, ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr,
ChanInit, CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector, EnumVal, DumpExpr, ChanInit, CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector, EnumVal, DumpExpr,
FloatLiteral, GoExpr, Ident, IfExpr, IndexExpr, IntegerLiteral, Likely, LockExpr, MapInit, FloatLiteral, GoExpr, Ident, IfExpr, IndexExpr, IntegerLiteral, Likely, LockExpr, MapInit,
@ -1540,6 +1559,9 @@ pub:
pub fn (node Node) position() token.Position { pub fn (node Node) position() token.Position {
match node { match node {
NodeError {
return token.Position{}
}
Stmt { Stmt {
mut pos := node.pos mut pos := node.pos
if node is Import { if node is Import {
@ -1736,15 +1758,19 @@ pub fn (node Node) children() []Node {
// a dependency cycle between v.ast and v.table, for the single // a dependency cycle between v.ast and v.table, for the single
// field table.Field.default_expr, which should be ast.Expr // field table.Field.default_expr, which should be ast.Expr
pub fn fe2ex(x table.FExpr) Expr { pub fn fe2ex(x table.FExpr) Expr {
res := Expr{} unsafe {
unsafe { C.memcpy(&res, &x, sizeof(Expr)) } res := Expr{}
return res C.memcpy(&res, &x, sizeof(Expr))
return res
}
} }
pub fn ex2fe(x Expr) table.FExpr { pub fn ex2fe(x Expr) table.FExpr {
res := table.FExpr{} unsafe {
unsafe { C.memcpy(&res, &x, sizeof(table.FExpr)) } res := table.FExpr{}
return res C.memcpy(&res, &x, sizeof(table.FExpr))
return res
}
} }
// helper for dealing with `m[k1][k2][k3][k3] = value` // helper for dealing with `m[k1][k2][k3][k3] = value`

View File

@ -9,9 +9,9 @@ pub fn resolve_init(node StructInit, typ table.Type, t &table.Table) Expr {
mut has_len := false mut has_len := false
mut has_cap := false mut has_cap := false
mut has_default := false mut has_default := false
mut len_expr := Expr{} mut len_expr := empty_expr()
mut cap_expr := Expr{} mut cap_expr := empty_expr()
mut default_expr := Expr{} mut default_expr := empty_expr()
mut exprs := []Expr{} mut exprs := []Expr{}
for field in node.fields { for field in node.fields {
match field.name { match field.name {

View File

@ -469,6 +469,9 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
utyp := c.unwrap_generic(struct_init.typ) utyp := c.unwrap_generic(struct_init.typ)
c.ensure_type_exists(utyp, struct_init.pos) or {} c.ensure_type_exists(utyp, struct_init.pos) or {}
type_sym := c.table.get_type_symbol(utyp) type_sym := c.table.get_type_symbol(utyp)
if !c.inside_unsafe && type_sym.kind == .sum_type {
c.warn('direct sum type init (`x := SumType{}`) will be removed soon', struct_init.pos)
}
// Make sure the first letter is capital, do not allow e.g. `x := string{}`, // Make sure the first letter is capital, do not allow e.g. `x := string{}`,
// but `x := T{}` is ok. // but `x := T{}` is ok.
if !c.is_builtin_mod && !c.inside_unsafe && type_sym.language == .v if !c.is_builtin_mod && !c.inside_unsafe && type_sym.language == .v
@ -3386,6 +3389,10 @@ fn (mut c Checker) stmt(node ast.Stmt) {
} }
// c.expected_type = table.void_type // c.expected_type = table.void_type
match mut node { match mut node {
ast.EmptyStmt {
print_backtrace()
eprintln('Checker.stmt() EmptyStmt')
}
ast.NodeError {} ast.NodeError {}
ast.AsmStmt { ast.AsmStmt {
c.asm_stmt(mut node) c.asm_stmt(mut node)
@ -3532,9 +3539,13 @@ fn (mut c Checker) branch_stmt(node ast.BranchStmt) {
fn (mut c Checker) for_c_stmt(node ast.ForCStmt) { fn (mut c Checker) for_c_stmt(node ast.ForCStmt) {
c.in_for_count++ c.in_for_count++
prev_loop_label := c.loop_label prev_loop_label := c.loop_label
c.stmt(node.init) if node.has_init {
c.stmt(node.init)
}
c.expr(node.cond) c.expr(node.cond)
c.stmt(node.inc) if node.has_inc {
c.stmt(node.inc)
}
c.check_loop_label(node.label, node.pos) c.check_loop_label(node.label, node.pos)
c.stmts(node.stmts) c.stmts(node.stmts)
c.loop_label = prev_loop_label c.loop_label = prev_loop_label
@ -3975,6 +3986,10 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
} }
match mut node { match mut node {
ast.NodeError {} ast.NodeError {}
ast.EmptyExpr {
print_backtrace()
c.error('checker.expr(): unhandled EmptyExpr', token.Position{})
}
ast.CTempVar { ast.CTempVar {
return node.typ return node.typ
} }
@ -5567,7 +5582,7 @@ fn (mut c Checker) find_obj_definition(obj ast.ScopeObject) ?ast.Expr {
match obj { match obj {
ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister { name = obj.name } ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister { name = obj.name }
} }
mut expr := ast.Expr{} mut expr := ast.empty_expr()
if obj is ast.Var { if obj is ast.Var {
if obj.is_mut { if obj.is_mut {
return error('`$name` is mut and may have changed since its definition') return error('`$name` is mut and may have changed since its definition')
@ -6202,7 +6217,9 @@ fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) table.Type {
c.expr(expr) c.expr(expr)
} }
} }
c.expr(node.where_expr) if node.where_expr !is ast.EmptyExpr {
c.expr(node.where_expr)
}
return table.void_type return table.void_type
} }

View File

@ -1,6 +1,6 @@
vlib/v/checker/tests/sum_type_assign_non_variant_err.vv:11:6: error: cannot assign to `w`: expected `Stmt`, not `IfExpr` vlib/v/checker/tests/sum_type_assign_non_variant_err.vv:11:6: error: cannot assign to `w`: expected `Stmt`, not `IfExpr`
9 | fn main() { 9 | fn main() {
10 | mut w := Stmt{} 10 | mut w := Stmt(AnotherThing{})
11 | w = IfExpr{} 11 | w = IfExpr{}
| ~~~~~~~~ | ~~~~~~~~
12 | } 12 | }

View File

@ -7,6 +7,6 @@ type Stmt = Expr | AnotherThing
struct AnotherThing {} struct AnotherThing {}
fn main() { fn main() {
mut w := Stmt{} mut w := Stmt(AnotherThing{})
w = IfExpr{} w = IfExpr{}
} }

View File

@ -365,7 +365,7 @@ pub fn (mut f Fmt) node_str(node ast.Node) string {
//=== General Stmt-related methods and helpers ===// //=== General Stmt-related methods and helpers ===//
pub fn (mut f Fmt) stmts(stmts []ast.Stmt) { pub fn (mut f Fmt) stmts(stmts []ast.Stmt) {
mut prev_stmt := if stmts.len > 0 { stmts[0] } else { ast.Stmt{} } mut prev_stmt := if stmts.len > 0 { stmts[0] } else { ast.empty_stmt() }
f.indent++ f.indent++
for stmt in stmts { for stmt in stmts {
if !f.pref.building_v && f.should_insert_newline_before_node(stmt, prev_stmt) { if !f.pref.building_v && f.should_insert_newline_before_node(stmt, prev_stmt) {
@ -383,6 +383,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
} }
match node { match node {
ast.NodeError {} ast.NodeError {}
ast.EmptyStmt {}
ast.AsmStmt { ast.AsmStmt {
f.asm_stmt(node) f.asm_stmt(node)
} }
@ -482,6 +483,7 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
} }
match mut node { match mut node {
ast.NodeError {} ast.NodeError {}
ast.EmptyExpr {}
ast.AnonFn { ast.AnonFn {
f.fn_decl(node.decl) f.fn_decl(node.decl)
} }
@ -897,7 +899,11 @@ pub fn (mut f Fmt) const_decl(node ast.ConstDecl) {
} }
f.indent++ f.indent++
} }
mut prev_field := if node.fields.len > 0 { ast.Node(node.fields[0]) } else { ast.Node{} } mut prev_field := if node.fields.len > 0 {
ast.Node(node.fields[0])
} else {
ast.Node(ast.NodeError{})
}
for field in node.fields { for field in node.fields {
if field.comments.len > 0 { if field.comments.len > 0 {
if f.should_insert_newline_before_node(ast.Expr(field.comments[0]), prev_field) { if f.should_insert_newline_before_node(ast.Expr(field.comments[0]), prev_field) {

View File

@ -1010,6 +1010,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
// println('g.stmt()') // println('g.stmt()')
// g.writeln('//// stmt start') // g.writeln('//// stmt start')
match node { match node {
ast.EmptyStmt {}
ast.AsmStmt { ast.AsmStmt {
g.write_v_source_line_info(node.pos) g.write_v_source_line_info(node.pos)
g.gen_asm_stmt(node) g.gen_asm_stmt(node)
@ -2789,6 +2790,9 @@ fn (mut g Gen) expr(node ast.Expr) {
} }
// NB: please keep the type names in the match here in alphabetical order: // NB: please keep the type names in the match here in alphabetical order:
match mut node { match mut node {
ast.EmptyExpr {
g.error('g.expr(): unhandled EmptyExpr', token.Position{})
}
ast.AnonFn { ast.AnonFn {
// TODO: dont fiddle with buffers // TODO: dont fiddle with buffers
g.gen_anon_fn_decl(mut node) g.gen_anon_fn_decl(mut node)
@ -4158,7 +4162,7 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
mut is_push := []bool{cap: n_channels} mut is_push := []bool{cap: n_channels}
mut has_else := false mut has_else := false
mut has_timeout := false mut has_timeout := false
mut timeout_expr := ast.Expr{} mut timeout_expr := ast.empty_expr()
mut exception_branch := -1 mut exception_branch := -1
for j, branch in node.branches { for j, branch in node.branches {
if branch.is_else { if branch.is_else {
@ -4182,7 +4186,7 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
elem_types << '' elem_types << ''
} else { } else {
// must be evaluated to tmp var before real `select` is performed // must be evaluated to tmp var before real `select` is performed
objs << ast.Expr{} objs << ast.empty_expr()
tmp_obj := g.new_tmp_var() tmp_obj := g.new_tmp_var()
tmp_objs << tmp_obj tmp_objs << tmp_obj
el_stype := g.typ(g.table.mktyp(expr.right_type)) el_stype := g.typ(g.table.mktyp(expr.right_type))
@ -5283,6 +5287,14 @@ fn (mut g Gen) write_builtin_types() {
for builtin_name in c.builtins { for builtin_name in c.builtins {
sym := g.table.type_symbols[g.table.type_idxs[builtin_name]] sym := g.table.type_symbols[g.table.type_idxs[builtin_name]]
if sym.kind == .interface_ { if sym.kind == .interface_ {
if g.pref.is_verbose {
println('XAXAXA $sym.name')
if isnil(sym.info) {
println('FFF')
}
println(sym.info)
println(sym.kind)
}
g.write_interface_typesymbol_declaration(sym) g.write_interface_typesymbol_declaration(sym)
} else { } else {
builtin_types << sym builtin_types << sym

View File

@ -356,6 +356,7 @@ fn (mut g JsGen) stmts(stmts []ast.Stmt) {
fn (mut g JsGen) stmt(node ast.Stmt) { fn (mut g JsGen) stmt(node ast.Stmt) {
g.stmt_start_pos = g.ns.out.len g.stmt_start_pos = g.ns.out.len
match node { match node {
ast.EmptyStmt{}
ast.AsmStmt { ast.AsmStmt {
panic('inline asm is not supported by js') panic('inline asm is not supported by js')
} }
@ -447,6 +448,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
fn (mut g JsGen) expr(node ast.Expr) { fn (mut g JsGen) expr(node ast.Expr) {
match node { match node {
ast.NodeError {} ast.NodeError {}
ast.EmptyExpr {}
ast.CTempVar { ast.CTempVar {
g.write('/* ast.CTempVar: node.name */') g.write('/* ast.CTempVar: node.name */')
} }

View File

@ -49,6 +49,7 @@ pub fn (mut w Walker) mark_root_fns(all_fn_root_names []string) {
pub fn (mut w Walker) stmt(node ast.Stmt) { pub fn (mut w Walker) stmt(node ast.Stmt) {
match mut node { match mut node {
ast.EmptyStmt {}
ast.AsmStmt { ast.AsmStmt {
w.asm_io(node.output) w.asm_io(node.output)
w.asm_io(node.input) w.asm_io(node.input)
@ -153,6 +154,9 @@ fn (mut w Walker) exprs(exprs []ast.Expr) {
fn (mut w Walker) expr(node ast.Expr) { fn (mut w Walker) expr(node ast.Expr) {
match mut node { match mut node {
ast.EmptyExpr {
panic('Walker: EmptyExpr')
}
ast.AnonFn { ast.AnonFn {
w.fn_decl(mut node.decl) w.fn_decl(mut node.decl)
} }

View File

@ -149,7 +149,7 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
r0 := right[0] r0 := right[0]
mut v := ast.Var{ mut v := ast.Var{
name: lx.name name: lx.name
expr: if left.len == right.len { right[i] } else { ast.Expr{} } expr: if left.len == right.len { right[i] } else { ast.empty_expr() }
share: share share: share
is_mut: lx.is_mut || p.inside_for is_mut: lx.is_mut || p.inside_for
pos: lx.pos pos: lx.pos

View File

@ -21,7 +21,7 @@ fn (mut p Parser) array_init() ast.ArrayInit {
mut has_val := false mut has_val := false
mut has_type := false mut has_type := false
mut has_default := false mut has_default := false
mut default_expr := ast.Expr{} mut default_expr := ast.empty_expr()
if p.tok.kind == .rsbr { if p.tok.kind == .rsbr {
last_pos = p.tok.position() last_pos = p.tok.position()
// []typ => `[]` and `typ` must be on the same line // []typ => `[]` and `typ` must be on the same line
@ -103,8 +103,8 @@ fn (mut p Parser) array_init() ast.ArrayInit {
} }
mut has_len := false mut has_len := false
mut has_cap := false mut has_cap := false
mut len_expr := ast.Expr{} mut len_expr := ast.empty_expr()
mut cap_expr := ast.Expr{} mut cap_expr := ast.empty_expr()
if p.tok.kind == .lcbr && exprs.len == 0 && array_type != table.void_type { if p.tok.kind == .lcbr && exprs.len == 0 && array_type != table.void_type {
// `[]int{ len: 10, cap: 100}` syntax // `[]int{ len: 10, cap: 100}` syntax
p.next() p.next()

View File

@ -129,7 +129,7 @@ pub fn (mut p Parser) call_args() []ast.CallArg {
p.next() p.next()
array_decompose = true array_decompose = true
} }
mut expr := ast.Expr{} mut expr := ast.empty_expr()
if p.tok.kind == .name && p.peek_tok.kind == .colon { if p.tok.kind == .name && p.peek_tok.kind == .colon {
// `foo(key:val, key2:val2)` // `foo(key:val, key2:val2)`
expr = p.struct_init(true) // short_syntax:true expr = p.struct_init(true) // short_syntax:true

View File

@ -35,9 +35,9 @@ fn (mut p Parser) for_stmt() ast.Stmt {
if p.tok.kind == .key_mut { if p.tok.kind == .key_mut {
return p.error('`mut` is not needed in `for ;;` loops: use `for i := 0; i < n; i ++ {`') return p.error('`mut` is not needed in `for ;;` loops: use `for i := 0; i < n; i ++ {`')
} }
mut init := ast.Stmt{} mut init := ast.empty_stmt()
mut cond := p.new_true_expr() mut cond := p.new_true_expr()
mut inc := ast.Stmt{} mut inc := ast.empty_stmt()
mut has_init := false mut has_init := false
mut has_cond := false mut has_cond := false
mut has_inc := false mut has_inc := false
@ -136,7 +136,7 @@ fn (mut p Parser) for_stmt() ast.Stmt {
// 0 .. 10 // 0 .. 10
// start := p.tok.lit.int() // start := p.tok.lit.int()
// TODO use RangeExpr // TODO use RangeExpr
mut high_expr := ast.Expr{} mut high_expr := ast.empty_expr()
mut is_range := false mut is_range := false
if p.tok.kind == .dotdot { if p.tok.kind == .dotdot {
is_range = true is_range = true

View File

@ -79,7 +79,7 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
return ast.IfExpr{} return ast.IfExpr{}
} }
comments << p.eat_comments({}) comments << p.eat_comments({})
mut cond := ast.Expr{} mut cond := ast.empty_expr()
mut is_guard := false mut is_guard := false
// `if x := opt() {` // `if x := opt() {`
if !is_comptime && p.peek_tok.kind == .decl_assign { if !is_comptime && p.peek_tok.kind == .decl_assign {
@ -290,7 +290,7 @@ fn (mut p Parser) select_expr() ast.SelectExpr {
// final else // final else
mut is_else := false mut is_else := false
mut is_timeout := false mut is_timeout := false
mut stmt := ast.Stmt{} mut stmt := ast.empty_stmt()
if p.tok.kind == .key_else { if p.tok.kind == .key_else {
if has_timeout { if has_timeout {
p.error_with_pos('timeout `> t` and `else` are mutually exclusive `select` keys', p.error_with_pos('timeout `> t` and `else` are mutually exclusive `select` keys',

View File

@ -597,7 +597,7 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
} }
// TODO remove dummy return statement // TODO remove dummy return statement
// the compiler complains if it's not there // the compiler complains if it's not there
return ast.Stmt{} return ast.empty_stmt()
} }
// TODO [if vfmt] // TODO [if vfmt]
@ -1757,7 +1757,7 @@ fn (p &Parser) is_generic_call() bool {
pub fn (mut p Parser) name_expr() ast.Expr { pub fn (mut p Parser) name_expr() ast.Expr {
prev_tok_kind := p.prev_tok.kind prev_tok_kind := p.prev_tok.kind
mut node := ast.Expr{} mut node := ast.empty_expr()
if p.expecting_type { if p.expecting_type {
p.expecting_type = false p.expecting_type = false
// get type position before moving to next // get type position before moving to next
@ -1801,7 +1801,7 @@ pub fn (mut p Parser) name_expr() ast.Expr {
mut last_pos := first_pos mut last_pos := first_pos
chan_type := p.parse_chan_type() chan_type := p.parse_chan_type()
mut has_cap := false mut has_cap := false
mut cap_expr := ast.Expr{} mut cap_expr := ast.empty_expr()
p.check(.lcbr) p.check(.lcbr)
if p.tok.kind == .rcbr { if p.tok.kind == .rcbr {
last_pos = p.tok.position() last_pos = p.tok.position()
@ -1910,8 +1910,8 @@ pub fn (mut p Parser) name_expr() ast.Expr {
// without the next line int would result in int* // without the next line int would result in int*
p.is_amp = false p.is_amp = false
p.check(.lpar) p.check(.lpar)
mut expr := ast.Expr{} mut expr := ast.empty_expr()
mut arg := ast.Expr{} mut arg := ast.empty_expr()
mut has_arg := false mut has_arg := false
expr = p.expr(0) expr = p.expr(0)
// TODO, string(b, len) // TODO, string(b, len)
@ -2013,7 +2013,7 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
left: left left: left
pos: pos pos: pos
index: ast.RangeExpr{ index: ast.RangeExpr{
low: ast.Expr{} low: ast.empty_expr()
high: high high: high
has_high: true has_high: true
pos: pos pos: pos
@ -2025,7 +2025,7 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
if p.tok.kind == .dotdot { if p.tok.kind == .dotdot {
// [start..end] or [start..] // [start..end] or [start..]
p.next() p.next()
mut high := ast.Expr{} mut high := ast.empty_expr()
if p.tok.kind != .rsbr { if p.tok.kind != .rsbr {
has_high = true has_high = true
high = p.expr(0) high = p.expr(0)
@ -2263,7 +2263,7 @@ fn (mut p Parser) string_expr() ast.Expr {
if is_raw || is_cstr { if is_raw || is_cstr {
p.next() p.next()
} }
mut node := ast.Expr{} mut node := ast.empty_expr()
val := p.tok.lit val := p.tok.lit
pos := p.tok.position() pos := p.tok.position()
if p.peek_tok.kind != .str_dollar { if p.peek_tok.kind != .str_dollar {
@ -2372,7 +2372,7 @@ fn (mut p Parser) parse_number_literal() ast.Expr {
} }
lit := p.tok.lit lit := p.tok.lit
full_lit := if is_neg { '-' + lit } else { lit } full_lit := if is_neg { '-' + lit } else { lit }
mut node := ast.Expr{} mut node := ast.empty_expr()
if lit.index_any('.eE') >= 0 && lit[..2] !in ['0x', '0X', '0o', '0O', '0b', '0B'] { if lit.index_any('.eE') >= 0 && lit[..2] !in ['0x', '0X', '0o', '0O', '0b', '0B'] {
node = ast.FloatLiteral{ node = ast.FloatLiteral{
val: full_lit val: full_lit
@ -2714,7 +2714,7 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
p.error('global assign must have the type around the value, use `__global ( name = type(value) )`') p.error('global assign must have the type around the value, use `__global ( name = type(value) )`')
return ast.GlobalDecl{} return ast.GlobalDecl{}
} }
mut expr := ast.Expr{} mut expr := ast.empty_expr()
if has_expr { if has_expr {
if p.tok.kind != .lpar { if p.tok.kind != .lpar {
p.error('global assign must have a type and value, use `__global ( name = type(value) )` or `__global ( name type )`') p.error('global assign must have a type and value, use `__global ( name = type(value) )` or `__global ( name type )`')
@ -2769,7 +2769,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
pos := p.tok.position() pos := p.tok.position()
val := p.check_name() val := p.check_name()
vals << val vals << val
mut expr := ast.Expr{} mut expr := ast.empty_expr()
mut has_expr := false mut has_expr := false
// p.warn('enum val $val') // p.warn('enum val $val')
if p.tok.kind == .assign { if p.tok.kind == .assign {
@ -2854,7 +2854,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
if name.len == 1 && name[0].is_capital() { if name.len == 1 && name[0].is_capital() {
p.error_with_pos('single letter capital names are reserved for generic template types.', p.error_with_pos('single letter capital names are reserved for generic template types.',
decl_pos) decl_pos)
return ast.TypeDecl{} return ast.FnTypeDecl{}
} }
mut sum_variants := []ast.SumTypeVariant{} mut sum_variants := []ast.SumTypeVariant{}
p.check(.assign) p.check(.assign)

View File

@ -14,7 +14,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
eprintln('parsing file: ${p.file_name:-30} | tok.kind: ${p.tok.kind:-10} | tok.lit: ${p.tok.lit:-10} | tok_pos: ${tok_pos.str():-45} | expr($precedence)') eprintln('parsing file: ${p.file_name:-30} | tok.kind: ${p.tok.kind:-10} | tok.lit: ${p.tok.lit:-10} | tok_pos: ${tok_pos.str():-45} | expr($precedence)')
} }
// println('\n\nparser.expr()') // println('\n\nparser.expr()')
mut node := ast.Expr{} mut node := ast.empty_expr()
is_stmt_ident := p.is_stmt_ident is_stmt_ident := p.is_stmt_ident
p.is_stmt_ident = false p.is_stmt_ident = false
if !p.pref.is_fmt { if !p.pref.is_fmt {
@ -439,7 +439,7 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr {
precedence := p.tok.precedence() precedence := p.tok.precedence()
mut pos := p.tok.position() mut pos := p.tok.position()
p.next() p.next()
mut right := ast.Expr{} mut right := ast.empty_expr()
prev_expecting_type := p.expecting_type prev_expecting_type := p.expecting_type
if op in [.key_is, .not_is] { if op in [.key_is, .not_is] {
p.expecting_type = true p.expecting_type = true

View File

@ -22,7 +22,7 @@ fn (mut p Parser) sql_expr() ast.Expr {
} }
table_pos := p.tok.position() table_pos := p.tok.position()
table_type := p.parse_type() // `User` table_type := p.parse_type() // `User`
mut where_expr := ast.Expr{} mut where_expr := ast.empty_expr()
has_where := p.tok.kind == .name && p.tok.lit == 'where' has_where := p.tok.kind == .name && p.tok.lit == 'where'
mut query_one := false // one object is returned, not an array mut query_one := false // one object is returned, not an array
if has_where { if has_where {
@ -40,11 +40,11 @@ fn (mut p Parser) sql_expr() ast.Expr {
} }
} }
mut has_limit := false mut has_limit := false
mut limit_expr := ast.Expr{} mut limit_expr := ast.empty_expr()
mut has_offset := false mut has_offset := false
mut offset_expr := ast.Expr{} mut offset_expr := ast.empty_expr()
mut has_order := false mut has_order := false
mut order_expr := ast.Expr{} mut order_expr := ast.empty_expr()
mut has_desc := false mut has_desc := false
if p.tok.kind == .name && p.tok.lit == 'order' { if p.tok.kind == .name && p.tok.lit == 'order' {
p.check_name() // `order` p.check_name() // `order`
@ -172,7 +172,7 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
} }
mut table_pos := p.tok.position() mut table_pos := p.tok.position()
mut where_expr := ast.Expr{} mut where_expr := ast.empty_expr()
if kind == .insert { if kind == .insert {
table_pos = p.tok.position() table_pos = p.tok.position()
table_type = p.parse_type() table_type = p.parse_type()

View File

@ -239,7 +239,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
// attrs are stored in `p.attrs` // attrs are stored in `p.attrs`
p.attributes() p.attributes()
} }
mut default_expr := ast.Expr{} mut default_expr := ast.empty_expr()
mut has_default_expr := false mut has_default_expr := false
if !is_embed { if !is_embed {
if p.tok.kind == .assign { if p.tok.kind == .assign {
@ -352,12 +352,12 @@ fn (mut p Parser) struct_init(short_syntax bool) ast.StructInit {
// p.warn(is_short_syntax.str()) // p.warn(is_short_syntax.str())
saved_is_amp := p.is_amp saved_is_amp := p.is_amp
p.is_amp = false p.is_amp = false
mut update_expr := ast.Expr{} mut update_expr := ast.empty_expr()
mut update_expr_comments := []ast.Comment{} mut update_expr_comments := []ast.Comment{}
mut has_update_expr := false mut has_update_expr := false
for p.tok.kind !in [.rcbr, .rpar, .eof] { for p.tok.kind !in [.rcbr, .rpar, .eof] {
mut field_name := '' mut field_name := ''
mut expr := ast.Expr{} mut expr := ast.empty_expr()
mut field_pos := token.Position{} mut field_pos := token.Position{}
mut first_field_pos := token.Position{} mut first_field_pos := token.Position{}
mut comments := []ast.Comment{} mut comments := []ast.Comment{}