diff options
Diffstat (limited to 'src/server/analysis.odin')
| -rw-r--r-- | src/server/analysis.odin | 214 |
1 files changed, 131 insertions, 83 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin index c7081c5..2630b79 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -70,28 +70,28 @@ DocumentLocal :: struct { } AstContext :: struct { - locals: map[int]map[string][dynamic]DocumentLocal, //locals all the way to the document position - globals: map[string]common.GlobalExpr, - variables: map[string]bool, - parameters: map[string]bool, - in_package: map[string]string, //sometimes you have to extract types from arrays/maps and you lose package information - usings: [dynamic]string, - file: ast.File, - allocator: mem.Allocator, - imports: []Package, //imports for the current document - current_package: string, - document_package: string, - use_globals: bool, - use_locals: bool, - local_id: int, - call: ^ast.Call_Expr, //used to determene the types for generics and the correct function for overloaded functions - position: common.AbsolutePosition, - value_decl: ^ast.Value_Decl, - field_name: ast.Ident, - uri: string, - fullpath: string, - recursion_counter: int, //Sometimes the ast is so malformed that it causes infinite recursion. - non_mutable_only: bool, + locals: map[int]map[string][dynamic]DocumentLocal, //locals all the way to the document position + globals: map[string]common.GlobalExpr, + variables: map[string]bool, + parameters: map[string]bool, + in_package: map[string]string, //sometimes you have to extract types from arrays/maps and you lose package information + recursion_map: map[rawptr]bool, + usings: [dynamic]string, + file: ast.File, + allocator: mem.Allocator, + imports: []Package, //imports for the current document + current_package: string, + document_package: string, + use_globals: bool, + use_locals: bool, + local_id: int, + call: ^ast.Call_Expr, //used to determene the types for generics and the correct function for overloaded functions + position: common.AbsolutePosition, + value_decl: ^ast.Value_Decl, + field_name: ast.Ident, + uri: string, + fullpath: string, + non_mutable_only: bool, } make_ast_context :: proc( @@ -113,6 +113,7 @@ make_ast_context :: proc( usings = make([dynamic]string, allocator), parameters = make(map[string]bool, 0, allocator), in_package = make(map[string]string, 0, allocator), + recursion_map = make(map[rawptr]bool, 0, allocator), file = file, imports = imports, use_locals = true, @@ -129,6 +130,12 @@ make_ast_context :: proc( return ast_context } +reset_ast_context :: proc(ast_context: ^AstContext) { + ast_context.use_globals = true + ast_context.use_locals = true + clear(&ast_context.recursion_map) +} + tokenizer_error_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { } @@ -1029,12 +1036,26 @@ resolve_basic_directive :: proc( ) ident.name = "Source_Code_Location" ast_context.current_package = ast_context.document_package - return resolve_type_identifier(ast_context, ident^) + return internal_resolve_type_identifier(ast_context, ident^) } return {}, false } +check_node_recursion :: proc( + ast_context: ^AstContext, + node: ^ast.Node, +) -> bool { + raw := cast(rawptr)node + + if raw in ast_context.recursion_map { + return true + } + + ast_context.recursion_map[raw] = true + + return false +} resolve_type_expression :: proc( ast_context: ^AstContext, @@ -1043,6 +1064,17 @@ resolve_type_expression :: proc( Symbol, bool, ) { + clear(&ast_context.recursion_map) + return internal_resolve_type_expression(ast_context, node) +} + +internal_resolve_type_expression :: proc( + ast_context: ^AstContext, + node: ^ast.Expr, +) -> ( + Symbol, + bool, +) { if node == nil { return {}, false } @@ -1053,25 +1085,19 @@ resolve_type_expression :: proc( ast_context.current_package = saved_package } - if ast_context.recursion_counter > 200 { - log.error("Recursion passed 200 attempts - giving up", node) + if check_node_recursion(ast_context, node) { + log.error("Recursion detected") return {}, false } - ast_context.recursion_counter += 1 - - defer { - ast_context.recursion_counter -= 1 - } - using ast #partial switch v in node.derived { case ^ast.Value_Decl: if v.type != nil { - return resolve_type_expression(ast_context, v.type) + return internal_resolve_type_expression(ast_context, v.type) } else if len(v.values) > 0 { - return resolve_type_expression(ast_context, v.values[0]) + return internal_resolve_type_expression(ast_context, v.values[0]) } case ^Union_Type: return make_symbol_union_from_ast( @@ -1150,47 +1176,49 @@ resolve_type_expression :: proc( case ^Basic_Lit: return resolve_basic_lit(ast_context, v^) case ^Type_Cast: - return resolve_type_expression(ast_context, v.type) + return internal_resolve_type_expression(ast_context, v.type) case ^Auto_Cast: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Comp_Lit: - return resolve_type_expression(ast_context, v.type) + return internal_resolve_type_expression(ast_context, v.type) case ^Unary_Expr: if v.op.kind == .And { - symbol, ok := resolve_type_expression(ast_context, v.expr) + symbol, ok := internal_resolve_type_expression(ast_context, v.expr) symbol.pointers += 1 return symbol, ok } else { - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) } case ^Deref_Expr: - symbol, ok := resolve_type_expression(ast_context, v.expr) + symbol, ok := internal_resolve_type_expression(ast_context, v.expr) symbol.pointers -= 1 return symbol, ok case ^Paren_Expr: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Slice_Expr: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Tag_Expr: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Helper_Type: - return resolve_type_expression(ast_context, v.type) + return internal_resolve_type_expression(ast_context, v.type) case ^Ellipsis: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Implicit: ident := new_type(Ident, v.node.pos, v.node.end, ast_context.allocator) ident.name = v.tok.text - return resolve_type_identifier(ast_context, ident^) + return internal_resolve_type_identifier(ast_context, ident^) case ^Type_Assertion: if unary, ok := v.type.derived.(^ast.Unary_Expr); ok { if unary.op.kind == .Question { - if symbol, ok := resolve_type_expression(ast_context, v.expr); - ok { + if symbol, ok := internal_resolve_type_expression( + ast_context, + v.expr, + ); ok { if union_value, ok := symbol.value.(SymbolUnionValue); ok { if len(union_value.types) != 1 { return {}, false } - return resolve_type_expression( + return internal_resolve_type_expression( ast_context, union_value.types[0], ) @@ -1198,23 +1226,23 @@ resolve_type_expression :: proc( } } } else { - return resolve_type_expression(ast_context, v.type) + return internal_resolve_type_expression(ast_context, v.type) } case ^Proc_Lit: if v.type.results != nil { if len(v.type.results.list) == 1 { - return resolve_type_expression( + return internal_resolve_type_expression( ast_context, v.type.results.list[0].type, ) } } case ^Pointer_Type: - symbol, ok := resolve_type_expression(ast_context, v.elem) + symbol, ok := internal_resolve_type_expression(ast_context, v.elem) symbol.pointers += 1 return symbol, ok case ^Index_Expr: - indexed, ok := resolve_type_expression(ast_context, v.expr) + indexed, ok := internal_resolve_type_expression(ast_context, v.expr) if !ok { return {}, false @@ -1224,15 +1252,18 @@ resolve_type_expression :: proc( #partial switch v2 in indexed.value { case SymbolDynamicArrayValue: - symbol, ok = resolve_type_expression(ast_context, v2.expr) + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) case SymbolSliceValue: - symbol, ok = resolve_type_expression(ast_context, v2.expr) + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) case SymbolFixedArrayValue: - symbol, ok = resolve_type_expression(ast_context, v2.expr) + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) case SymbolMapValue: - symbol, ok = resolve_type_expression(ast_context, v2.value) + symbol, ok = internal_resolve_type_expression( + ast_context, + v2.value, + ) case SymbolMultiPointer: - symbol, ok = resolve_type_expression(ast_context, v2.expr) + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) } symbol.type = indexed.type @@ -1240,13 +1271,16 @@ resolve_type_expression :: proc( return symbol, ok case ^Call_Expr: ast_context.call = cast(^Call_Expr)node - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Implicit_Selector_Expr: return Symbol{}, false case ^Selector_Call_Expr: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Selector_Expr: - if selector, ok := resolve_type_expression(ast_context, v.expr); ok { + if selector, ok := internal_resolve_type_expression( + ast_context, + v.expr, + ); ok { ast_context.use_locals = false #partial switch s in selector.value { @@ -1276,7 +1310,10 @@ resolve_type_expression :: proc( ast_context.current_package = ast_context.document_package } - symbol, ok := resolve_type_expression(ast_context, s.expr) + symbol, ok := internal_resolve_type_expression( + ast_context, + s.expr, + ) symbol.type = .Variable return symbol, ok } else { @@ -1303,7 +1340,10 @@ resolve_type_expression :: proc( ) selector_expr.expr = s.return_types[0].type selector_expr.field = v.field - return resolve_type_expression(ast_context, selector_expr) + return internal_resolve_type_expression( + ast_context, + selector_expr, + ) } case SymbolStructValue: if selector.pkg != "" { @@ -1315,7 +1355,7 @@ resolve_type_expression :: proc( for name, i in s.names { if v.field != nil && name == v.field.name { ast_context.field_name = v.field^ - symbol, ok := resolve_type_expression( + symbol, ok := internal_resolve_type_expression( ast_context, s.types[i], ) @@ -1341,7 +1381,7 @@ resolve_type_expression :: proc( return Symbol{}, false } case: - log.warnf("default node kind, resolve_type_expression: %T", v) + log.warnf("default node kind, internal_resolve_type_expression: %T", v) if v == nil { return {}, false } @@ -1474,10 +1514,21 @@ resolve_type_identifier :: proc( Symbol, bool, ) { + clear(&ast_context.recursion_map) + return internal_resolve_type_identifier(ast_context, node) +} + +internal_resolve_type_identifier :: proc( + ast_context: ^AstContext, + node: ast.Ident, +) -> ( + Symbol, + bool, +) { using ast - if ast_context.recursion_counter > 200 { - log.error("Recursion passed 200 attempts - giving up", node) + if check_node_recursion(ast_context, node.derived.(^ast.Ident)) { + log.error("Recursion detected") return {}, false } @@ -1487,12 +1538,6 @@ resolve_type_identifier :: proc( ast_context.current_package = saved_package } - ast_context.recursion_counter += 1 - - defer { - ast_context.recursion_counter -= 1 - } - if pkg, ok := ast_context.in_package[node.name]; ok { ast_context.current_package = pkg } @@ -1561,7 +1606,10 @@ resolve_type_identifier :: proc( #partial switch v in local.derived { case ^Ident: - return_symbol, ok = resolve_type_identifier(ast_context, v^) + return_symbol, ok = internal_resolve_type_identifier( + ast_context, + v^, + ) case ^Union_Type: return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true @@ -1655,7 +1703,10 @@ resolve_type_identifier :: proc( #partial switch v in global.expr.derived { case ^Ident: - return_symbol, ok = resolve_type_identifier(ast_context, v^) + return_symbol, ok = internal_resolve_type_identifier( + ast_context, + v^, + ) case ^Struct_Type: return_symbol, ok = make_symbol_struct_from_ast(ast_context, v^, node), true @@ -1713,7 +1764,7 @@ resolve_type_identifier :: proc( return_symbol.name = node.name return_symbol.type = global.mutable ? .Variable : .Constant case: - return_symbol, ok = resolve_type_expression( + return_symbol, ok = internal_resolve_type_expression( ast_context, global.expr, ) @@ -2013,8 +2064,7 @@ resolve_location_selector :: proc( Symbol, bool, ) { - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) ast_context.current_package = ast_context.document_package symbol, ok := resolve_type_expression(ast_context, selector.expr) @@ -2657,8 +2707,7 @@ get_generic_assignment :: proc( ) { using ast - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) #partial switch v in value.derived { case ^Or_Return_Expr: @@ -2788,8 +2837,7 @@ get_locals_stmt :: proc( document_position: ^DocumentPositionContext, save_assign := false, ) { - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) ast_context.current_package = ast_context.document_package using ast @@ -3420,8 +3468,8 @@ resolve_entire_decl :: proc( } data := cast(^Visit_Data)visitor.data ast_context := data.ast_context - ast_context.use_locals = true - ast_context.use_globals = true + + reset_ast_context(ast_context) data.last_visit = node |