diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2021-02-11 18:23:52 +0100 |
|---|---|---|
| committer | DanielGavin <danielgavin5@hotmail.com> | 2021-02-11 18:23:52 +0100 |
| commit | ffd28b51411fbc5a665374d5ca0bc867138e4175 (patch) | |
| tree | cbc34531e8d2e8f724b7458c5448189c8c7fc550 /src | |
| parent | 51595ac19fe8f7c13788199c8af8033eddbf2448 (diff) | |
major rewrite of the locals now having a stack per variable, since they can now be shadowed
Diffstat (limited to 'src')
| -rw-r--r-- | src/index/collector.odin | 4 | ||||
| -rw-r--r-- | src/index/symbol.odin | 16 | ||||
| -rw-r--r-- | src/server/analysis.odin | 134 | ||||
| -rw-r--r-- | src/server/completion.odin | 15 |
4 files changed, 137 insertions, 32 deletions
diff --git a/src/index/collector.odin b/src/index/collector.odin index 0a765ad..c9d21f2 100644 --- a/src/index/collector.odin +++ b/src/index/collector.odin @@ -266,6 +266,10 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri token_type = .Enum; symbol.value = collect_union_fields(collection, v, package_map); symbol.signature = "union"; + case ast.Bit_Set_Type: + + case ast.Bit_Field_Type: + case ast.Basic_Lit: token = v; symbol.value = collect_generic(collection, col_expr, package_map); diff --git a/src/index/symbol.odin b/src/index/symbol.odin index 8e0a9d0..a0fab6d 100644 --- a/src/index/symbol.odin +++ b/src/index/symbol.odin @@ -47,6 +47,15 @@ SymbolUnionValue :: struct { names: [] string, }; +SymbolBitSetValue :: struct { + expr: ^ast.Expr, +}; + +SymbolBitFieldValue :: struct { + names: [] string, + bits: [] int, +}; + /* Generic symbol that is used by the indexer for any variable type(constants, defined global variables, etc), */ @@ -62,6 +71,8 @@ SymbolValue :: union { SymbolProcedureGroupValue, SymbolUnionValue, SymbolEnumValue, + SymbolBitSetValue, + SymbolBitFieldValue }; Symbol :: struct { @@ -116,6 +127,11 @@ free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { delete(v.names, allocator); case SymbolUnionValue: delete(v.names, allocator); + case SymbolBitFieldValue: + delete(v.names, allocator); + delete(v.bits, allocator); + case SymbolBitSetValue: + common.free_ast(v.expr, allocator); } } diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 6d791e9..f2a5779 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -12,6 +12,7 @@ import "core:strconv" import "core:path/filepath" import "core:sort" import "core:slice" +import "core:unicode/utf8" import "shared:common" import "shared:index" @@ -47,11 +48,17 @@ DocumentPositionContext :: struct { implicit: bool, //used for completion binary: ^ast.Binary_Expr, //used for completion assign: ^ast.Assign_Stmt, //used for completion + value_decl: ^ast.Value_Decl, hint: DocumentPositionContextHint, }; +DocumentLocal :: struct { + expr: ^ast.Expr, + offset: int, +} + AstContext :: struct { - locals: map [string] ^ast.Expr, //locals all the way to the document position + locals: map [string] [dynamic] DocumentLocal, //locals all the way to the document position globals: map [string] ^ast.Expr, variables: map [string] bool, parameters: map [string] bool, @@ -65,12 +72,14 @@ AstContext :: struct { use_globals: bool, use_locals: bool, 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, }; make_ast_context :: proc(file: ast.File, imports: [] Package, package_name: string, allocator := context.temp_allocator) -> AstContext { ast_context := AstContext { - locals = make(map [string] ^ast.Expr, 0, allocator), + locals = make(map [string] [dynamic] DocumentLocal, 0, allocator), globals = make(map [string] ^ast.Expr, 0, allocator), variables = make(map [string] bool, 0, allocator), usings = make([dynamic] string, allocator), @@ -731,6 +740,54 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i return index.Symbol {}, false; } +store_local :: proc(ast_context: ^AstContext, expr: ^ast.Expr, offset: int, name: string) { + + local_stack := &ast_context.locals[name]; + + if local_stack == nil { + ast_context.locals[name] = make([dynamic] DocumentLocal, context.temp_allocator); + local_stack = &ast_context.locals[name]; + } + + append(local_stack, DocumentLocal { expr = expr, offset = offset }); +} + +get_local :: proc(ast_context: ^AstContext, offset: int, name: string) -> ^ast.Expr { + + previous := 0; + + //is the local we are getting being declared? + if ast_context.value_decl != nil { + + for value_decl_name in ast_context.value_decl.names { + + if ident, ok := value_decl_name.derived.(ast.Ident); ok { + + if ident.name == name { + previous = 1; + break; + } + } + + } + + + } + + if local_stack, ok := ast_context.locals[name]; ok { + + for i := len(local_stack)-1; i >= 0; i -= 1 { + + if local_stack[i].offset <= offset { + return local_stack[max(0, i - previous)].expr; + } + + } + + } + + return nil; +} /* Function recusively goes through the identifier until it hits a struct, enum, procedure literals, since you can @@ -763,7 +820,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i } //note(Daniel, if global and local ends up being 100% same just make a function that takes the map) - if local, ok := ast_context.locals[node.name]; ast_context.use_locals && ok { + if local := get_local(ast_context, node.pos.offset, node.name); local != nil && ast_context.use_locals { switch v in local.derived { case Ident: @@ -1054,8 +1111,8 @@ resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) - symbol: index.Symbol; - if local, ok := ast_context.locals[node.name]; ok { - symbol.range = common.get_token_range(local, ast_context.file.src); + if local := get_local(ast_context, node.pos.offset, node.name); local != nil { + symbol.range = common.get_token_range(get_local(ast_context, node.pos.offset, node.name), ast_context.file.src); return symbol, true; } @@ -1086,12 +1143,6 @@ make_int_ast :: proc() -> ^ast.Ident { return ident; } -make_ident_ast :: proc(name: string) -> ^ast.Ident { - ident := index.new_type(ast.Ident, {}, {}, context.temp_allocator); - ident.name = name; - return ident; -} - get_package_from_node :: proc(node: ast.Node) -> string { slashed, _ := filepath.to_slash(node.pos.file, context.temp_allocator); ret := strings.to_lower(path.dir(slashed, context.temp_allocator), context.temp_allocator); @@ -1439,7 +1490,7 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co if value_decl.type != nil { str := common.get_ast_node_string(value_decl.names[0], file.src); ast_context.variables[str] = value_decl.is_mutable; - ast_context.locals[str] = value_decl.type; + store_local(ast_context, value_decl.type, value_decl.pos.offset, str); return; } @@ -1453,7 +1504,7 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co if i < len(results) { str := common.get_ast_node_string(name, file.src); ast_context.in_package[str] = get_package_from_node(results[i]); - ast_context.locals[str] = results[i]; + store_local(ast_context, results[i], name.pos.offset, str); ast_context.variables[str] = value_decl.is_mutable; } } @@ -1533,7 +1584,7 @@ get_locals_using_stmt :: proc(file: ast.File, stmt: ast.Using_Stmt, ast_context: selector.expr = u; selector.field = index.new_type(ast.Ident, v.types[i].pos, v.types[i].end, context.temp_allocator); selector.field.name = name; - ast_context.locals[name] = selector; + store_local(ast_context, selector, 0, name); ast_context.variables[name] = true; } @@ -1568,7 +1619,7 @@ get_locals_assign_stmt :: proc(file: ast.File, stmt: ast.Assign_Stmt, ast_contex for lhs, i in stmt.lhs { if ident, ok := lhs.derived.(ast.Ident); ok { - ast_context.locals[ident.name] = results[i]; + store_local(ast_context, results[i], ident.pos.offset, ident.name); ast_context.variables[ident.name] = true; } } @@ -1609,7 +1660,7 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont if stmt.val0 != nil { if ident, ok := stmt.val0.derived.(Ident); ok { - ast_context.locals[ident.name] = v.key; + store_local(ast_context, v.key, ident.pos.offset, ident.name); ast_context.variables[ident.name] = true; ast_context.in_package[ident.name] = symbol.pkg; } @@ -1619,7 +1670,7 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont if stmt.val1 != nil { if ident, ok := stmt.val1.derived.(Ident); ok { - ast_context.locals[ident.name] = v.value; + store_local(ast_context, v.value, ident.pos.offset, ident.name); ast_context.variables[ident.name] = true; ast_context.in_package[ident.name] = symbol.pkg; } @@ -1629,7 +1680,7 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont if stmt.val0 != nil { if ident, ok := stmt.val0.derived.(Ident); ok { - ast_context.locals[ident.name] = v.elem; + store_local(ast_context, v.elem, ident.pos.offset, ident.name); ast_context.variables[ident.name] = true; ast_context.in_package[ident.name] = symbol.pkg; } @@ -1639,7 +1690,7 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont if stmt.val1 != nil { if ident, ok := stmt.val1.derived.(Ident); ok { - ast_context.locals[ident.name] = make_int_ast(); + store_local(ast_context, make_int_ast(), ident.pos.offset, ident.name); ast_context.variables[ident.name] = true; ast_context.in_package[ident.name] = symbol.pkg; } @@ -1649,7 +1700,7 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont if stmt.val0 != nil { if ident, ok := stmt.val0.derived.(Ident); ok { - ast_context.locals[ident.name] = v.elem; + store_local(ast_context, v.elem, ident.pos.offset, ident.name); ast_context.variables[ident.name] = true; ast_context.in_package[ident.name] = symbol.pkg; } @@ -1659,7 +1710,7 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont if stmt.val1 != nil { if ident, ok := stmt.val1.derived.(Ident); ok { - ast_context.locals[ident.name] = make_int_ast(); + store_local(ast_context, make_int_ast(), ident.pos.offset, ident.name); ast_context.variables[ident.name] = true; ast_context.in_package[ident.name] = symbol.pkg; } @@ -1719,7 +1770,7 @@ get_locals_type_switch_stmt :: proc(file: ast.File, stmt: ast.Type_Switch_Stmt, if len(tag.lhs) == 1 && len(cause.list) == 1 { ident := tag.lhs[0].derived.(Ident); - ast_context.locals[ident.name] = cause.list[0]; + store_local(ast_context, cause.list[0], ident.pos.offset, ident.name); ast_context.variables[ident.name] = true; } @@ -1747,7 +1798,7 @@ get_locals :: proc(file: ast.File, function: ^ast.Node, ast_context: ^AstContext for name in arg.names { if arg.type != nil { str := common.get_ast_node_string(name, file.src); - ast_context.locals[str] = arg.type; + store_local(ast_context, arg.type, name.pos.offset, str); ast_context.variables[str] = true; ast_context.parameters[str] = true; @@ -1981,7 +2032,7 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: index. if is_variable, ok := ast_context.variables[ident.name]; ok && is_variable { - if local, ok := ast_context.locals[ident.name]; ok { + if local := get_local(ast_context, ident.pos.offset, ident.name); local != nil { if i, ok := local.derived.(ast.Ident); ok { return get_signature(ast_context, i, symbol, true); @@ -2115,6 +2166,10 @@ get_document_symbols :: proc(document: ^Document) -> [] DocumentSymbol { } /* + All these fallback functions are differently not perfect and should be fixed. A lot of weird use of the odin tokenizer and parser. +*/ + +/* Figure out what exactly is at the given position and whether it is in a function, struct, etc. */ get_document_position_context :: proc(document: ^Document, position: common.Position, hint: DocumentPositionContextHint) -> (DocumentPositionContext, bool) { @@ -2228,9 +2283,12 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm end -= 1; } - str := position_context.file.src[max(0, start):max(start, end+1)]; + begin_offset := max(0, start); + end_offset := max(start, end+1); + + str := position_context.file.src[0:end_offset]; - if empty_dot && len(str) == 0 { + if empty_dot && end_offset - begin_offset == 0 { position_context.implicit = true; return; } @@ -2245,7 +2303,16 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm tokenizer.init(&p.tok, str, position_context.file.fullpath, parser_warning_handler); + p.tok.ch = ' '; p.tok.line_count = position.line; + p.tok.offset = begin_offset; + p.tok.read_offset = begin_offset; + + tokenizer.advance_rune(&p.tok); + + if p.tok.ch == utf8.RUNE_BOM { + tokenizer.advance_rune(&p.tok); + } parser.advance_token(&p); @@ -2314,7 +2381,10 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo return; } - str := position_context.file.src[max(0, start):max(start, end)]; + begin_offset := max(0, start); + end_offset := max(start, end+1); + + str := position_context.file.src[0:end_offset]; p := parser.Parser { err = parser_warning_handler, //empty @@ -2324,7 +2394,16 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo tokenizer.init(&p.tok, str, position_context.file.fullpath, parser_warning_handler); + p.tok.ch = ' '; p.tok.line_count = position.line; + p.tok.offset = begin_offset; + p.tok.read_offset = begin_offset; + + tokenizer.advance_rune(&p.tok); + + if p.tok.ch == utf8.RUNE_BOM { + tokenizer.advance_rune(&p.tok); + } parser.advance_token(&p); @@ -2527,6 +2606,7 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP get_document_position(n.list, position_context); case Bad_Decl: case Value_Decl: + position_context.value_decl = cast(^Value_Decl)node; get_document_position(n.attributes, position_context); get_document_position(n.names, position_context); get_document_position(n.type, position_context); diff --git a/src/server/completion.odin b/src/server/completion.odin index f4ceaee..026c97d 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -20,13 +20,14 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( list: CompletionList; - ast_context := make_ast_context(document.ast, document.imports, document.package_name); - position_context, ok := get_document_position_context(document, position, .Completion); + ast_context := make_ast_context(document.ast, document.imports, document.package_name); + get_globals(document.ast, &ast_context); ast_context.current_package = ast_context.document_package; + ast_context.value_decl = position_context.value_decl; if position_context.function != nil { get_locals(document.ast, position_context.function, &ast_context, &position_context); @@ -212,7 +213,7 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc if ident, ok := position_context.selector.derived.(ast.Ident); ok { - if !resolve_ident_is_variable(ast_context, ident) && !resolve_ident_is_package(ast_context, ident) { + if !resolve_ident_is_variable(ast_context, ident) && !resolve_ident_is_package(ast_context, ident) && ident.name != "" { return; } @@ -688,7 +689,7 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D ast_context.use_globals = true; ast_context.current_package = ast_context.document_package; - ident := index.new_type(ast.Ident, tokenizer.Pos {}, tokenizer.Pos {}, context.temp_allocator); + ident := index.new_type(ast.Ident, v.pos, v.end, context.temp_allocator); ident.name = k; if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { @@ -702,13 +703,17 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D } } + + for k, v in ast_context.locals { ast_context.use_locals = true; ast_context.use_globals = true; ast_context.current_package = ast_context.document_package; - ident := index.new_type(ast.Ident, tokenizer.Pos {}, tokenizer.Pos {}, context.temp_allocator); + last_local := v[len(v)-1]; + + ident := index.new_type(ast.Ident, last_local.expr.pos, last_local.expr.end, context.temp_allocator); ident.name = k; if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { |