From 59baef89a065483de915dab5b1d5ea30189a3373 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 17 Apr 2020 18:16:55 +0200 Subject: [PATCH] parser: assign.v, containers.v, for.v, if.v --- vlib/v/parser/assign.v | 115 +++++++++ vlib/v/parser/containers.v | 111 ++++++++ vlib/v/parser/for.v | 128 ++++++++++ vlib/v/parser/if.v | 175 +++++++++++++ vlib/v/parser/parser.v | 500 ------------------------------------- 5 files changed, 529 insertions(+), 500 deletions(-) create mode 100644 vlib/v/parser/assign.v create mode 100644 vlib/v/parser/for.v create mode 100644 vlib/v/parser/if.v diff --git a/vlib/v/parser/assign.v b/vlib/v/parser/assign.v new file mode 100644 index 0000000000..f606cf1b33 --- /dev/null +++ b/vlib/v/parser/assign.v @@ -0,0 +1,115 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module parser + +import v.ast +import v.table +import v.token + +fn (var p Parser) assign_stmt() ast.Stmt { + is_static := p.tok.kind == .key_static + if is_static { + p.next() + } + idents := p.parse_assign_lhs() + op := p.tok.kind + p.next() // :=, = + pos := p.tok.position() + exprs := p.parse_assign_rhs() + is_decl := op == .decl_assign + for i, ident in idents { + known_var := p.scope.known_var(ident.name) + if !is_decl && !known_var { + p.error('unknown variable `$ident.name`') + } + if is_decl && ident.kind != .blank_ident { + if p.scope.known_var(ident.name) { + p.error('redefinition of `$ident.name`') + } + if idents.len == exprs.len { + p.scope.register(ident.name, ast.Var{ + name: ident.name + expr: exprs[i] + is_mut: ident.is_mut || p.inside_for + }) + } else { + p.scope.register(ident.name, ast.Var{ + name: ident.name + is_mut: ident.is_mut || p.inside_for + }) + } + } + } + return ast.AssignStmt{ + left: idents + right: exprs + op: op + pos: pos + is_static: is_static + } +} + +// TODO: is it possible to merge with AssignStmt? +pub fn (var p Parser) assign_expr(left ast.Expr) ast.AssignExpr { + op := p.tok.kind + p.next() + pos := p.tok.position() + val := p.expr(0) + match left { + ast.IndexExpr { + // it.mark_as_setter() + it.is_setter = true + } + else {} + } + node := ast.AssignExpr{ + left: left + val: val + op: op + pos: pos + } + return node +} + +fn (var p Parser) parse_assign_lhs() []ast.Ident { + var idents := []ast.Ident + for { + is_mut := p.tok.kind == .key_mut || p.tok.kind == .key_var + if is_mut { + p.next() + } + is_static := p.tok.kind == .key_static + if is_static { + p.check(.key_static) + } + var ident := p.parse_ident(false, false) + ident.is_mut = is_mut + ident.info = ast.IdentVar{ + is_mut: is_mut + is_static: is_static + } + idents << ident + if p.tok.kind == .comma { + p.check(.comma) + } else { + break + } + } + return idents +} + +// right hand side of `=` or `:=` in `a,b,c := 1,2,3` +fn (var p Parser) parse_assign_rhs() []ast.Expr { + var exprs := []ast.Expr + for { + expr := p.expr(0) + exprs << expr + if p.tok.kind == .comma { + p.check(.comma) + } else { + break + } + } + return exprs +} diff --git a/vlib/v/parser/containers.v b/vlib/v/parser/containers.v index 27640a846f..e29772bd59 100644 --- a/vlib/v/parser/containers.v +++ b/vlib/v/parser/containers.v @@ -2,3 +2,114 @@ // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. module parser + +import v.ast +import v.table +import v.token + +fn (var p Parser) array_init() ast.ArrayInit { + first_pos := p.tok.position() + var last_pos := token.Position{} + p.check(.lsbr) + // p.warn('array_init() exp=$p.expected_type') + var array_type := table.void_type + var elem_type := table.void_type + var exprs := []ast.Expr + var is_fixed := false + if p.tok.kind == .rsbr { + // []typ => `[]` and `typ` must be on the same line + line_nr := p.tok.line_nr + p.check(.rsbr) + // []string + if p.tok.kind in [.name, .amp] && p.tok.line_nr == line_nr { + elem_type = p.parse_type() + // this is set here becasue its a known type, others could be the + // result of expr so we do those in checker + idx := p.table.find_or_register_array(elem_type, 1) + array_type = table.new_type(idx) + } + } else { + // [1,2,3] or [const]byte + for i := 0; p.tok.kind != .rsbr; i++ { + expr := p.expr(0) + exprs << expr + if p.tok.kind == .comma { + p.check(.comma) + } + // p.check_comment() + } + line_nr := p.tok.line_nr + $if tinyc { + // NB: do not remove the next line without testing + // v selfcompilation with tcc first + tcc_stack_bug := 12345 + } + last_pos = p.tok.position() + p.check(.rsbr) + // [100]byte + if exprs.len == 1 && p.tok.kind in [.name, .amp] && p.tok.line_nr == line_nr { + elem_type = p.parse_type() + is_fixed = true + } + } + // ! + if p.tok.kind == .not { + last_pos = p.tok.position() + p.next() + } + if p.tok.kind == .not { + last_pos = p.tok.position() + p.next() + } + if p.tok.kind == .lcbr && exprs.len == 0 { + // `[]int{ len: 10, cap: 100}` syntax + p.next() + for p.tok.kind != .rcbr { + key := p.check_name() + p.check(.colon) + if !(key in ['len', 'cap', 'init']) { + p.error('wrong field `$key`, expecting `len`, `cap`, or `init`') + } + p.expr(0) + if p.tok.kind != .rcbr { + p.check(.comma) + } + } + p.check(.rcbr) + } + pos := token.Position{ + line_nr: first_pos.line_nr + pos: first_pos.pos + len: last_pos.pos - first_pos.pos + last_pos.len + } + return ast.ArrayInit{ + is_fixed: is_fixed + mod: p.mod + elem_type: elem_type + typ: array_type + exprs: exprs + pos: pos + } +} + +fn (var p Parser) map_init() ast.MapInit { + pos := p.tok.position() + var keys := []ast.Expr + var vals := []ast.Expr + for p.tok.kind != .rcbr && p.tok.kind != .eof { + // p.check(.str) + key := p.expr(0) + keys << key + p.check(.colon) + val := p.expr(0) + vals << val + if p.tok.kind == .comma { + p.next() + } + } + return ast.MapInit{ + keys: keys + vals: vals + pos: pos + } +} diff --git a/vlib/v/parser/for.v b/vlib/v/parser/for.v new file mode 100644 index 0000000000..9fc87ba1f6 --- /dev/null +++ b/vlib/v/parser/for.v @@ -0,0 +1,128 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module parser + +import v.ast +import v.table +import v.token + +fn (var p Parser) for_stmt() ast.Stmt { + p.check(.key_for) + pos := p.tok.position() + p.open_scope() + p.inside_for = true + // defer { p.close_scope() } + // Infinite loop + if p.tok.kind == .lcbr { + p.inside_for = false + stmts := p.parse_block() + p.close_scope() + return ast.ForStmt{ + stmts: stmts + pos: pos + is_inf: true + } + } else if p.tok.kind in [.key_mut, .key_var] { + p.error('`mut` is not needed in for loops') + } else if p.peek_tok.kind in [.decl_assign, .assign, .semicolon] || p.tok.kind == .semicolon { + // `for i := 0; i < 10; i++ {` + var init := ast.Stmt{} + var cond := p.new_true_expr() + // mut inc := ast.Stmt{} + var inc := ast.Expr{} + var has_init := false + var has_cond := false + var has_inc := false + if p.peek_tok.kind in [.assign, .decl_assign] { + init = p.assign_stmt() + has_init = true + } else if p.tok.kind != .semicolon { + } + // allow `for ;; i++ {` + // Allow `for i = 0; i < ...` + p.check(.semicolon) + if p.tok.kind != .semicolon { + var typ := table.void_type + cond = p.expr(0) + has_cond = true + } + p.check(.semicolon) + if p.tok.kind != .lcbr { + // inc = p.stmt() + inc = p.expr(0) + has_inc = true + } + p.inside_for = false + stmts := p.parse_block() + p.close_scope() + return ast.ForCStmt{ + stmts: stmts + has_init: has_init + has_cond: has_cond + has_inc: has_inc + init: init + cond: cond + inc: inc + pos: pos + } + } else if p.peek_tok.kind in [.key_in, .comma] { + // `for i in vals`, `for i in start .. end` + var key_var_name := '' + var val_var_name := p.check_name() + if p.tok.kind == .comma { + p.check(.comma) + key_var_name = val_var_name + val_var_name = p.check_name() + p.scope.register(key_var_name, ast.Var{ + name: key_var_name + typ: table.int_type + }) + } + p.check(.key_in) + // arr_expr + cond := p.expr(0) + // 0 .. 10 + // start := p.tok.lit.int() + // TODO use RangeExpr + var high_expr := ast.Expr{} + var is_range := false + if p.tok.kind == .dotdot { + is_range = true + p.check(.dotdot) + high_expr = p.expr(0) + p.scope.register(val_var_name, ast.Var{ + name: val_var_name + typ: table.int_type + }) + } else { + // this type will be set in checker + p.scope.register(val_var_name, ast.Var{ + name: val_var_name + }) + } + p.inside_for = false + stmts := p.parse_block() + // println('nr stmts=$stmts.len') + p.close_scope() + return ast.ForInStmt{ + stmts: stmts + cond: cond + key_var: key_var_name + val_var: val_var_name + high: high_expr + is_range: is_range + pos: pos + } + } + // `for cond {` + cond := p.expr(0) + p.inside_for = false + stmts := p.parse_block() + p.close_scope() + return ast.ForStmt{ + cond: cond + stmts: stmts + pos: pos + } +} diff --git a/vlib/v/parser/if.v b/vlib/v/parser/if.v new file mode 100644 index 0000000000..9b01b53b8d --- /dev/null +++ b/vlib/v/parser/if.v @@ -0,0 +1,175 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module parser + +import v.ast +import v.table +import v.token + +fn (var p Parser) if_expr() ast.IfExpr { + pos := p.tok.position() + var branches := []ast.IfBranch + var has_else := false + for p.tok.kind in [.key_if, .key_else] { + p.inside_if = true + branch_pos := p.tok.position() + var comment := ast.Comment{} + if p.tok.kind == .key_if { + p.check(.key_if) + } else { + // if p.tok.kind == .comment { + // p.error('place comments inside {}') + // } + // comment = p.check_comment() + p.check(.key_else) + if p.tok.kind == .key_if { + p.check(.key_if) + } else { + has_else = true + p.inside_if = false + branches << ast.IfBranch{ + stmts: p.parse_block() + pos: branch_pos + comment: comment + } + break + } + } + var cond := ast.Expr{} + var is_or := false + // `if x := opt() {` + if p.peek_tok.kind == .decl_assign { + is_or = true + p.open_scope() + var_name := p.check_name() + p.check(.decl_assign) + expr := p.expr(0) + p.scope.register(var_name, ast.Var{ + name: var_name + expr: expr + }) + cond = ast.IfGuardExpr{ + var_name: var_name + expr: expr + } + } else { + cond = p.expr(0) + } + p.inside_if = false + stmts := p.parse_block() + if is_or { + p.close_scope() + } + branches << ast.IfBranch{ + cond: cond + stmts: stmts + pos: branch_pos + comment: ast.Comment{} + } + if p.tok.kind != .key_else { + break + } + } + return ast.IfExpr{ + branches: branches + pos: pos + has_else: has_else + } +} + +fn (var p Parser) match_expr() ast.MatchExpr { + match_first_pos := p.tok.position() + p.inside_match = true + p.check(.key_match) + is_mut := p.tok.kind in [.key_mut, .key_var] + var is_sum_type := false + if is_mut { + p.next() + } + cond := p.expr(0) + p.inside_match = false + p.check(.lcbr) + var branches := []ast.MatchBranch + for { + branch_first_pos := p.tok.position() + comment := p.check_comment() // comment before {} + var exprs := []ast.Expr + p.open_scope() + // final else + var is_else := false + if p.tok.kind == .key_else { + is_else = true + p.next() + } else if p.tok.kind == .name && (p.tok.lit in table.builtin_type_names || (p.tok.lit[0].is_capital() && + !p.tok.lit.is_upper()) || p.peek_tok.kind == .dot) { + // Sum type match + // if sym.kind == .sum_type { + // p.warn('is sum') + // TODO `exprs << ast.Type{...} + typ := p.parse_type() + x := ast.Type{ + typ: typ + } + var expr := ast.Expr{} + expr = x + exprs << expr + p.scope.register('it', ast.Var{ + name: 'it' + typ: table.type_to_ptr(typ) + }) + // TODO + if p.tok.kind == .comma { + p.next() + p.parse_type() + } + is_sum_type = true + } else { + // Expression match + for { + p.inside_match_case = true + expr := p.expr(0) + p.inside_match_case = false + exprs << expr + if p.tok.kind != .comma { + break + } + p.check(.comma) + } + } + branch_last_pos := p.tok.position() + // p.warn('match block') + stmts := p.parse_block() + pos := token.Position{ + line_nr: branch_first_pos.line_nr + pos: branch_first_pos.pos + len: branch_last_pos.pos - branch_first_pos.pos + branch_last_pos.len + } + branches << ast.MatchBranch{ + exprs: exprs + stmts: stmts + pos: pos + comment: comment + is_else: is_else + } + p.close_scope() + if p.tok.kind == .rcbr { + break + } + } + match_last_pos := p.tok.position() + pos := token.Position{ + line_nr: match_first_pos.line_nr + pos: match_first_pos.pos + len: match_last_pos.pos - match_first_pos.pos + match_last_pos.len + } + p.check(.rcbr) + return ast.MatchExpr{ + branches: branches + cond: cond + is_sum_type: is_sum_type + pos: pos + is_mut: is_mut + } +} + diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 75f6f44761..bc76a035b9 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -455,28 +455,6 @@ pub fn (var p Parser) stmt() ast.Stmt { } } -// TODO: is it possible to merge with AssignStmt? -pub fn (var p Parser) assign_expr(left ast.Expr) ast.AssignExpr { - op := p.tok.kind - p.next() - pos := p.tok.position() - val := p.expr(0) - match left { - ast.IndexExpr { - // it.mark_as_setter() - it.is_setter = true - } - else {} - } - node := ast.AssignExpr{ - left: left - val: val - op: op - pos: pos - } - return node -} - fn (var p Parser) attribute() ast.Attr { p.check(.lsbr) if p.tok.kind == .key_if { @@ -826,197 +804,6 @@ fn (var p Parser) enum_val() ast.EnumVal { } } -fn (var p Parser) for_stmt() ast.Stmt { - p.check(.key_for) - pos := p.tok.position() - p.open_scope() - p.inside_for = true - // defer { p.close_scope() } - // Infinite loop - if p.tok.kind == .lcbr { - p.inside_for = false - stmts := p.parse_block() - p.close_scope() - return ast.ForStmt{ - stmts: stmts - pos: pos - is_inf: true - } - } else if p.tok.kind in [.key_mut, .key_var] { - p.error('`mut` is not needed in for loops') - } else if p.peek_tok.kind in [.decl_assign, .assign, .semicolon] || p.tok.kind == .semicolon { - // `for i := 0; i < 10; i++ {` - var init := ast.Stmt{} - var cond := p.new_true_expr() - // mut inc := ast.Stmt{} - var inc := ast.Expr{} - var has_init := false - var has_cond := false - var has_inc := false - if p.peek_tok.kind in [.assign, .decl_assign] { - init = p.assign_stmt() - has_init = true - } else if p.tok.kind != .semicolon { - } - // allow `for ;; i++ {` - // Allow `for i = 0; i < ...` - p.check(.semicolon) - if p.tok.kind != .semicolon { - var typ := table.void_type - cond = p.expr(0) - has_cond = true - } - p.check(.semicolon) - if p.tok.kind != .lcbr { - // inc = p.stmt() - inc = p.expr(0) - has_inc = true - } - p.inside_for = false - stmts := p.parse_block() - p.close_scope() - return ast.ForCStmt{ - stmts: stmts - has_init: has_init - has_cond: has_cond - has_inc: has_inc - init: init - cond: cond - inc: inc - pos: pos - } - } else if p.peek_tok.kind in [.key_in, .comma] { - // `for i in vals`, `for i in start .. end` - var key_var_name := '' - var val_var_name := p.check_name() - if p.tok.kind == .comma { - p.check(.comma) - key_var_name = val_var_name - val_var_name = p.check_name() - p.scope.register(key_var_name, ast.Var{ - name: key_var_name - typ: table.int_type - }) - } - p.check(.key_in) - // arr_expr - cond := p.expr(0) - // 0 .. 10 - // start := p.tok.lit.int() - // TODO use RangeExpr - var high_expr := ast.Expr{} - var is_range := false - if p.tok.kind == .dotdot { - is_range = true - p.check(.dotdot) - high_expr = p.expr(0) - p.scope.register(val_var_name, ast.Var{ - name: val_var_name - typ: table.int_type - }) - } else { - // this type will be set in checker - p.scope.register(val_var_name, ast.Var{ - name: val_var_name - }) - } - p.inside_for = false - stmts := p.parse_block() - // println('nr stmts=$stmts.len') - p.close_scope() - return ast.ForInStmt{ - stmts: stmts - cond: cond - key_var: key_var_name - val_var: val_var_name - high: high_expr - is_range: is_range - pos: pos - } - } - // `for cond {` - cond := p.expr(0) - p.inside_for = false - stmts := p.parse_block() - p.close_scope() - return ast.ForStmt{ - cond: cond - stmts: stmts - pos: pos - } -} - -fn (var p Parser) if_expr() ast.IfExpr { - pos := p.tok.position() - var branches := []ast.IfBranch - var has_else := false - for p.tok.kind in [.key_if, .key_else] { - p.inside_if = true - branch_pos := p.tok.position() - var comment := ast.Comment{} - if p.tok.kind == .key_if { - p.check(.key_if) - } else { - // if p.tok.kind == .comment { - // p.error('place comments inside {}') - // } - // comment = p.check_comment() - p.check(.key_else) - if p.tok.kind == .key_if { - p.check(.key_if) - } else { - has_else = true - p.inside_if = false - branches << ast.IfBranch{ - stmts: p.parse_block() - pos: branch_pos - comment: comment - } - break - } - } - var cond := ast.Expr{} - var is_or := false - // `if x := opt() {` - if p.peek_tok.kind == .decl_assign { - is_or = true - p.open_scope() - var_name := p.check_name() - p.check(.decl_assign) - expr := p.expr(0) - p.scope.register(var_name, ast.Var{ - name: var_name - expr: expr - }) - cond = ast.IfGuardExpr{ - var_name: var_name - expr: expr - } - } else { - cond = p.expr(0) - } - p.inside_if = false - stmts := p.parse_block() - if is_or { - p.close_scope() - } - branches << ast.IfBranch{ - cond: cond - stmts: stmts - pos: branch_pos - comment: ast.Comment{} - } - if p.tok.kind != .key_else { - break - } - } - return ast.IfExpr{ - branches: branches - pos: pos - has_else: has_else - } -} - fn (var p Parser) string_expr() ast.Expr { is_raw := p.tok.kind == .name && p.tok.lit == 'r' is_cstr := p.tok.kind == .name && p.tok.lit == 'c' @@ -1078,113 +865,6 @@ fn (var p Parser) string_expr() ast.Expr { return node } -fn (var p Parser) array_init() ast.ArrayInit { - first_pos := p.tok.position() - var last_pos := token.Position{} - p.check(.lsbr) - // p.warn('array_init() exp=$p.expected_type') - var array_type := table.void_type - var elem_type := table.void_type - var exprs := []ast.Expr - var is_fixed := false - if p.tok.kind == .rsbr { - // []typ => `[]` and `typ` must be on the same line - line_nr := p.tok.line_nr - p.check(.rsbr) - // []string - if p.tok.kind in [.name, .amp] && p.tok.line_nr == line_nr { - elem_type = p.parse_type() - // this is set here becasue its a known type, others could be the - // result of expr so we do those in checker - idx := p.table.find_or_register_array(elem_type, 1) - array_type = table.new_type(idx) - } - } else { - // [1,2,3] or [const]byte - for i := 0; p.tok.kind != .rsbr; i++ { - expr := p.expr(0) - exprs << expr - if p.tok.kind == .comma { - p.check(.comma) - } - // p.check_comment() - } - line_nr := p.tok.line_nr - $if tinyc { - // NB: do not remove the next line without testing - // v selfcompilation with tcc first - tcc_stack_bug := 12345 - } - last_pos = p.tok.position() - p.check(.rsbr) - // [100]byte - if exprs.len == 1 && p.tok.kind in [.name, .amp] && p.tok.line_nr == line_nr { - elem_type = p.parse_type() - is_fixed = true - } - } - // ! - if p.tok.kind == .not { - last_pos = p.tok.position() - p.next() - } - if p.tok.kind == .not { - last_pos = p.tok.position() - p.next() - } - if p.tok.kind == .lcbr && exprs.len == 0 { - // `[]int{ len: 10, cap: 100}` syntax - p.next() - for p.tok.kind != .rcbr { - key := p.check_name() - p.check(.colon) - if !(key in ['len', 'cap', 'init']) { - p.error('wrong field `$key`, expecting `len`, `cap`, or `init`') - } - p.expr(0) - if p.tok.kind != .rcbr { - p.check(.comma) - } - } - p.check(.rcbr) - } - pos := token.Position{ - line_nr: first_pos.line_nr - pos: first_pos.pos - len: last_pos.pos - first_pos.pos + last_pos.len - } - return ast.ArrayInit{ - is_fixed: is_fixed - mod: p.mod - elem_type: elem_type - typ: array_type - exprs: exprs - pos: pos - } -} - -fn (var p Parser) map_init() ast.MapInit { - pos := p.tok.position() - var keys := []ast.Expr - var vals := []ast.Expr - for p.tok.kind != .rcbr && p.tok.kind != .eof { - // p.check(.str) - key := p.expr(0) - keys << key - p.check(.colon) - val := p.expr(0) - vals << val - if p.tok.kind == .comma { - p.next() - } - } - return ast.MapInit{ - keys: keys - vals: vals - pos: pos - } -} - fn (var p Parser) parse_number_literal() ast.Expr { lit := p.tok.lit pos := p.tok.position() @@ -1329,91 +1009,6 @@ fn (var p Parser) return_stmt() ast.Return { } // left hand side of `=` or `:=` in `a,b,c := 1,2,3` -fn (var p Parser) parse_assign_lhs() []ast.Ident { - var idents := []ast.Ident - for { - is_mut := p.tok.kind == .key_mut || p.tok.kind == .key_var - if is_mut { - p.next() - } - is_static := p.tok.kind == .key_static - if is_static { - p.check(.key_static) - } - var ident := p.parse_ident(false, false) - ident.is_mut = is_mut - ident.info = ast.IdentVar{ - is_mut: is_mut - is_static: is_static - } - idents << ident - if p.tok.kind == .comma { - p.check(.comma) - } else { - break - } - } - return idents -} - -// right hand side of `=` or `:=` in `a,b,c := 1,2,3` -fn (var p Parser) parse_assign_rhs() []ast.Expr { - var exprs := []ast.Expr - for { - expr := p.expr(0) - exprs << expr - if p.tok.kind == .comma { - p.check(.comma) - } else { - break - } - } - return exprs -} - -fn (var p Parser) assign_stmt() ast.Stmt { - is_static := p.tok.kind == .key_static - if is_static { - p.next() - } - idents := p.parse_assign_lhs() - op := p.tok.kind - p.next() // :=, = - pos := p.tok.position() - exprs := p.parse_assign_rhs() - is_decl := op == .decl_assign - for i, ident in idents { - known_var := p.scope.known_var(ident.name) - if !is_decl && !known_var { - p.error('unknown variable `$ident.name`') - } - if is_decl && ident.kind != .blank_ident { - if p.scope.known_var(ident.name) { - p.error('redefinition of `$ident.name`') - } - if idents.len == exprs.len { - p.scope.register(ident.name, ast.Var{ - name: ident.name - expr: exprs[i] - is_mut: ident.is_mut || p.inside_for - }) - } else { - p.scope.register(ident.name, ast.Var{ - name: ident.name - is_mut: ident.is_mut || p.inside_for - }) - } - } - } - return ast.AssignStmt{ - left: idents - right: exprs - op: op - pos: pos - is_static: is_static - } -} - fn (var p Parser) global_decl() ast.GlobalDecl { if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod != 'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals { @@ -1454,101 +1049,6 @@ fn (var p Parser) global_decl() ast.GlobalDecl { return glob } -fn (var p Parser) match_expr() ast.MatchExpr { - match_first_pos := p.tok.position() - p.inside_match = true - p.check(.key_match) - is_mut := p.tok.kind in [.key_mut, .key_var] - var is_sum_type := false - if is_mut { - p.next() - } - cond := p.expr(0) - p.inside_match = false - p.check(.lcbr) - var branches := []ast.MatchBranch - for { - branch_first_pos := p.tok.position() - comment := p.check_comment() // comment before {} - var exprs := []ast.Expr - p.open_scope() - // final else - var is_else := false - if p.tok.kind == .key_else { - is_else = true - p.next() - } else if p.tok.kind == .name && (p.tok.lit in table.builtin_type_names || (p.tok.lit[0].is_capital() && - !p.tok.lit.is_upper()) || p.peek_tok.kind == .dot) { - // Sum type match - // if sym.kind == .sum_type { - // p.warn('is sum') - // TODO `exprs << ast.Type{...} - typ := p.parse_type() - x := ast.Type{ - typ: typ - } - var expr := ast.Expr{} - expr = x - exprs << expr - p.scope.register('it', ast.Var{ - name: 'it' - typ: table.type_to_ptr(typ) - }) - // TODO - if p.tok.kind == .comma { - p.next() - p.parse_type() - } - is_sum_type = true - } else { - // Expression match - for { - p.inside_match_case = true - expr := p.expr(0) - p.inside_match_case = false - exprs << expr - if p.tok.kind != .comma { - break - } - p.check(.comma) - } - } - branch_last_pos := p.tok.position() - // p.warn('match block') - stmts := p.parse_block() - pos := token.Position{ - line_nr: branch_first_pos.line_nr - pos: branch_first_pos.pos - len: branch_last_pos.pos - branch_first_pos.pos + branch_last_pos.len - } - branches << ast.MatchBranch{ - exprs: exprs - stmts: stmts - pos: pos - comment: comment - is_else: is_else - } - p.close_scope() - if p.tok.kind == .rcbr { - break - } - } - match_last_pos := p.tok.position() - pos := token.Position{ - line_nr: match_first_pos.line_nr - pos: match_first_pos.pos - len: match_last_pos.pos - match_first_pos.pos + match_last_pos.len - } - p.check(.rcbr) - return ast.MatchExpr{ - branches: branches - cond: cond - is_sum_type: is_sum_type - pos: pos - is_mut: is_mut - } -} - fn (var p Parser) enum_decl() ast.EnumDecl { is_pub := p.tok.kind == .key_pub if is_pub {