all: optimize scope usage in checker & parser. store scope in ast nodes (#7281)

pull/7282/head
joe-conigliaro 2020-12-12 19:01:12 +11:00 committed by GitHub
parent eb48208599
commit 0aa9f5a007
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 167 additions and 119 deletions

View File

@ -112,6 +112,7 @@ pub mut:
expr_type table.Type // type of `Foo` in `Foo.bar`
typ table.Type // type of the entire thing (`Foo.bar`)
name_type table.Type // T in `T.name` or typeof in `typeof(expr).name`
scope &Scope
}
// root_ident returns the origin ident where the selector started.
@ -287,6 +288,7 @@ pub mut:
return_type table.Type
comments []Comment // comments *after* the header, but *before* `{`; used for InterfaceDecl
source_file &File = 0
scope &Scope
}
// break, continue
@ -317,6 +319,7 @@ pub mut:
generic_type table.Type // TODO array, to support multiple types
generic_list_pos token.Position
free_receiver bool // true if the receiver expression needs to be freed
scope &Scope
}
/*
@ -460,6 +463,7 @@ pub:
pos token.Position
mut_pos token.Position
pub mut:
scope &Scope
obj ScopeObject
mod string
name string
@ -548,6 +552,7 @@ pub:
pub mut:
stmts []Stmt
smartcast bool // true when cond is `x is SumType`, set in checker.if_expr // no longer needed with union sum types TODO: remove
scope &Scope
}
pub struct UnsafeExpr {
@ -590,6 +595,8 @@ pub:
comments []Comment // comment above `xxx {`
is_else bool
post_comments []Comment
pub mut:
scope &Scope
}
pub struct SelectExpr {
@ -637,6 +644,7 @@ pub:
pos token.Position
pub mut:
label string // `label: for {`
scope &Scope
}
pub struct ForInStmt {
@ -656,6 +664,7 @@ pub mut:
cond_type table.Type
kind table.Kind // array/map/string
label string // `label: for {`
scope &Scope
}
pub struct ForCStmt {
@ -670,6 +679,7 @@ pub:
pos token.Position
pub mut:
label string // `label: for {`
scope &Scope
}
// #include etc
@ -942,6 +952,7 @@ pub:
pos token.Position
pub mut:
typ table.Type
scope &Scope
}
pub struct SizeOf {

View File

@ -147,6 +147,9 @@ pub fn (mut c Checker) check_files(ast_files []ast.File) {
mod: 'main'
file: first_main_file.path
return_type: table.void_type
scope: &ast.Scope{
parent: 0
}
}
has_main_fn = true
}
@ -1141,15 +1144,13 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
is_sort := method_name == 'sort'
if is_filter_map || is_sort {
array_info := left_type_sym.info as table.Array
args_pos := call_expr.pos.pos + call_expr.name.len
mut scope := c.file.scope.innermost(args_pos)
if is_filter_map {
// position of `it` doesn't matter
scope_register_it(mut scope, call_expr.pos, array_info.elem_type)
scope_register_it(mut call_expr.scope, call_expr.pos, array_info.elem_type)
} else if is_sort {
c.fail_if_immutable(call_expr.left)
// position of `a` and `b` doesn't matter, they're the same
scope_register_ab(mut scope, call_expr.pos, array_info.elem_type)
scope_register_ab(mut call_expr.scope, call_expr.pos, array_info.elem_type)
// Verify `.sort(a < b)`
if call_expr.args.len > 0 {
if call_expr.args[0].expr !is ast.InfixExpr {
@ -1450,8 +1451,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
}
// check for arg (var) of fn type
if !found {
scope := c.file.scope.innermost(call_expr.pos.pos)
if v := scope.find_var(fn_name) {
if v := call_expr.scope.find_var(fn_name) {
if v.typ != 0 {
vts := c.table.get_type_symbol(v.typ)
if vts.kind == .function {
@ -1468,8 +1468,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
return table.void_type
}
if !found_in_args {
scope := c.file.scope.innermost(call_expr.pos.pos)
if _ := scope.find_var(fn_name) {
if _ := call_expr.scope.find_var(fn_name) {
c.error('ambiguous call to: `$fn_name`, may refer to fn `$fn_name` or variable `$fn_name`',
call_expr.pos)
}
@ -1825,8 +1824,7 @@ pub fn (mut c Checker) selector_expr(mut selector_expr ast.SelectorExpr) table.T
field_sym := c.table.get_type_symbol(field.typ)
if field_sym.kind == .sum_type {
if !prevent_sum_type_unwrapping_once {
scope := c.file.scope.innermost(selector_expr.pos.pos)
if scope_field := scope.find_struct_field(utyp, field_name) {
if scope_field := selector_expr.scope.find_struct_field(utyp, field_name) {
return scope_field.sum_type_casts.last()
}
}
@ -2052,38 +2050,6 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
}
return
}
// Check `x := &y` and `mut x := <-ch`
if right_first is ast.PrefixExpr {
node := right_first
left_first := assign_stmt.left[0]
if left_first is ast.Ident {
assigned_var := left_first
if node.right is ast.Ident {
scope := c.file.scope.innermost(node.pos.pos)
if v := scope.find_var(node.right.name) {
right_type0 = v.typ
if node.op == .amp {
if !v.is_mut && assigned_var.is_mut && !c.inside_unsafe {
c.error('`$node.right.name` is immutable, cannot have a mutable reference to it',
node.pos)
}
}
}
}
if node.op == .arrow {
if assigned_var.is_mut {
right_sym := c.table.get_type_symbol(right_type0)
if right_sym.kind == .chan {
chan_info := right_sym.chan_info()
if chan_info.elem_type.is_ptr() && !chan_info.is_mut {
c.error('cannot have a mutable reference to object from `$right_sym.name`',
node.pos)
}
}
}
}
}
}
//
is_decl := assign_stmt.op == .decl_assign
for i, left in assign_stmt.left {
@ -2284,6 +2250,40 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
}
}
}
// this needs to run after the assign stmt left exprs have been run through checker so that ident.obj is set
// Check `x := &y` and `mut x := <-ch`
if right_first is ast.PrefixExpr {
node := right_first
left_first := assign_stmt.left[0]
if left_first is ast.Ident {
assigned_var := left_first
c.expr(node.right)
if node.right is ast.Ident {
if node.right.obj is ast.Var {
v := node.right.obj
right_type0 = v.typ
if node.op == .amp {
if !v.is_mut && assigned_var.is_mut && !c.inside_unsafe {
c.error('`$node.right.name` is immutable, cannot have a mutable reference to it',
node.pos)
}
}
}
}
if node.op == .arrow {
if assigned_var.is_mut {
right_sym := c.table.get_type_symbol(right_type0)
if right_sym.kind == .chan {
chan_info := right_sym.chan_info()
if chan_info.elem_type.is_ptr() && !chan_info.is_mut {
c.error('cannot have a mutable reference to object from `$right_sym.name`',
node.pos)
}
}
}
}
}
}
}
fn scope_register_it(mut s ast.Scope, pos token.Position, typ table.Type) {
@ -2422,25 +2422,18 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
// [50]byte
mut fixed_size := 1
init_expr := array_init.exprs[0]
c.expr(init_expr)
match init_expr {
ast.IntegerLiteral {
fixed_size = init_expr.val.int()
}
ast.Ident {
// if obj := c.file.global_scope.find_const(init_expr.name) {
// if obj := scope.find(init_expr.name) {
// scope := c.file.scope.innermost(array_init.pos.pos)
// eprintln('scope: ${scope.str()}')
// scope.find(init_expr.name) or {
// c.error('undefined ident: `$init_expr.name`', array_init.pos)
// }
mut full_const_name := init_expr.mod + '.' + init_expr.name
if obj := c.file.global_scope.find_const(full_const_name) {
if cint := const_int_value(obj) {
if init_expr.obj is ast.ConstField {
if cint := const_int_value(init_expr.obj) {
fixed_size = cint
}
} else {
c.error('non existent integer const $full_const_name while initializing the size of a static array',
c.error('non existent integer const $init_expr.name while initializing the size of a static array',
array_init.pos)
}
}
@ -2584,7 +2577,6 @@ fn (mut c Checker) stmt(node ast.Stmt) {
c.error('range type can not be string', node.cond.position())
}
} else {
mut scope := c.file.scope.innermost(node.pos.pos)
sym := c.table.get_type_symbol(typ)
if sym.kind == .map && !(node.key_var.len > 0 && node.val_var.len > 0) {
c.error('declare a key and a value variable when ranging a map: `for key, val in map {`\n' +
@ -2596,7 +2588,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
else { table.int_type }
}
node.key_type = key_type
scope.update_var_type(node.key_var, key_type)
node.scope.update_var_type(node.key_var, key_type)
}
mut value_type := c.table.value_type(typ)
if value_type == table.void_type || typ.has_flag(.optional) {
@ -2611,7 +2603,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
node.cond_type = typ
node.kind = sym.kind
node.val_type = value_type
scope.update_var_type(node.val_var, value_type)
node.scope.update_var_type(node.val_var, value_type)
}
c.check_loop_label(node.label, node.pos)
c.stmts(node.stmts)
@ -2873,8 +2865,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
return node.typ.to_ptr()
}
ast.Assoc {
scope := c.file.scope.innermost(node.pos.pos)
v := scope.find_var(node.var_name) or { panic(err) }
v := node.scope.find_var(node.var_name) or { panic(err) }
for i, _ in node.fields {
c.expr(node.exprs[i])
}
@ -3270,8 +3261,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
if ident.tok_kind == .assign && ident.is_mut {
c.error('`mut` not allowed with `=` (use `:=` to declare a variable)', ident.pos)
}
start_scope := c.file.scope.innermost(ident.pos.pos)
if obj := start_scope.find(ident.name) {
if obj := ident.scope.find(ident.name) {
match mut obj {
ast.GlobalField {
ident.kind = .global
@ -3509,7 +3499,8 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
// an expr was used in the match
mut branch_exprs := map[string]int{}
cond_type_sym := c.table.get_type_symbol(node.cond_type)
for branch in node.branches {
for branch_i, _ in node.branches {
mut branch := node.branches[branch_i]
mut expr_types := []ast.Type{}
for expr in branch.exprs {
mut key := ''
@ -3623,7 +3614,6 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
} else {
expr_type = expr_types[0].typ
}
mut scope := c.file.scope.innermost(branch.pos.pos)
match mut node.cond {
ast.SelectorExpr {
mut is_mut := false
@ -3632,18 +3622,19 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
if field := c.table.struct_find_field(expr_sym, node.cond.field_name) {
if field.is_mut {
root_ident := node.cond.root_ident()
if v := scope.find_var(root_ident.name) {
if v := branch.scope.find_var(root_ident.name) {
is_mut = v.is_mut
}
}
}
if field := scope.find_struct_field(node.cond.expr_type, node.cond.field_name) {
if field := branch.scope.find_struct_field(node.cond.expr_type,
node.cond.field_name) {
sum_type_casts << field.sum_type_casts
}
// smartcast either if the value is immutable or if the mut argument is explicitly given
if !is_mut || node.cond.is_mut {
sum_type_casts << expr_type
scope.register_struct_field(ast.ScopeStructField{
branch.scope.register_struct_field(ast.ScopeStructField{
struct_type: node.cond.expr_type
name: node.cond.field_name
typ: node.cond_type
@ -3656,7 +3647,8 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
mut is_mut := false
mut sum_type_casts := []table.Type{}
mut is_already_casted := false
if v := scope.find_var(node.cond.name) {
if node.cond.obj is ast.Var {
v := node.cond.obj as ast.Var
is_mut = v.is_mut
sum_type_casts << v.sum_type_casts
is_already_casted = v.pos.pos == node.cond.pos.pos
@ -3664,7 +3656,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
// smartcast either if the value is immutable or if the mut argument is explicitly given
if (!is_mut || node.cond.is_mut) && !is_already_casted {
sum_type_casts << expr_type
scope.register(ast.Var{
branch.scope.register(ast.Var{
name: node.cond.name
typ: node.cond_type
pos: node.cond.pos
@ -3891,10 +3883,9 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
// TODO: merge this code with match_expr because it has the same logic implemented
if left_sym.kind in [.interface_, .sum_type] {
mut is_mut := false
mut scope := c.file.scope.innermost(branch.body_pos.pos)
if mut infix.left is ast.Ident {
mut sum_type_casts := []table.Type{}
if v := scope.find_var(infix.left.name) {
if v := branch.scope.find_var(infix.left.name) {
is_mut = v.is_mut
sum_type_casts << v.sum_type_casts
}
@ -3902,7 +3893,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
// smartcast either if the value is immutable or if the mut argument is explicitly given
if !is_mut || infix.left.is_mut {
sum_type_casts << right_expr.typ
scope.register(ast.Var{
branch.scope.register(ast.Var{
name: infix.left.name
typ: infix.left_type
sum_type_casts: sum_type_casts
@ -3912,7 +3903,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
})
}
} else if left_sym.kind == .interface_ {
scope.register(ast.Var{
branch.scope.register(ast.Var{
name: infix.left.name
typ: right_expr.typ.to_ptr()
sum_type_casts: sum_type_casts
@ -3929,19 +3920,19 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
if field := c.table.struct_find_field(expr_sym, infix.left.field_name) {
if field.is_mut {
root_ident := infix.left.root_ident()
if v := scope.find_var(root_ident.name) {
is_mut = v.is_mut
if root_ident.obj is ast.Var {
is_mut = root_ident.obj.is_mut
}
}
}
if field := scope.find_struct_field(infix.left.expr_type,
if field := branch.scope.find_struct_field(infix.left.expr_type,
infix.left.field_name) {
sum_type_casts << field.sum_type_casts
}
// smartcast either if the value is immutable or if the mut argument is explicitly given
if (!is_mut || infix.left.is_mut) && left_sym.kind == .sum_type {
sum_type_casts << right_expr.typ
scope.register_struct_field(ast.ScopeStructField{
branch.scope.register_struct_field(ast.ScopeStructField{
struct_type: infix.left.expr_type
name: infix.left.field_name
typ: infix.left_type
@ -4159,12 +4150,12 @@ fn (mut c Checker) comp_if_branch(cond ast.Expr, pos token.Position) bool {
} else if cond.name !in c.pref.compile_defines_all {
// `$if some_var {}`
typ := c.expr(cond)
scope := c.file.scope.innermost(pos.pos)
obj := scope.find(cond.name) or {
if cond.obj !is ast.Var &&
cond.obj !is ast.ConstField && cond.obj !is ast.GlobalField {
c.error('unknown var: `$cond.name`', pos)
return false
}
expr := c.find_obj_definition(obj) or {
expr := c.find_obj_definition(cond.obj) or {
c.error(err, cond.pos)
return false
}
@ -4285,8 +4276,8 @@ pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) table.Type {
if !c.inside_unsafe && (typ.is_ptr() || typ.is_pointer()) {
mut is_ok := false
if mut node.left is ast.Ident {
scope := c.file.scope.innermost(node.left.pos.pos)
if v := scope.find_var(node.left.name) {
if node.left.obj is ast.Var {
v := node.left.obj as ast.Var
// `mut param []T` function parameter
is_ok = v.is_mut && v.is_arg && !typ.deref().is_ptr()
}

View File

@ -1735,7 +1735,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
val := assign_stmt.right[i]
mut is_call := false
mut blank_assign := false
mut ident := ast.Ident{}
mut ident := ast.Ident{
scope: 0
}
if left is ast.Ident {
ident = left
// id_info := ident.var_info()

View File

@ -126,7 +126,8 @@ fn (mut p Parser) vweb() ast.ComptimeCall {
for stmt in file.stmts {
if stmt is ast.FnDecl {
if stmt.name == 'main.vweb_tmpl_$tmp_fn_name' {
mut tmpl_scope := file.scope.innermost(stmt.body_pos.pos)
// mut tmpl_scope := file.scope.innermost(stmt.body_pos.pos)
mut tmpl_scope := stmt.scope
for _, obj in p.scope.objects {
if obj is ast.Var {
mut v := obj

View File

@ -101,6 +101,7 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp
kind: or_kind
pos: or_pos
}
scope: p.scope
}
}
@ -201,12 +202,16 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
rec_type = p.parse_type_with_mut(rec_mut)
if rec_type.idx() == 0 {
// error is set in parse_type
return ast.FnDecl{}
return ast.FnDecl{
scope: 0
}
}
rec_type_pos = rec_type_pos.extend(p.prev_tok.position())
if is_amp && rec_mut {
p.error('use `(mut f Foo)` or `(f &Foo)` instead of `(mut f &Foo)`')
return ast.FnDecl{}
return ast.FnDecl{
scope: 0
}
}
if is_shared {
rec_type = rec_type.set_flag(.shared_f)
@ -228,13 +233,17 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
name = if language == .js { p.check_js_name() } else { p.check_name() }
if language == .v && !p.pref.translated && util.contains_capital(name) && p.mod != 'builtin' {
p.error('function names cannot contain uppercase letters, use snake_case instead')
return ast.FnDecl{}
return ast.FnDecl{
scope: 0
}
}
type_sym := p.table.get_type_symbol(rec_type)
// interfaces are handled in the checker, methods can not be defined on them this way
if is_method && (type_sym.has_method(name) && type_sym.kind != .interface_) {
p.error('duplicate method `$name`')
return ast.FnDecl{}
return ast.FnDecl{
scope: 0
}
}
}
if p.tok.kind in [.plus, .minus, .mul, .div, .mod] {
@ -255,7 +264,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
for param in params {
if p.scope.known_var(param.name) {
p.error_with_pos('redefinition of parameter `$param.name`', param.pos)
return ast.FnDecl{}
return ast.FnDecl{
scope: 0
}
}
p.scope.register(ast.Var{
name: param.name
@ -291,7 +302,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
if is_non_local {
p.error_with_pos('cannot define new methods on non-local type $type_sym.name',
rec_type_pos)
return ast.FnDecl{}
return ast.FnDecl{
scope: 0
}
}
// p.warn('reg method $type_sym.name . $name ()')
type_sym_method_idx = type_sym.register_method(table.Fn{
@ -341,12 +354,13 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
if p.tok.kind == .lcbr {
stmts = p.parse_block_no_scope(true)
}
p.close_scope()
if !no_body && are_args_type_only {
p.error_with_pos('functions with type only args can not have bodies', body_start_pos)
return ast.FnDecl{}
return ast.FnDecl{
scope: 0
}
}
return ast.FnDecl{
fn_decl := ast.FnDecl{
name: name
mod: p.mod
stmts: stmts
@ -373,7 +387,10 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
file: p.file_name
is_builtin: p.builtin_mod || p.mod in util.builtin_module_parts
attrs: p.attrs
scope: p.scope
}
p.close_scope()
return fn_decl
}
fn (mut p Parser) anon_fn() ast.AnonFn {
@ -425,6 +442,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
no_body: no_body
pos: pos
file: p.file_name
scope: p.scope
}
typ: typ
}

View File

@ -19,13 +19,15 @@ fn (mut p Parser) for_stmt() ast.Stmt {
// Infinite loop
if p.tok.kind == .lcbr {
p.inside_for = false
stmts := p.parse_block()
p.close_scope()
return ast.ForStmt{
stmts := p.parse_block_no_scope(false)
for_stmt := ast.ForStmt{
stmts: stmts
pos: pos
is_inf: true
scope: p.scope
}
p.close_scope()
return for_stmt
} else if p.peek_tok.kind in [.decl_assign, .assign, .semicolon] || p.tok.kind == .semicolon {
// `for i := 0; i < 10; i++ {`
if p.tok.kind == .key_mut {
@ -60,9 +62,8 @@ fn (mut p Parser) for_stmt() ast.Stmt {
has_inc = true
}
p.inside_for = false
stmts := p.parse_block()
p.close_scope()
return ast.ForCStmt{
stmts := p.parse_block_no_scope(false)
for_c_stmt := ast.ForCStmt{
stmts: stmts
has_init: has_init
has_cond: has_cond
@ -71,7 +72,10 @@ fn (mut p Parser) for_stmt() ast.Stmt {
cond: cond
inc: inc
pos: pos
scope: p.scope
}
p.close_scope()
return for_c_stmt
} else if p.peek_tok.kind in [.key_in, .comma] ||
(p.tok.kind == .key_mut && p.peek_tok2.kind in [.key_in, .comma]) {
// `for i in vals`, `for i in start .. end`
@ -146,10 +150,9 @@ fn (mut p Parser) for_stmt() ast.Stmt {
})
}
p.inside_for = false
stmts := p.parse_block()
stmts := p.parse_block_no_scope(false)
// println('nr stmts=$stmts.len')
p.close_scope()
return ast.ForInStmt{
for_in_stmt := ast.ForInStmt{
stmts: stmts
cond: cond
key_var: key_var_name
@ -158,16 +161,21 @@ fn (mut p Parser) for_stmt() ast.Stmt {
is_range: is_range
pos: pos
val_is_mut: val_is_mut
scope: p.scope
}
p.close_scope()
return for_in_stmt
}
// `for cond {`
cond := p.expr(0)
p.inside_for = false
stmts := p.parse_block()
p.close_scope()
return ast.ForStmt{
stmts := p.parse_block_no_scope(false)
for_stmt := ast.ForStmt{
cond: cond
stmts: stmts
pos: pos
scope: p.scope
}
p.close_scope()
return for_stmt
}

View File

@ -43,9 +43,9 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
p.inside_if = false
end_pos := p.prev_tok.position()
body_pos := p.tok.position()
p.open_scope()
// only declare `err` if previous branch was an `if` guard
if prev_guard {
p.open_scope()
p.scope.register(ast.Var{
name: 'errcode'
typ: table.int_type
@ -60,18 +60,13 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
})
}
branches << ast.IfBranch{
stmts: if prev_guard {
p.parse_block_no_scope(false)
} else {
p.parse_block()
}
stmts: p.parse_block_no_scope(false)
pos: start_pos.extend(end_pos)
body_pos: body_pos.extend(p.tok.position())
comments: comments
scope: p.scope
}
if prev_guard {
p.close_scope()
}
p.close_scope()
comments = []
break
}
@ -116,16 +111,19 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
end_pos := p.prev_tok.position()
body_pos := p.tok.position()
p.inside_if = false
stmts := p.parse_block()
if is_guard {
p.close_scope()
}
p.open_scope()
stmts := p.parse_block_no_scope(false)
branches << ast.IfBranch{
cond: cond
stmts: stmts
pos: start_pos.extend(end_pos)
body_pos: body_pos.extend(p.prev_tok.position())
comments: comments
scope: p.scope
}
p.close_scope()
if is_guard {
p.close_scope()
}
comments = p.eat_comments()
if is_comptime {
@ -226,6 +224,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
// p.warn('match block')
p.inside_match_body = true
stmts := p.parse_block_no_scope(false)
branch_scope := p.scope
p.close_scope()
p.inside_match_body = false
pos := token.Position{
@ -242,6 +241,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
comments: comments
is_else: is_else
post_comments: post_comments
scope: branch_scope
}
if p.tok.kind == .rcbr || (is_else && no_lcbr) {
break

View File

@ -18,6 +18,7 @@ fn (mut p Parser) lock_expr() ast.LockExpr {
name: p.tok.lit
is_mut: true
info: ast.IdentVar{}
scope: p.scope
}
p.next()
if p.tok.kind == .lcbr {

View File

@ -521,6 +521,7 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
stmts: stmts
file: p.file_name
return_type: table.void_type
scope: p.scope
}
} else if p.pref.is_fmt {
return p.stmt(false)
@ -995,6 +996,7 @@ pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident {
is_mut: false
is_static: false
}
scope: p.scope
}
}
if p.inside_match_body && name == 'it' {
@ -1017,12 +1019,17 @@ pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident {
is_static: is_static
share: table.sharetype_from_flags(is_shared, is_atomic)
}
scope: p.scope
}
} else {
p.error('unexpected token `$p.tok.lit`')
return ast.Ident{}
return ast.Ident{
scope: 0
}
}
return ast.Ident{
scope: 0
}
return ast.Ident{}
}
pub fn (mut p Parser) name_expr() ast.Expr {
@ -1230,9 +1237,11 @@ pub fn (mut p Parser) name_expr() ast.Expr {
return ast.SelectorExpr{
expr: ast.Ident{
name: name
scope: p.scope
}
field_name: field
pos: pos
scope: p.scope
}
}
// `Color.green`
@ -1413,6 +1422,7 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
kind: or_kind
pos: or_pos
}
scope: p.scope
}
if is_filter || field_name == 'sort' {
p.close_scope()
@ -1436,6 +1446,7 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
pos: name_pos
is_mut: is_mut
mut_pos: mut_pos
scope: p.scope
}
mut node := ast.Expr{}
node = sel_expr
@ -2095,7 +2106,9 @@ fn (mut p Parser) assoc() ast.Assoc {
pos := p.tok.position()
mut v := p.scope.find_var(var_name) or {
p.error('unknown variable `$var_name`')
return ast.Assoc{}
return ast.Assoc{
scope: 0
}
}
v.is_used = true
// println('assoc var $name typ=$var.typ')
@ -2119,6 +2132,7 @@ fn (mut p Parser) assoc() ast.Assoc {
fields: fields
exprs: vals
pos: pos
scope: p.scope
}
}

View File

@ -235,6 +235,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
left: node
args: args
pos: pos
scope: p.scope
}
}
return node

View File

@ -439,6 +439,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
return_type: table.void_type
is_pub: true
pos: method_start_pos.extend(p.prev_tok.position())
scope: p.scope
}
if p.tok.kind.is_start_of_type() && p.tok.line_nr == line_nr {
method.return_type = p.parse_type()