all: optimize scope usage in checker & parser. store scope in ast nodes (#7281)
parent
eb48208599
commit
0aa9f5a007
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue