diff options
| author | Daniel Gavin <danielgavin5@hotmail.com> | 2021-04-27 18:22:41 +0200 |
|---|---|---|
| committer | Daniel Gavin <danielgavin5@hotmail.com> | 2021-04-27 18:22:41 +0200 |
| commit | 07e8e34144d2c8929c8eb40779488464d77308bc (patch) | |
| tree | 25a64714b5f32241b6120071a2f3748aadc326cc /src | |
| parent | 6f6f95c000edb7305371f96d466731122ac54178 (diff) | |
work on completion tests + new symbols
Diffstat (limited to 'src')
| -rw-r--r-- | src/index/symbol.odin | 76 | ||||
| -rw-r--r-- | src/server/analysis.odin | 280 | ||||
| -rw-r--r-- | src/server/semantic_tokens.odin | 4 | ||||
| -rw-r--r-- | src/testing/testing.odin | 38 |
4 files changed, 255 insertions, 143 deletions
diff --git a/src/index/symbol.odin b/src/index/symbol.odin index 0f9069a..0b932a0 100644 --- a/src/index/symbol.odin +++ b/src/index/symbol.odin @@ -10,12 +10,6 @@ import "core:slice" import "shared:common" -/* - Note(Daniel, how concerned should we be about keeping the memory usage low for the symbol. You could hash some of strings. - Right now I have the unique string map in order to have strings reference the same string match.) - -*/ - SymbolStructValue :: struct { names: []string, types: []^ast.Expr, @@ -35,6 +29,11 @@ SymbolProcedureGroupValue :: struct { group: ^ast.Expr, } +//runtime temp symbol value +SymbolAggregateValue :: struct { + symbols: []Symbol, +} + SymbolEnumValue :: struct { names: []string, } @@ -44,10 +43,36 @@ SymbolUnionValue :: struct { types: []^ast.Expr, } +SymbolDynamicArrayValue :: struct { + expr: ^ast.Expr, +} + +SymbolFixedArrayValue :: struct { + len: ^ast.Expr, + expr: ^ast.Expr, +} + +SymbolSliceValue :: struct { + expr: ^ast.Expr, +} + +SymbolBasicValue :: struct { + ident: ^ast.Ident, +} + SymbolBitSetValue :: struct { expr: ^ast.Expr, } +SymbolUntypedValue :: struct { + type: enum {Integer, Float, String, Bool}, +} + +SymbolMapValue :: struct { + key: ^ast.Expr, + value: ^ast.Expr, +} + /* Generic symbol that is used by the indexer for any variable type(constants, defined global variables, etc), */ @@ -64,18 +89,27 @@ SymbolValue :: union { SymbolUnionValue, SymbolEnumValue, SymbolBitSetValue, + SymbolAggregateValue, + SymbolDynamicArrayValue, + SymbolFixedArrayValue, + SymbolMapValue, + SymbolSliceValue, + SymbolBasicValue, + SymbolUntypedValue, } Symbol :: struct { - range: common.Range, - uri: string, - pkg: string, - name: string, - doc: string, - signature: string, - returns: string, - type: SymbolType, - value: SymbolValue, + range: common.Range, + uri: string, + pkg: string, + name: string, + doc: string, + signature: string, + returns: string, + type: SymbolType, + value: SymbolValue, + pointers: int, + is_distinct: bool, } SymbolType :: enum { @@ -93,8 +127,8 @@ SymbolType :: enum { free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { if symbol.signature != "" && symbol.signature != "struct" && - symbol.signature != "union" && symbol.signature != "enum" && - symbol.signature != "bitset" { + symbol.signature != "union" && symbol.signature != "enum" && + symbol.signature != "bitset" { delete(symbol.signature, allocator); } @@ -124,6 +158,14 @@ free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { common.free_ast(v.types, allocator); case SymbolBitSetValue: common.free_ast(v.expr, allocator); + case SymbolDynamicArrayValue: + common.free_ast(v.expr, allocator); + case SymbolFixedArrayValue: + common.free_ast(v.expr, allocator); + case SymbolSliceValue: + common.free_ast(v.expr, allocator); + case SymbolBasicValue: + common.free_ast(v.ident, allocator); } } diff --git a/src/server/analysis.odin b/src/server/analysis.odin index f769ec2..6c615e6 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -23,10 +23,6 @@ import "shared:index" TODO(try to flatten some of the nested branches if possible) */ -bool_lit := "bool"; -int_lit := "int"; -string_lit := "string"; - DocumentPositionContextHint :: enum { Completion, SignatureHelp, @@ -374,9 +370,11 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast if arg_eval, ok := resolve_type_expression(ast_context, call_expr.args[i]); ok { + /* if value, ok := arg_eval.value.(index.SymbolGenericValue); ok { resolve_poly_spec_node(ast_context, value.expr, poly.specialization, &poly_map); } + */ } } @@ -464,6 +462,8 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou call_expr := ast_context.call; + candidates := make([dynamic] index.Symbol, context.temp_allocator); + for arg_expr in group.args { next_fn: if f, ok := resolve_type_expression(ast_context, arg_expr); ok { @@ -480,52 +480,56 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou #partial switch v in eval_call_expr.value { case index.SymbolProcedureValue: + /* case index.SymbolGenericValue: if !common.node_equal(v.expr, procedure.arg_types[i].type) { break next_fn; } + */ case index.SymbolStructValue: } } else { - //log.debug("Failed to resolve call expr"); return index.Symbol {}, false; } } - //log.debugf("return overload %v", f); + append(&candidates, f); + return f, true; } } } + if len(candidates) > 1 { + return index.Symbol { + value = index.SymbolAggregateValue { + symbols = candidates[:], + }, + }, true; + } else if len(candidates) == 1 { + return candidates[0], true; + } + return index.Symbol {}, false; } resolve_basic_lit :: proc(ast_context: ^AstContext, basic_lit: ast.Basic_Lit) -> (index.Symbol, bool) { - /* - This is temporary, since basic lit is untyped, but either way it's going to be an ident representing a keyword. - - Could perhaps name them "$integer", "$float", etc. - */ - - ident := index.new_type(ast.Ident, basic_lit.pos, basic_lit.end, context.temp_allocator); - symbol := index.Symbol { type = .Keyword, }; + value: index.SymbolUntypedValue; + if v, ok := strconv.parse_bool(basic_lit.tok.text); ok { - ident.name = bool_lit; + value.type = .Bool; } else if v, ok := strconv.parse_int(basic_lit.tok.text); ok { - ident.name = int_lit; + value.type = .Integer; } else { - ident.name = string_lit; + value.type = .String; } - symbol.value = index.SymbolGenericValue { - expr = ident, - }; + symbol.value = value; return symbol, true; } @@ -551,12 +555,16 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i return resolve_type_expression(ast_context, v.expr); case Unary_Expr: if v.op.kind == .And { - return resolve_type_expression(ast_context, make_pointer_ast(v.expr)); + symbol, ok := resolve_type_expression(ast_context, v.expr); + symbol.pointers += 1; + return symbol, ok; } else { return resolve_type_expression(ast_context, v.expr); } case Deref_Expr: - return resolve_type_expression(ast_context, v.expr); + symbol, ok := resolve_type_expression(ast_context, v.expr); + symbol.pointers -= 1; + return symbol, ok; case Paren_Expr: return resolve_type_expression(ast_context, v.expr); case Slice_Expr: @@ -580,32 +588,21 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i } } case Pointer_Type: - - /* - Add flag to not pull out a type from a pointer for function overloading. - */ - - if v2, ok := v.elem.derived.(ast.Pointer_Type); !ok { - return resolve_type_expression(ast_context, v.elem); - } else if v2, ok := v.elem.derived.(ast.Type_Assertion); !ok { - return resolve_type_expression(ast_context, v.elem); - } else { - return make_symbol_generic_from_ast(ast_context, node), true; - } - + symbol, ok := 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); - if generic, ok := indexed.value.(index.SymbolGenericValue); ok { - - switch c in generic.expr.derived { - case Array_Type: - return resolve_type_expression(ast_context, c.elem); - case Dynamic_Array_Type: - return resolve_type_expression(ast_context, c.elem); - case Map_Type: - return resolve_type_expression(ast_context, c.value); - } + #partial switch v2 in indexed.value { + case index.SymbolDynamicArrayValue: + return resolve_type_expression(ast_context, v2.expr); + case index.SymbolSliceValue: + return resolve_type_expression(ast_context, v2.expr); + case index.SymbolFixedArrayValue: + return resolve_type_expression(ast_context, v2.expr); + case index.SymbolMapValue: + return resolve_type_expression(ast_context, v2.value); } return index.Symbol {}, false; @@ -663,8 +660,6 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i if v == nil { return {}, false; } - - return make_symbol_generic_from_ast(ast_context, node), true; } return index.Symbol {}, false; @@ -769,9 +764,9 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i case Proc_Group: return resolve_function_overload(ast_context, v); case Array_Type: - return make_symbol_generic_from_ast(ast_context, local), true; + return make_symbol_array_from_ast(ast_context, v), true; case Dynamic_Array_Type: - return make_symbol_generic_from_ast(ast_context, local), true; + return make_symbol_dynamic_array_from_ast(ast_context, v), true; case Call_Expr: return resolve_type_expression(ast_context, local); case: @@ -806,9 +801,9 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i case Proc_Group: return resolve_function_overload(ast_context, v); case Array_Type: - return make_symbol_generic_from_ast(ast_context, global), true; + return make_symbol_array_from_ast(ast_context, v), true; case Dynamic_Array_Type: - return make_symbol_generic_from_ast(ast_context, global), true; + return make_symbol_dynamic_array_from_ast(ast_context, v), true; case Call_Expr: return resolve_type_expression(ast_context, global); case: @@ -827,13 +822,12 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i type = .Keyword, signature = node.name, pkg = ast_context.current_package, - value = index.SymbolGenericValue { - expr = ident, + value = index.SymbolBasicValue { + ident = ident, }, }; return symbol, true; } else { - //right now we replace the package ident with the absolute directory name, so it should have '/' which is not a valid ident character if strings.contains(node.name, "/") { @@ -845,7 +839,6 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i return symbol, true; } else { - //part of the ast so we check the imports of the document for imp in ast_context.imports { @@ -988,7 +981,6 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok return symbol, true; } case index.SymbolStructValue: - //expand the types and names from the using - can't be done while indexing without complicating everything(this also saves memory) if len(v.usings) > 0 { expanded := symbol; @@ -997,9 +989,6 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok } else { return symbol, true; } - - case index.SymbolGenericValue: - return resolve_type_expression(ast_context, v.expr); } return symbol, true; @@ -1009,15 +998,13 @@ fix_symbol_unresolved_type :: proc(symbol: ^index.Symbol) { using index; - switch v in symbol.value { + #partial switch v in symbol.value { case SymbolStructValue: symbol.type = .Struct; case SymbolPackageValue: symbol.type = .Package; case SymbolProcedureValue, SymbolProcedureGroupValue: symbol.type = .Function; - case SymbolGenericValue: - symbol.type = .Variable; case SymbolUnionValue: symbol.type = .Enum; case SymbolEnumValue: @@ -1098,13 +1085,13 @@ make_pointer_ast :: proc(elem: ^ast.Expr) -> ^ast.Pointer_Type { make_bool_ast :: proc() -> ^ast.Ident { ident := index.new_type(ast.Ident, {}, {}, context.temp_allocator); - ident.name = bool_lit; + ident.name = "bool"; return ident; } make_int_ast :: proc() -> ^ast.Ident { ident := index.new_type(ast.Ident, {}, {}, context.temp_allocator); - ident.name = int_lit; + ident.name = "int"; return ident; } @@ -1148,10 +1135,9 @@ make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v range = common.get_token_range(n^, ast_context.file.src), type = .Function, pkg = get_package_from_node(n^), + name = name, }; - symbol.name = name; - return_types := make([dynamic]^ast.Field, context.temp_allocator); arg_types := make([dynamic]^ast.Field, context.temp_allocator); @@ -1181,17 +1167,64 @@ make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v return symbol; } -make_symbol_generic_from_ast :: proc(ast_context: ^AstContext, expr: ^ast.Expr) -> index.Symbol { +make_symbol_slice_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v: ast.Slice_Expr) -> index.Symbol { + + symbol := index.Symbol { + range = common.get_token_range(n^, ast_context.file.src), + pkg = get_package_from_node(n^), + }; + + symbol.value = index.SymbolSliceValue { + expr = v.expr, + }; + + return symbol; +} + +make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type) -> index.Symbol { + + symbol := index.Symbol { + range = common.get_token_range(v.node, ast_context.file.src), + pkg = get_package_from_node(v.node), + }; + + if v.len == nil { + symbol.value = index.SymbolFixedArrayValue { + expr = v.elem, + len = v.len, + }; + } else { + symbol.value = index.SymbolDynamicArrayValue { + expr = v.elem, + }; + } + + return symbol; +} + +make_symbol_dynamic_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Dynamic_Array_Type) -> index.Symbol { symbol := index.Symbol { - range = common.get_token_range(expr, ast_context.file.src), - type = .Variable, - signature = index.node_to_string(expr), - pkg = get_package_from_node(expr^), + range = common.get_token_range(v.node, ast_context.file.src), + pkg = get_package_from_node(v.node), }; - symbol.value = index.SymbolGenericValue { - expr = expr, + symbol.value = index.SymbolDynamicArrayValue { + expr = v.elem, + }; + + return symbol; +} + +make_symbol_basic_type_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v: ^ast.Ident) -> index.Symbol { + + symbol := index.Symbol { + range = common.get_token_range(n^, ast_context.file.src), + pkg = get_package_from_node(n^), + }; + + symbol.value = index.SymbolBasicValue { + ident = v, }; return symbol; @@ -1603,59 +1636,66 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont } if symbol, ok := resolve_type_expression(ast_context, stmt.expr); ok { - - if generic, ok := symbol.value.(index.SymbolGenericValue); ok { - - switch v in generic.expr.derived { - case Map_Type: - if len(stmt.vals) >= 1 { - if ident, ok := stmt.vals[0].derived.(Ident); ok { - 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; - } + #partial switch v in symbol.value { + case index.SymbolMapValue: + if len(stmt.vals) >= 1 { + if ident, ok := stmt.vals[0].derived.(Ident); ok { + 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; } - - if len(stmt.vals) >= 2 { - if ident, ok := stmt.vals[1].derived.(Ident); ok { - 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; - } + } + if len(stmt.vals) >= 2 { + if ident, ok := stmt.vals[1].derived.(Ident); ok { + 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; } - case Dynamic_Array_Type: - if len(stmt.vals) >= 1 { - if ident, ok := stmt.vals[0].derived.(Ident); ok { - 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; - } + } + case index.SymbolDynamicArrayValue: + if len(stmt.vals) >= 1 { + if ident, ok := stmt.vals[0].derived.(Ident); ok { + store_local(ast_context, v.expr, ident.pos.offset, ident.name); + ast_context.variables[ident.name] = true; + ast_context.in_package[ident.name] = symbol.pkg; } - - if len(stmt.vals) >= 2 { - if ident, ok := stmt.vals[1].derived.(Ident); ok { - 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; - } + } + if len(stmt.vals) >= 2 { + if ident, ok := stmt.vals[1].derived.(Ident); ok { + 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; } - case Array_Type: - if len(stmt.vals) >= 1 { - - if ident, ok := stmt.vals[0].derived.(Ident); ok { - 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; - } + } + case index.SymbolFixedArrayValue: + if len(stmt.vals) >= 1 { + if ident, ok := stmt.vals[0].derived.(Ident); ok { + store_local(ast_context, v.expr, ident.pos.offset, ident.name); + ast_context.variables[ident.name] = true; + ast_context.in_package[ident.name] = symbol.pkg; } + } - if len(stmt.vals) >= 2 { - - if ident, ok := stmt.vals[1].derived.(Ident); ok { - 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; - } + if len(stmt.vals) >= 2 { + if ident, ok := stmt.vals[1].derived.(Ident); ok { + 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; + } + } + case index.SymbolSliceValue: + if len(stmt.vals) >= 1 { + if ident, ok := stmt.vals[0].derived.(Ident); ok { + store_local(ast_context, v.expr, ident.pos.offset, ident.name); + ast_context.variables[ident.name] = true; + ast_context.in_package[ident.name] = symbol.pkg; + } + } + if len(stmt.vals) >= 2 { + if ident, ok := stmt.vals[1].derived.(Ident); ok { + 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; } } } diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin index 4feced5..c9fde74 100644 --- a/src/server/semantic_tokens.odin +++ b/src/server/semantic_tokens.odin @@ -381,9 +381,9 @@ write_semantic_token_basic_lit :: proc(basic_lit: ast.Basic_Lit, builder: ^Seman ident := generic.expr.derived.(ast.Ident); - if ident.name == string_lit { + if ident.name == "string" { write_semantic_node(builder, generic.expr, ast_context.file.src, .String, .None); - } else if ident.name == int_lit { + } else if ident.name == "int" { write_semantic_node(builder, generic.expr, ast_context.file.src, .Number, .None); } else { } diff --git a/src/testing/testing.odin b/src/testing/testing.odin index aaba07b..9562bc4 100644 --- a/src/testing/testing.odin +++ b/src/testing/testing.odin @@ -74,7 +74,7 @@ expect_signature_labels :: proc(t: ^testing.T, src: ^Source, expect_labels: []st help, ok := server.get_signature_information(src.document, src.position); if !ok { - testing.errorf(t, "Failed get_signature_information"); + testing.error(t, "Failed get_signature_information"); } if len(expect_labels) == 0 && len(help.signatures) > 0 { @@ -83,9 +83,9 @@ expect_signature_labels :: proc(t: ^testing.T, src: ^Source, expect_labels: []st flags := make([]int, len(expect_labels)); - for expect_signature, i in expect_labels { + for expect_label, i in expect_labels { for signature, j in help.signatures { - if expect_signature == signature.label { + if expect_label == signature.label { flags[i] += 1; } } @@ -99,9 +99,39 @@ expect_signature_labels :: proc(t: ^testing.T, src: ^Source, expect_labels: []st } -expect_completion :: proc(t: ^testing.T, src: ^Source, dot: bool, expect_completions: []string) { +expect_completion_details :: proc(t: ^testing.T, src: ^Source, trigger_character: string, expect_details: []string) { setup(src); + completion_context := server.CompletionContext { + triggerCharacter = trigger_character, + }; + + completion_list, ok := server.get_completion_list(src.document, src.position, completion_context); + + if !ok { + testing.error(t, "Failed get_completion_list"); + } + + if len(expect_details) == 0 && len(completion_list.items) > 0 { + testing.errorf(t, "Expected empty completion label, but received %v", completion_list.items); + } + + flags := make([]int, len(expect_details)); + + for expect_detail, i in expect_details { + for completion, j in completion_list.items { + if expect_detail == completion.detail { + flags[i] += 1; + } + } + } + + for flag, i in flags { + if flag != 1 { + testing.errorf(t, "Expected completion label %v, but received %v", expect_details[i], completion_list.items); + } + } + } expect_hover :: proc(t: ^testing.T, src: ^Source, expect_hover_info: string) { |