diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2020-11-11 23:03:48 +0100 |
|---|---|---|
| committer | DanielGavin <danielgavin5@hotmail.com> | 2020-11-11 23:03:48 +0100 |
| commit | 2fba6caddadc6d7d10f6af5892de6fd44d2291d4 (patch) | |
| tree | cbbf2d7879765ae3591429cf6c589cc7aca5dcac /src/server | |
| parent | 1e37c50fca2422321981518424923589d071b890 (diff) | |
started working on type inference in the ast
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/analysis.odin | 282 | ||||
| -rw-r--r-- | src/server/documents.odin | 5 |
2 files changed, 250 insertions, 37 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin index ef1edbc..a1300fc 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -22,60 +22,263 @@ DocumentPositionContextHint :: enum { DocumentPositionContext :: struct { position: common.AbsolutePosition, function: ^ast.Node, //used to help with type resolving in function scope - selector: ^ast.Node, //used for completion + selector: ^ast.Expr, //used for completion identifier: ^ast.Node, - field: ^ast.Node, //used for completion - call: ^ast.Node, //used for signature help + field: ^ast.Expr, //used for completion + call: ^ast.Expr, //used for signature help hint: DocumentPositionContextHint, }; +AstContext :: struct { + locals: map [string] ^ast.Expr, //locals all the way to the document position + globals: map [string] ^ast.Expr, + file: ast.File, + allocator: mem.Allocator, +}; + +make_ast_context :: proc(allocator := context.temp_allocator) -> AstContext { + + ast_context := AstContext { + locals = make(map [string] ^ast.Expr, 0, allocator), + globals = make(map [string] ^ast.Expr, 0, allocator), + }; + + return ast_context; +} tokenizer_error_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { } +resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (index.Symbol, bool) { + + using ast; + + switch v in node.derived { + case Ident: + return resolve_type_identifier(ast_context, v); + case Selector_Expr: + log.info("another selector"); + //selector, ok := resolve_type_expression(ast_context, v.expr); + + //switch s in selector.value { + //case: + //} + + + case: + //return "", false; + } + + return index.Symbol {}, false; + +} + +/* + Function recusively goes through the identifier until it hits a struct, enum, procedure literals, since you can + have chained variable declarations. ie. a := foo { test = 2}; b := a; c := b; + */ +resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (index.Symbol, bool) { + + using ast; + + if local, ok := ast_context.locals[node.name]; ok { + + switch v in local.derived { + case Ident: + return resolve_type_identifier(ast_context, v); + case Struct_Type: + return make_symbol_struct_from_ast(ast_context, v), true; + case Proc_Lit: + return make_symbol_procedure_from_ast(ast_context, v), true; + case: + return index.Symbol {}, false; + } + + } + + if global, ok := ast_context.globals[node.name]; ok { + + switch v in global.derived { + case Ident: + return resolve_type_identifier(ast_context, v); + case Struct_Type: + return make_symbol_struct_from_ast(ast_context, v), true; + case Proc_Lit: + return make_symbol_procedure_from_ast(ast_context, v), true; + case: + return index.Symbol {}, false; + } + + } + + return index.Symbol {}, false; +} + +resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (index.Symbol, bool) { + + symbol: index.Symbol; + + if local, ok := ast_context.locals[node.name]; ok { + symbol.range = common.get_token_range(local, ast_context.file.src); + return symbol, true; + } + + else if global, ok := ast_context.globals[node.name]; ok { + symbol.range = common.get_token_range(global, ast_context.file.src); + return symbol, true; + } + + return symbol, false; +} + +make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, v: ast.Proc_Lit) -> index.Symbol { + + symbol := index.Symbol { + range = common.get_token_range(v, ast_context.file.src), + type = .Struct, + }; + + return symbol; +} + +make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type) -> index.Symbol { + + symbol := index.Symbol { + range = common.get_token_range(v, ast_context.file.src), + type = .Struct, + }; + + return symbol; +} + +make_symbol_package_from_ast :: proc(ast_context: ^AstContext, v: ast.Import_Decl) -> index.Symbol { + + symbol := index.Symbol { + range = common.get_token_range(v, ast_context.file.src), + type = .Struct, + }; + + return symbol; +} + +get_globals :: proc(file: ast.File, ast_context: ^AstContext) { + + for decl in file.decls { + + if value_decl, ok := decl.derived.(ast.Value_Decl); ok { + + for name, i in value_decl.names { + + str := common.get_ast_node_string(name, file.src); + + if value_decl.type != nil { + ast_context.globals[str] = value_decl.type; + } + + else { + ast_context.globals[str] = value_decl.values[i]; + } + + } + + } + } +} + +get_locals :: proc(file: ast.File, function: ^ast.Node, ast_context: ^AstContext) { + + proc_lit, ok := function.derived.(ast.Proc_Lit); + + if !ok || proc_lit.body == nil { + return; + } + + block: ast.Block_Stmt; + block, ok = proc_lit.body.derived.(ast.Block_Stmt); + + if !ok { + return; + } + + for stmt in block.stmts { + + if value_decl, ok := stmt.derived.(ast.Value_Decl); ok { + + for name, i in value_decl.names { + + str := common.get_ast_node_string(name, file.src); + + if value_decl.type != nil { + ast_context.locals[str] = value_decl.type; + } + + else { + ast_context.locals[str] = value_decl.values[i]; + } + + } + + } + + } + +} get_definition_location :: proc(document: ^Document, position: common.Position) -> (common.Location, bool) { location: common.Location; + + ast_context := make_ast_context(); + + symbol: index.Symbol; + position_context, ok := get_document_position_context(document, position, .Definition); if !ok { + log.info("Failed to get position context"); return location, false; } - symbol: index.Symbol; + get_globals(document.ast, &ast_context); - if position_context.selector != nil && position_context.field != nil { + if position_context.function != nil { + get_locals(document.ast, position_context.function, &ast_context); + } - selector: string; + /* + fmt.println(""); + fmt.println("locals"); + fmt.println(ast_context.locals); - switch v in position_context.selector.derived { - case ast.Ident: - selector = v.name; - case: - return location, false; - } + fmt.println(""); + fmt.println("globals: "); + fmt.println(ast_context.globals); + */ - field: string; - switch v in position_context.field.derived { - case ast.Ident: - field = v.name; - case: - return location, false; - } + if position_context.identifier != nil { - symbol, ok = index.lookup(strings.concatenate({selector, field}, context.temp_allocator)); + if resolved, ok := resolve_location_identifier(&ast_context, position_context.identifier.derived.(ast.Ident)); ok { + symbol = resolved; + } - if !ok { + else { return location, false; } } - else if position_context.identifier != nil { + else if position_context.selector != nil && position_context.field != nil { + + selector: index.Symbol; + + selector, ok = resolve_type_expression(&ast_context, position_context.selector); + + if !ok { + return location, false; + } field: string; @@ -86,22 +289,27 @@ get_definition_location :: proc(document: ^Document, position: common.Position) return location, false; } - symbol, ok = index.lookup(strings.concatenate({document.ast.pkg_name, field}, context.temp_allocator)); + //symbol, ok = index.lookup(strings.concatenate({selector, field}, context.temp_allocator)); if !ok { return location, false; } - } else { return location, false; } - location.range = symbol.range; - location.uri = symbol.uri; + + if symbol.uri == "" { + location.uri = document.uri.uri; + } + + else { + location.uri = symbol.uri; + } return location, true; @@ -111,8 +319,16 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( list: CompletionList; + ast_context := make_ast_context(); + position_context, ok := get_document_position_context(document, position, .Completion); + get_globals(document.ast, &ast_context); + + if position_context.function != nil { + get_locals(document.ast, position_context.function, &ast_context); + } + /* symbols: [] index.Symbol; //if we have format "selector.access" with plain identifiers @@ -120,11 +336,10 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( selector: string; - switch v in position_context.selector.derived { - case ast.Ident: - selector = v.name; - case: - return list, false; + selector, ok = resolve_type_expression(&ast_context, position_context.selector); + + if !ok { + return list, true; } field: string; @@ -133,7 +348,7 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( case ast.Ident: field = v.name; case: - return list, false; + return list, true; } symbols, ok = index.fuzzy_search(field, {selector}); @@ -155,6 +370,7 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> ( list.items[i].label = symbol.name; list.items[i].kind = cast(CompletionItemKind) symbol.type; } + */ return list, true; } @@ -163,6 +379,8 @@ get_signature_information :: proc(document: ^Document, position: common.Position signature_help: SignatureHelp; + ast_context := make_ast_context(); + position_context, ok := get_document_position_context(document, position, .SignatureHelp); return signature_help, true; diff --git a/src/server/documents.odin b/src/server/documents.odin index 4c35641..d68bb57 100644 --- a/src/server/documents.odin +++ b/src/server/documents.odin @@ -437,8 +437,3 @@ parse_document :: proc(document: ^Document, config: ^common.Config) -> ([] Parse return current_errors[:], true; } - - -free_ast_node :: proc(file: ^ast.Node) { - -}
\ No newline at end of file |