From 28ce0ddfebfd671094e8da231923ff96fb72dd47 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 5 May 2021 23:43:12 +0200 Subject: begun argument underlining --- src/server/analysis.odin | 28 ++++++++++++++++++++++++++ src/server/signature.odin | 50 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 74 insertions(+), 4 deletions(-) (limited to 'src/server') diff --git a/src/server/analysis.odin b/src/server/analysis.odin index cd505ce..d7ac8ef 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -57,6 +57,7 @@ DocumentPositionContext :: struct { hint: DocumentPositionContextHint, global_lhs_stmt: bool, import_stmt: ^ast.Import_Decl, + call_commas: []int, } DocumentLocal :: struct { @@ -2284,6 +2285,29 @@ get_document_symbols :: proc(document: ^Document) -> []DocumentSymbol { return symbols[:]; } +/* + Parser gives ranges of expression, but not actually where the commas are placed. +*/ +get_call_commas :: proc(position_context: ^DocumentPositionContext, document: ^Document) { + + if position_context.call == nil { + return; + } + + commas := make([dynamic]int, 0, 10, context.temp_allocator); + + if call, ok := position_context.call.derived.(ast.Call_Expr); ok { + for i := call.open.offset; i < call.close.offset; i += 1 { + + if document.text[i] == ',' { + append(&commas, i); + } + } + } + + position_context.call_commas = commas[:]; +} + /* Figure out what exactly is at the given position and whether it is in a function, struct, etc. */ @@ -2357,6 +2381,10 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi fallback_position_context_signature(document, position, &position_context); } + if hint == .SignatureHelp { + get_call_commas(&position_context, document); + } + return position_context, true; } diff --git a/src/server/signature.odin b/src/server/signature.odin index 883bd2e..64028c8 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -16,7 +16,36 @@ import "core:slice" import "shared:common" import "shared:index" - +SignatureInformationCapabilities :: struct { + parameterInformation: ParameterInformationCapabilities, +} + +SignatureHelpClientCapabilities :: struct { + dynamicRegistration: bool, + signatureInformation: SignatureInformationCapabilities, + contextSupport: bool, +} + +SignatureHelpOptions :: struct { + triggerCharacters: []string, + retriggerCharacters: []string, +} + +SignatureHelp :: struct { + signatures: []SignatureInformation, + activeSignature: int, + activeParameter: int, +} + +SignatureInformation :: struct { + label: string, + documentation: string, + parameters: []ParameterInformation, +} + +ParameterInformation :: struct { + label: string, +} get_signature_information :: proc(document: ^Document, position: common.Position) -> (SignatureHelp, bool) { @@ -40,15 +69,30 @@ get_signature_information :: proc(document: ^Document, position: common.Position get_locals(document.ast, position_context.function, &ast_context, &position_context); } + for comma, i in position_context.call_commas { + if position_context.position > comma { + signature_help.activeParameter = i+1; + } else if position_context.position == comma { + signature_help.activeParameter = i; + } + } + call: index.Symbol; call, ok = resolve_type_expression(&ast_context, position_context.call); signature_information := make([dynamic]SignatureInformation, context.temp_allocator); - if _, ok := call.value.(index.SymbolProcedureValue); ok { + if value, ok := call.value.(index.SymbolProcedureValue); ok { + parameters := make([]ParameterInformation, len(value.arg_types), context.temp_allocator); + + for arg, i in value.arg_types { + parameters[i].label = common.get_ast_node_string(arg, document.ast.src); + } + info := SignatureInformation { label = concatenate_symbols_information(&ast_context, call, false), documentation = call.doc, + parameters = parameters, }; append(&signature_information, info); } else if value, ok := call.value.(index.SymbolAggregateValue); ok { @@ -62,8 +106,6 @@ get_signature_information :: proc(document: ^Document, position: common.Position } signature_help.signatures = signature_information[:]; - signature_help.activeSignature = 0; - signature_help.activeParameter = 0; return signature_help, true; } \ No newline at end of file -- cgit v1.2.3 From f780d92a4083648561dd1f0973c884126c2a5416 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 5 May 2021 23:48:06 +0200 Subject: forgot types file --- src/server/types.odin | 31 ------------------------------- 1 file changed, 31 deletions(-) (limited to 'src/server') diff --git a/src/server/types.odin b/src/server/types.odin index e6ee85d..df78906 100644 --- a/src/server/types.odin +++ b/src/server/types.odin @@ -131,21 +131,6 @@ ParameterInformationCapabilities :: struct { labelOffsetSupport: bool, } -SignatureInformationCapabilities :: struct { - parameterInformation: ParameterInformationCapabilities, -} - -SignatureHelpClientCapabilities :: struct { - dynamicRegistration: bool, - signatureInformation: SignatureInformationCapabilities, - contextSupport: bool, -} - -SignatureHelpOptions :: struct { - triggerCharacters: []string, - retriggerCharacters: []string, -} - ClientCapabilities :: struct { textDocument: TextDocumentClientCapabilities, } @@ -275,22 +260,6 @@ TextDocumentSyncOptions :: struct { save: SaveOptions, } -SignatureHelp :: struct { - signatures: []SignatureInformation, - activeSignature: int, - activeParameter: int, -} - -SignatureInformation :: struct { - label: string, - documentation: string, - parameters: []ParameterInformation, -} - -ParameterInformation :: struct { - label: [2]int, -} - OlsConfig :: struct { collections: [dynamic]OlsConfigCollection, thread_pool_count: int, -- cgit v1.2.3 From 9007c6fa37dff74c8abe2555f9da0420f0a81294 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 6 May 2021 02:31:23 +0200 Subject: prepare with tests for ..any arguments --- src/server/signature.odin | 3 +++ tests/signatures_test.odin | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) (limited to 'src/server') diff --git a/src/server/signature.odin b/src/server/signature.odin index 64028c8..d084507 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -59,6 +59,7 @@ get_signature_information :: proc(document: ^Document, position: common.Position return signature_help, true; } + //TODO(should probably not be an ast.Expr, but ast.Call_Expr) if position_context.call == nil { return signature_help, true; } @@ -83,6 +84,7 @@ get_signature_information :: proc(document: ^Document, position: common.Position signature_information := make([dynamic]SignatureInformation, context.temp_allocator); if value, ok := call.value.(index.SymbolProcedureValue); ok { + parameters := make([]ParameterInformation, len(value.arg_types), context.temp_allocator); for arg, i in value.arg_types { @@ -96,6 +98,7 @@ get_signature_information :: proc(document: ^Document, position: common.Position }; append(&signature_information, info); } else if value, ok := call.value.(index.SymbolAggregateValue); ok { + //function overloaded procedures for symbol in value.symbols { info := SignatureInformation { label = concatenate_symbols_information(&ast_context, symbol, false), diff --git a/tests/signatures_test.odin b/tests/signatures_test.odin index ed4392a..2f5a738 100644 --- a/tests/signatures_test.odin +++ b/tests/signatures_test.odin @@ -64,7 +64,7 @@ ast_proc_signature_argument_move_position :: proc(t: ^testing.T) { } main :: proc() { - cool_function(2,*, 3); + cool_function(2,3*, 3); } `, packages = {}, @@ -73,6 +73,42 @@ ast_proc_signature_argument_move_position :: proc(t: ^testing.T) { test.expect_signature_parameter_position(t, &source, 1); } +@(test) +ast_proc_signature_argument_open_brace_position :: proc(t: ^testing.T) { + + source := test.Source { + main = `package test + cool_function :: proc(a: int, b: int, c: int) { + } + + main :: proc() { + cool_function(2,3, 3* + } + `, + packages = {}, + }; + + test.expect_signature_parameter_position(t, &source, 2); +} + +@(test) +ast_proc_signature_argument_any_ellipsis_position :: proc(t: ^testing.T) { + + source := test.Source { + main = `package test + cool_function :: proc(args: ..any, b := 2) { + } + + main :: proc() { + cool_function(3, 4, 5*) + } + `, + packages = {}, + }; + + test.expect_signature_parameter_position(t, &source, 0); +} + @(test) ast_proc_group_signature_empty_call :: proc(t: ^testing.T) { -- cgit v1.2.3 From 126553d5efff75d87c1a1505a42e922b5d13e9a9 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 6 May 2021 17:08:07 +0200 Subject: started lazy creating signatures for procedures --- src/common/ast.odin | 182 +++++++++++++++++++++++++++++++++++++++++++++ src/index/collector.odin | 11 --- src/index/util.odin | 169 ----------------------------------------- src/server/analysis.odin | 10 +-- src/server/completion.odin | 6 +- src/server/hover.odin | 2 +- src/server/signature.odin | 59 ++++++++++++++- tests/signatures_test.odin | 52 ++++++++++++- 8 files changed, 297 insertions(+), 194 deletions(-) delete mode 100644 src/index/util.odin (limited to 'src/server') diff --git a/src/common/ast.odin b/src/common/ast.odin index 0c9bdcf..dfc603b 100644 --- a/src/common/ast.odin +++ b/src/common/ast.odin @@ -5,6 +5,7 @@ import "core:log" import "core:mem" import "core:fmt" import "core:strings" +import "core:path" keyword_map: map[string]bool = { "int" = true, @@ -622,3 +623,184 @@ node_equal_node :: proc(a, b: ^ast.Node) -> bool { return false; } + +/* + Returns the string representation of a type. This allows us to print the signature without storing it in the indexer as a string(saving memory). +*/ +node_to_string :: proc(node: ^ast.Node) -> string { + + builder := strings.make_builder(context.temp_allocator); + + build_string(node, &builder); + + return strings.to_string(builder); +} + +build_string :: proc{ + build_string_ast_array, + build_string_dynamic_array, + build_string_node, +}; + +build_string_dynamic_array :: proc(array: $A/[]^$T, builder: ^strings.Builder) { + + for elem, i in array { + build_string(elem, builder); + } +} + +build_string_ast_array :: proc(array: $A/[dynamic]^$T, builder: ^strings.Builder) { + + for elem, i in array { + build_string(elem, builder); + } +} + +build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder) { + + using ast; + + if node == nil { + return; + } + + switch n in node.derived { + case Bad_Expr: + case Ident: + if strings.contains(n.name, "/") { + strings.write_string(builder, path.base(n.name, false, context.temp_allocator)); + } else { + strings.write_string(builder, n.name); + } + case Implicit: + strings.write_string(builder, n.tok.text); + case Undef: + case Basic_Lit: + strings.write_string(builder, n.tok.text); + case Basic_Directive: + strings.write_string(builder, n.name); + case Ellipsis: + build_string(n.expr, builder); + case Proc_Lit: + build_string(n.type, builder); + build_string(n.body, builder); + case Comp_Lit: + build_string(n.type, builder); + build_string(n.elems, builder); + case Tag_Expr: + build_string(n.expr, builder); + case Unary_Expr: + build_string(n.expr, builder); + case Binary_Expr: + build_string(n.left, builder); + build_string(n.right, builder); + case Paren_Expr: + strings.write_string(builder, "("); + build_string(n.expr, builder); + strings.write_string(builder, ")"); + case Call_Expr: + build_string(n.expr, builder); + strings.write_string(builder, "("); + build_string(n.args, builder); + strings.write_string(builder, ")"); + case Selector_Expr: + build_string(n.expr, builder); + strings.write_string(builder, "."); + build_string(n.field, builder); + case Index_Expr: + build_string(n.expr, builder); + strings.write_string(builder, "["); + build_string(n.index, builder); + strings.write_string(builder, "]"); + case Deref_Expr: + build_string(n.expr, builder); + case Slice_Expr: + build_string(n.expr, builder); + build_string(n.low, builder); + build_string(n.high, builder); + case Field_Value: + build_string(n.field, builder); + strings.write_string(builder, ": "); + build_string(n.value, builder); + case Type_Cast: + build_string(n.type, builder); + build_string(n.expr, builder); + case Bad_Stmt: + case Bad_Decl: + case Attribute: + build_string(n.elems, builder); + case Field: + build_string(n.names, builder); + if len(n.names) > 0 && n.type != nil { + strings.write_string(builder, ": "); + build_string(n.type, builder); + + if n.default_value != nil && n.type != nil { + strings.write_string(builder, "="); + } + + } else if len(n.names) > 0 && n.default_value != nil { + strings.write_string(builder, " := "); + } + + build_string(n.default_value, builder); + case Field_List: + for field, i in n.list { + build_string(field, builder); + if len(n.list) - 1 != i { + strings.write_string(builder, ","); + } + } + case Typeid_Type: + build_string(n.specialization, builder); + case Helper_Type: + build_string(n.type, builder); + case Distinct_Type: + build_string(n.type, builder); + case Poly_Type: + strings.write_string(builder, "$"); + + build_string(n.type, builder); + + if n.specialization != nil { + strings.write_string(builder, "/"); + build_string(n.specialization, builder); + } + case Proc_Type: + strings.write_string(builder, "proc("); + build_string(n.params, builder); + strings.write_string(builder, ") -> "); + build_string(n.results, builder); + case Pointer_Type: + strings.write_string(builder, "^"); + build_string(n.elem, builder); + case Array_Type: + strings.write_string(builder, "["); + build_string(n.len, builder); + strings.write_string(builder, "]"); + build_string(n.elem, builder); + case Dynamic_Array_Type: + strings.write_string(builder, "[dynamic]"); + build_string(n.elem, builder); + case Struct_Type: + build_string(n.poly_params, builder); + build_string(n.align, builder); + build_string(n.fields, builder); + case Union_Type: + build_string(n.poly_params, builder); + build_string(n.align, builder); + build_string(n.variants, builder); + case Enum_Type: + build_string(n.base_type, builder); + build_string(n.fields, builder); + case Bit_Set_Type: + build_string(n.elem, builder); + build_string(n.underlying, builder); + case Map_Type: + strings.write_string(builder, "map"); + strings.write_string(builder, "["); + build_string(n.key, builder); + strings.write_string(builder, "]"); + build_string(n.value, builder); + } +} diff --git a/src/index/collector.odin b/src/index/collector.odin index 053c27e..952b0cb 100644 --- a/src/index/collector.odin +++ b/src/index/collector.odin @@ -304,17 +304,6 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri case ast.Proc_Type: token = v; token_type = .Function; - - if v.params != nil { - symbol.signature = strings.concatenate({"(", string(file.src[v.params.pos.offset:v.params.end.offset]), ")"}, - collection.allocator); - } - - if v.results != nil { - symbol.returns = strings.concatenate({"(", string(file.src[v.results.pos.offset:v.results.end.offset]), ")"}, - collection.allocator); - } - symbol.value = collect_procedure_fields(collection, cast(^ast.Proc_Type)col_expr, v.params, v.results, package_map); case ast.Proc_Group: token = v; diff --git a/src/index/util.odin b/src/index/util.odin deleted file mode 100644 index e87af2b..0000000 --- a/src/index/util.odin +++ /dev/null @@ -1,169 +0,0 @@ -package index - -import "core:odin/ast" -import "core:strings" -import "core:path" - -/* - Returns the string representation of a type. This allows us to print the signature without storing it in the indexer as a string(saving memory). -*/ -node_to_string :: proc(node: ^ast.Node) -> string { - - builder := strings.make_builder(context.temp_allocator); - - build_string(node, &builder); - - return strings.to_string(builder); -} - -build_string :: proc{ - build_string_ast_array, - build_string_dynamic_array, - build_string_node, -}; - -build_string_dynamic_array :: proc(array: $A/[]^$T, builder: ^strings.Builder) { - - for elem, i in array { - build_string(elem, builder); - } -} - -build_string_ast_array :: proc(array: $A/[dynamic]^$T, builder: ^strings.Builder) { - - for elem, i in array { - build_string(elem, builder); - } -} - -build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder) { - - using ast; - - if node == nil { - return; - } - - switch n in node.derived { - case Bad_Expr: - case Ident: - if strings.contains(n.name, "/") { - strings.write_string(builder, path.base(n.name, false, context.temp_allocator)); - } else { - strings.write_string(builder, n.name); - } - case Implicit: - case Undef: - case Basic_Lit: - //strings.write_string(builder, n.tok.text); - case Ellipsis: - build_string(n.expr, builder); - case Proc_Lit: - build_string(n.type, builder); - build_string(n.body, builder); - case Comp_Lit: - build_string(n.type, builder); - build_string(n.elems, builder); - case Tag_Expr: - build_string(n.expr, builder); - case Unary_Expr: - build_string(n.expr, builder); - case Binary_Expr: - build_string(n.left, builder); - build_string(n.right, builder); - case Paren_Expr: - strings.write_string(builder, "("); - build_string(n.expr, builder); - strings.write_string(builder, ")"); - case Call_Expr: - build_string(n.expr, builder); - strings.write_string(builder, "("); - build_string(n.args, builder); - strings.write_string(builder, ")"); - case Selector_Expr: - build_string(n.expr, builder); - strings.write_string(builder, "."); - build_string(n.field, builder); - case Index_Expr: - build_string(n.expr, builder); - strings.write_string(builder, "["); - build_string(n.index, builder); - strings.write_string(builder, "]"); - case Deref_Expr: - build_string(n.expr, builder); - case Slice_Expr: - build_string(n.expr, builder); - build_string(n.low, builder); - build_string(n.high, builder); - case Field_Value: - build_string(n.field, builder); - strings.write_string(builder, ": "); - build_string(n.value, builder); - case Type_Cast: - build_string(n.type, builder); - build_string(n.expr, builder); - case Bad_Stmt: - case Bad_Decl: - case Attribute: - build_string(n.elems, builder); - case Field: - build_string(n.names, builder); - if len(n.names) > 0 { - strings.write_string(builder, ": "); - } - build_string(n.type, builder); - build_string(n.default_value, builder); - case Field_List: - for field, i in n.list { - build_string(field, builder); - if len(n.list) - 1 != i { - strings.write_string(builder, ","); - } - } - case Typeid_Type: - build_string(n.specialization, builder); - case Helper_Type: - build_string(n.type, builder); - case Distinct_Type: - build_string(n.type, builder); - case Poly_Type: - build_string(n.type, builder); - build_string(n.specialization, builder); - case Proc_Type: - strings.write_string(builder, "proc("); - build_string(n.params, builder); - strings.write_string(builder, ") -> "); - build_string(n.results, builder); - case Pointer_Type: - strings.write_string(builder, "^"); - build_string(n.elem, builder); - case Array_Type: - strings.write_string(builder, "["); - build_string(n.len, builder); - strings.write_string(builder, "]"); - build_string(n.elem, builder); - case Dynamic_Array_Type: - strings.write_string(builder, "[dynamic]"); - build_string(n.elem, builder); - case Struct_Type: - build_string(n.poly_params, builder); - build_string(n.align, builder); - build_string(n.fields, builder); - case Union_Type: - build_string(n.poly_params, builder); - build_string(n.align, builder); - build_string(n.variants, builder); - case Enum_Type: - build_string(n.base_type, builder); - build_string(n.fields, builder); - case Bit_Set_Type: - build_string(n.elem, builder); - build_string(n.underlying, builder); - case Map_Type: - strings.write_string(builder, "map"); - strings.write_string(builder, "["); - build_string(n.key, builder); - strings.write_string(builder, "]"); - build_string(n.value, builder); - } -} diff --git a/src/server/analysis.odin b/src/server/analysis.odin index d7ac8ef..7cd4764 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -1365,21 +1365,15 @@ make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v arg_types := make([dynamic]^ast.Field, context.temp_allocator); if v.results != nil { - for ret in v.results.list { append(&return_types, ret); } - - symbol.returns = strings.concatenate({"(", string(ast_context.file.src[v.results.pos.offset:v.results.end.offset]), ")"}, context.temp_allocator); } if v.params != nil { - for param in v.params.list { append(&arg_types, param); } - - symbol.signature = strings.concatenate({"(", string(ast_context.file.src[v.params.pos.offset:v.params.end.offset]), ")"}, context.temp_allocator); } symbol.value = index.SymbolProcedureValue { @@ -2202,7 +2196,7 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: index. if i, ok := local.derived.(ast.Ident); ok { return get_signature(ast_context, i, symbol, true); } else { - return index.node_to_string(local); + return common.node_to_string(local); } } @@ -2210,7 +2204,7 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: index. if i, ok := global.expr.derived.(ast.Ident); ok { return get_signature(ast_context, i, symbol, true); } else { - return index.node_to_string(global.expr); + return common.node_to_string(global.expr); } } } diff --git a/src/server/completion.odin b/src/server/completion.odin index 66893e0..241548d 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -231,7 +231,7 @@ get_comp_lit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc item := CompletionItem { label = resolved.name, kind = .Field, - detail = fmt.tprintf("%v.%v: %v", comp_symbol.name, resolved.name, index.node_to_string(v.types[i])), + detail = fmt.tprintf("%v.%v: %v", comp_symbol.name, resolved.name, common.node_to_string(v.types[i])), documentation = resolved.doc, }; @@ -364,7 +364,7 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc item := CompletionItem { label = name, kind = .Field, - detail = fmt.tprintf("%v.%v: %v", selector.name, name, index.node_to_string(v.types[i])), + detail = fmt.tprintf("%v.%v: %v", selector.name, name, common.node_to_string(v.types[i])), documentation = symbol.doc, }; @@ -374,7 +374,7 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc item := CompletionItem { label = symbol.name, kind = .Field, - detail = fmt.tprintf("%v: %v", name, index.node_to_string(v.types[i])), + detail = fmt.tprintf("%v: %v", name, common.node_to_string(v.types[i])), documentation = symbol.doc, }; diff --git a/src/server/hover.odin b/src/server/hover.odin index d14cd34..771c867 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -126,7 +126,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok { symbol.name = name; symbol.pkg = selector.name; - symbol.signature = index.node_to_string(v.types[i]); + symbol.signature = common.node_to_string(v.types[i]); hover.contents = write_hover_content(&ast_context, symbol); return hover, true; } diff --git a/src/server/signature.odin b/src/server/signature.odin index d084507..1c2f52f 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -47,6 +47,47 @@ ParameterInformation :: struct { label: string, } +/* + Lazily build the signature and returns from ast.Nodes +*/ +build_symbol_signature :: proc(symbol: ^index.Symbol) { + if value, ok := symbol.value.(index.SymbolProcedureValue); ok { + builder := strings.make_builder(context.temp_allocator); + + strings.write_string(&builder, "("); + for arg, i in value.arg_types { + strings.write_string(&builder, common.node_to_string(arg)); + if i != len(value.arg_types) - 1 { + strings.write_string(&builder, ", "); + } + } + strings.write_string(&builder, ")"); + + symbol.signature = strings.to_string(builder); + } +} + +build_symbol_return :: proc(symbol: ^index.Symbol) { + if value, ok := symbol.value.(index.SymbolProcedureValue); ok { + builder := strings.make_builder(context.temp_allocator); + + if len(value.return_types) == 0 { + return; + } + + strings.write_string(&builder, "("); + for arg, i in value.return_types { + strings.write_string(&builder, common.node_to_string(arg)); + if i != len(value.return_types) - 1 { + strings.write_string(&builder, ", "); + } + } + strings.write_string(&builder, ")"); + symbol.returns = strings.to_string(builder); + } +} + + get_signature_information :: proc(document: ^Document, position: common.Position) -> (SignatureHelp, bool) { signature_help: SignatureHelp; @@ -88,9 +129,19 @@ get_signature_information :: proc(document: ^Document, position: common.Position parameters := make([]ParameterInformation, len(value.arg_types), context.temp_allocator); for arg, i in value.arg_types { - parameters[i].label = common.get_ast_node_string(arg, document.ast.src); + + if arg.type != nil { + if _, is_ellipsis := arg.type.derived.(ast.Ellipsis); is_ellipsis { + signature_help.activeParameter = min(i, signature_help.activeParameter); + } + } + + parameters[i].label = common.node_to_string(arg); } + build_symbol_signature(&call); + build_symbol_return(&call); + info := SignatureInformation { label = concatenate_symbols_information(&ast_context, call, false), documentation = call.doc, @@ -100,6 +151,12 @@ get_signature_information :: proc(document: ^Document, position: common.Position } else if value, ok := call.value.(index.SymbolAggregateValue); ok { //function overloaded procedures for symbol in value.symbols { + + symbol := symbol; + + build_symbol_signature(&call); + build_symbol_return(&call); + info := SignatureInformation { label = concatenate_symbols_information(&ast_context, symbol, false), documentation = symbol.doc, diff --git a/tests/signatures_test.odin b/tests/signatures_test.odin index 2f5a738..bfa605a 100644 --- a/tests/signatures_test.odin +++ b/tests/signatures_test.odin @@ -6,6 +6,19 @@ import "core:fmt" import test "shared:testing" +@(test) +ast_declare_proc_signature :: proc(t: ^testing.T) { + + source := test.Source { + main = `package test + main :: proc(*) + `, + packages = {}, + }; + + test.expect_signature_labels(t, &source, {}); +} + @(test) ast_declare_proc_signature :: proc(t: ^testing.T) { @@ -38,7 +51,25 @@ ast_simple_proc_signature :: proc(t: ^testing.T) { } @(test) -ast_proc_signature_argument_position :: proc(t: ^testing.T) { +ast_default_assignment_proc_signature :: proc(t: ^testing.T) { + + source := test.Source { + main = `package test + cool_function :: proc(a: int, b := context.allocator) { + } + + main :: proc() { + cool_function(*) + } + `, + packages = {}, + }; + + test.expect_signature_labels(t, &source, {"test.cool_function: proc(a: int, b := context.allocator)"}); +} + +@(test) +ast_proc_signature_argument_last_position :: proc(t: ^testing.T) { source := test.Source { main = `package test @@ -55,6 +86,25 @@ ast_proc_signature_argument_position :: proc(t: ^testing.T) { test.expect_signature_parameter_position(t, &source, 1); } +@(test) +ast_proc_signature_argument_first_position :: proc(t: ^testing.T) { + + source := test.Source { + main = `package test + cool_function :: proc(a: int, b: int) { + } + + main :: proc() { + cool_function(2*,) + } + `, + packages = {}, + }; + + test.expect_signature_parameter_position(t, &source, 0); +} + + @(test) ast_proc_signature_argument_move_position :: proc(t: ^testing.T) { -- cgit v1.2.3 From 277b3b260025c9ca6e430e2dad0136436bc5a547 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 6 May 2021 19:51:47 +0200 Subject: signatures and returns are not lazily created when needed --- src/common/ast.odin | 9 ++++++--- src/server/analysis.odin | 8 ++++---- src/server/signature.odin | 4 ++-- tests/signatures_test.odin | 14 ++++++++++++-- 4 files changed, 24 insertions(+), 11 deletions(-) (limited to 'src/server') diff --git a/src/common/ast.odin b/src/common/ast.odin index dfc603b..e6ab8ac 100644 --- a/src/common/ast.odin +++ b/src/common/ast.odin @@ -657,13 +657,13 @@ build_string_ast_array :: proc(array: $A/[dynamic]^$T, builder: ^strings.Builder } build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder) { - + using ast; - + if node == nil { return; } - + switch n in node.derived { case Bad_Expr: case Ident: @@ -741,6 +741,8 @@ build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder) { } else if len(n.names) > 0 && n.default_value != nil { strings.write_string(builder, " := "); + } else { + build_string(n.type, builder); } build_string(n.default_value, builder); @@ -752,6 +754,7 @@ build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder) { } } case Typeid_Type: + strings.write_string(builder, "$"); build_string(n.specialization, builder); case Helper_Type: build_string(n.type, builder); diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 7cd4764..c461621 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -944,8 +944,6 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v), true; case Map_Type: return_symbol, ok = make_symbol_map_from_ast(ast_context, v), true; - case Call_Expr: - return_symbol, ok = resolve_type_expression(ast_context, local); case: return_symbol, ok = resolve_type_expression(ast_context, local); } @@ -1000,8 +998,6 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i return_symbol, ok = make_symbol_array_from_ast(ast_context, v), true; case Dynamic_Array_Type: return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v), true; - case Call_Expr: - return_symbol, ok = resolve_type_expression(ast_context, global.expr); case: return_symbol, ok = resolve_type_expression(ast_context, global.expr); } @@ -2606,6 +2602,10 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo begin_offset := max(0, start); end_offset := max(start, end + 1); + if end_offset - begin_offset <= 1 { + return; + } + str := position_context.file.src[0:end_offset]; p := parser.Parser { diff --git a/src/server/signature.odin b/src/server/signature.odin index 1c2f52f..181adbe 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -154,8 +154,8 @@ get_signature_information :: proc(document: ^Document, position: common.Position symbol := symbol; - build_symbol_signature(&call); - build_symbol_return(&call); + build_symbol_signature(&symbol); + build_symbol_return(&symbol); info := SignatureInformation { label = concatenate_symbols_information(&ast_context, symbol, false), diff --git a/tests/signatures_test.odin b/tests/signatures_test.odin index bfa605a..d127b77 100644 --- a/tests/signatures_test.odin +++ b/tests/signatures_test.odin @@ -20,11 +20,21 @@ ast_declare_proc_signature :: proc(t: ^testing.T) { } @(test) -ast_declare_proc_signature :: proc(t: ^testing.T) { +ast_naked_parens :: proc(t: ^testing.T) { source := test.Source { main = `package test - main :: proc(*) + main :: proc() { + + if node == nil { + return; + } + + (*) + switch n in node.derived { + + } + } `, packages = {}, }; -- cgit v1.2.3 From 1d5897230e1387fd6fe861b7fa59066361d27a11 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 6 May 2021 23:46:59 +0200 Subject: lazily create signatures for functions --- src/index/clone.odin | 6 ++++++ src/index/collector.odin | 10 ---------- src/server/analysis.odin | 4 +--- src/server/completion.odin | 31 +++++++++++++++++++++++++------ src/server/hover.odin | 3 +++ tests/signatures_test.odin | 2 +- 6 files changed, 36 insertions(+), 20 deletions(-) (limited to 'src/server') diff --git a/src/index/clone.odin b/src/index/clone.odin index 3180fbf..17a1002 100644 --- a/src/index/clone.odin +++ b/src/index/clone.odin @@ -111,6 +111,12 @@ clone_node :: proc(node: ^ast.Node, allocator: mem.Allocator, unique_strings: ^m r.tok.text = get_index_unique_string(unique_strings, allocator, n.tok.text); } case Basic_Directive: + r := cast(^Basic_Directive)res; + if unique_strings == nil { + r.name = strings.clone(n.name, allocator); + } else { + r.name = get_index_unique_string(unique_strings, allocator, n.name); + } case Ellipsis: r := cast(^Ellipsis)res; r.expr = clone_type(r.expr, allocator, unique_strings); diff --git a/src/index/collector.odin b/src/index/collector.odin index 952b0cb..f25add8 100644 --- a/src/index/collector.odin +++ b/src/index/collector.odin @@ -288,16 +288,6 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri token = v; token_type = .Function; - if v.type.params != nil { - symbol.signature = strings.concatenate({"(", string(file.src[v.type.params.pos.offset:v.type.params.end.offset]), ")"}, - collection.allocator); - } - - if v.type.results != nil { - symbol.returns = strings.concatenate({"(", string(file.src[v.type.results.pos.offset:v.type.results.end.offset]), ")"}, - collection.allocator); - } - if v.type != nil { symbol.value = collect_procedure_fields(collection, v.type, v.type.params, v.type.results, package_map); } diff --git a/src/server/analysis.odin b/src/server/analysis.odin index c461621..8c68252 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -2039,8 +2039,6 @@ clear_locals :: proc(ast_context: ^AstContext) { clear(&ast_context.usings); } - - concatenate_symbols_information :: proc(ast_context: ^AstContext, symbol: index.Symbol, is_completion: bool) -> string { pkg := path.base(symbol.pkg, false, context.temp_allocator); @@ -2048,7 +2046,7 @@ concatenate_symbols_information :: proc(ast_context: ^AstContext, symbol: index. if symbol.type == .Function { if symbol.returns != "" { - return fmt.tprintf("%v.%v: proc %v -> %v", pkg, symbol.name, symbol.signature, symbol.returns); + return fmt.tprintf("%v.%v: proc%v -> %v", pkg, symbol.name, symbol.signature, symbol.returns); } else { return fmt.tprintf("%v.%v: proc%v", pkg, symbol.name, symbol.signature); } diff --git a/src/server/completion.odin b/src/server/completion.odin index 241548d..86ed681 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -18,6 +18,11 @@ import "core:os" import "shared:common" import "shared:index" +/* + TODOS: Making the signature details is really annoying and not that nice - try to see if this can be refractored. + +*/ + Completion_Type :: enum { Implicit, Selector, @@ -229,9 +234,9 @@ get_comp_lit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } item := CompletionItem { - label = resolved.name, + label = name, kind = .Field, - detail = fmt.tprintf("%v.%v: %v", comp_symbol.name, resolved.name, common.node_to_string(v.types[i])), + detail = fmt.tprintf("%v.%v: %v", comp_symbol.name, name, common.node_to_string(v.types[i])), documentation = resolved.doc, }; @@ -390,11 +395,16 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc for search in searched { + symbol := search.symbol; + + build_symbol_signature(&symbol); + build_symbol_return(&symbol); + item := CompletionItem { - label = search.symbol.name, - kind = cast(CompletionItemKind)search.symbol.type, - detail = fmt.tprintf("%v.%v: %v", path.base(search.symbol.pkg, false, context.temp_allocator), search.symbol.name, search.symbol.signature), - documentation = search.symbol.doc, + label = symbol.name, + kind = cast(CompletionItemKind)symbol.type, + detail = fmt.tprintf("%v.%v: %v", path.base(symbol.pkg, false, context.temp_allocator), symbol.name, symbol.signature), + documentation = symbol.doc, }; append(&items, item); @@ -819,6 +829,9 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D if results, ok := index.fuzzy_search(lookup, pkgs[:]); ok { for r in results { + r := r; + build_symbol_return(&r.symbol); + build_symbol_signature(&r.symbol); if r.symbol.uri != ast_context.uri { append(&combined, CombinedResult {score = r.score, symbol = r.symbol}); } @@ -851,6 +864,9 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D symbol.name = ident.name; symbol.signature = get_signature(ast_context, ident^, symbol); + build_symbol_return(&symbol); + build_symbol_signature(&symbol); + if score, ok := common.fuzzy_match(matcher, symbol.name); ok { append(&combined, CombinedResult {score = score * 1.1, symbol = symbol, variable = ident}); } @@ -874,6 +890,9 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D symbol.name = ident.name; symbol.signature = get_signature(ast_context, ident^, symbol); + build_symbol_return(&symbol); + build_symbol_signature(&symbol); + if score, ok := common.fuzzy_match(matcher, symbol.name); ok { append(&combined, CombinedResult {score = score * 1.1, symbol = symbol, variable = ident}); } diff --git a/src/server/hover.odin b/src/server/hover.odin index 771c867..adb141d 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -30,6 +30,9 @@ write_hover_content :: proc(ast_context: ^AstContext, symbol: index.Symbol) -> M } } + build_symbol_return(&symbol); + build_symbol_signature(&symbol); + cat := concatenate_symbols_information(ast_context, symbol, false); if cat != "" { diff --git a/tests/signatures_test.odin b/tests/signatures_test.odin index c915f1d..56ece93 100644 --- a/tests/signatures_test.odin +++ b/tests/signatures_test.odin @@ -213,7 +213,7 @@ ast_proc_signature_generic :: proc(t: ^testing.T) { packages = {}, }; - test.expect_signature_labels(t, &source, {"test.clone_array: proc (array: $A/[]^$T, allocator: mem.Allocator, unique_strings: ^map[string]string) -> (A)"}); + test.expect_signature_labels(t, &source, {"test.clone_array: proc(array: $A/[]^$T, allocator: mem.Allocator, unique_strings: ^map[string]string) -> (A)"}); } @(test) -- cgit v1.2.3 From b3548adc1efcb143767e63d370efed1a60f724c5 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Fri, 7 May 2021 17:02:52 +0200 Subject: make sure complex calls is handled correctly with comma positions --- src/server/analysis.odin | 20 ++++++++++++++++++-- src/server/signature.odin | 34 +++++++++++++++++++++++++++------- tests/signatures_test.odin | 21 ++++++++++++++++++++- 3 files changed, 65 insertions(+), 10 deletions(-) (limited to 'src/server') diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 8c68252..999c7c1 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -2284,11 +2284,27 @@ get_call_commas :: proc(position_context: ^DocumentPositionContext, document: ^D commas := make([dynamic]int, 0, 10, context.temp_allocator); + paren_count := 0; + bracket_count := 0; + brace_count := 0; + if call, ok := position_context.call.derived.(ast.Call_Expr); ok { + if document.text[call.open.offset] == '(' { + paren_count -= 1; + } for i := call.open.offset; i < call.close.offset; i += 1 { - if document.text[i] == ',' { - append(&commas, i); + switch document.text[i] { + case '[': paren_count += 1; + case ']': paren_count -= 1; + case '{': brace_count += 1; + case '}': brace_count -= 1; + case '(': paren_count += 1; + case ')': paren_count -= 1; + case ',': + if paren_count == 0 && brace_count == 0 && bracket_count == 0 { + append(&commas, i); + } } } } diff --git a/src/server/signature.odin b/src/server/signature.odin index 181adbe..fb3f8e6 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -45,6 +45,7 @@ SignatureInformation :: struct { ParameterInformation :: struct { label: string, + activeParameter: int, } /* @@ -154,14 +155,33 @@ get_signature_information :: proc(document: ^Document, position: common.Position symbol := symbol; - build_symbol_signature(&symbol); - build_symbol_return(&symbol); + if value, ok := symbol.value.(index.SymbolProcedureValue); ok { + + parameters := make([]ParameterInformation, len(value.arg_types), context.temp_allocator); + + for arg, i in value.arg_types { + + if arg.type != nil { + if _, is_ellipsis := arg.type.derived.(ast.Ellipsis); is_ellipsis { + signature_help.activeParameter = min(i, signature_help.activeParameter); + } + } + + parameters[i].label = common.node_to_string(arg); + parameters[i].activeParameter = i; + } + + build_symbol_signature(&symbol); + build_symbol_return(&symbol); - info := SignatureInformation { - label = concatenate_symbols_information(&ast_context, symbol, false), - documentation = symbol.doc, - }; - append(&signature_information, info); + info := SignatureInformation { + label = concatenate_symbols_information(&ast_context, symbol, false), + documentation = symbol.doc, + parameters = parameters, + }; + + append(&signature_information, info); + } } } diff --git a/tests/signatures_test.odin b/tests/signatures_test.odin index 56ece93..82c6223 100644 --- a/tests/signatures_test.odin +++ b/tests/signatures_test.odin @@ -133,6 +133,24 @@ ast_proc_signature_argument_move_position :: proc(t: ^testing.T) { test.expect_signature_parameter_position(t, &source, 1); } +@(test) +ast_proc_signature_argument_complex :: proc(t: ^testing.T) { + + source := test.Source { + main = `package test + cool_function :: proc(a: int, b: int, c: int) { + } + + main :: proc() { + cool_function(a(2,5,b(3,sdf[2],{})), *); + } + `, + packages = {}, + }; + + test.expect_signature_parameter_position(t, &source, 1); +} + @(test) ast_proc_signature_argument_open_brace_position :: proc(t: ^testing.T) { @@ -343,4 +361,5 @@ index_simple_signature :: proc(t: ^testing.T) { }; test.expect_signature_labels(t, &source, {"my_package.my_function: proc(a: int, b := context.allocator)"}); -} \ No newline at end of file +} + -- cgit v1.2.3 From 6443fc0a31f2949993d7cd7806391fd5d7ee97c3 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Sat, 8 May 2021 14:12:16 +0200 Subject: more work on generics and overloading --- src/server/analysis.odin | 30 ++++++++++++++++++++---------- tests/completions_test.odin | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 10 deletions(-) (limited to 'src/server') diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 999c7c1..d928f7c 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -336,23 +336,28 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast using ast; if params == nil { - return index.Symbol {}, false; + return {}, false; } if results == nil { - return index.Symbol {}, false; + return {}, false; } if ast_context.call == nil { - return index.Symbol {}, false; + return {}, false; } call_expr := ast_context.call; - poly_map := make(map[string]^Expr, 0, context.temp_allocator); - i := 0; + poly_map := make(map[string]^Expr, 0, context.temp_allocator); + i := 0; + count_required_params := 0; for param in params { + if param.default_value != nil { + count_required_params += 1; + } + for name in param.names { if len(call_expr.args) <= i { @@ -373,6 +378,10 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast } } + if count_required_params > len(call_expr.args) || count_required_params == 0 || len(call_expr.args) == 0 { + return {}, false; + } + function_name := ""; function_range: common.Range; @@ -402,16 +411,17 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast if ident, ok := result.type.derived.(Ident); ok { field := cast(^Field)index.clone_node(result, context.temp_allocator, nil); - - if m := &poly_map[ident.name]; m != nil { + if m, ok := poly_map[ident.name]; ok { field.type = poly_map[ident.name]; append(&return_types, field); - } else { - return index.Symbol {}, false; - } + } } } + if len(poly_map) != len(return_types) { + return {}, false; + } + symbol.value = index.SymbolProcedureValue { return_types = return_types[:], arg_types = params, diff --git a/tests/completions_test.odin b/tests/completions_test.odin index 48000a0..9cd5a6f 100644 --- a/tests/completions_test.odin +++ b/tests/completions_test.odin @@ -304,6 +304,38 @@ index_package_completion :: proc(t: ^testing.T) { test.expect_completion_details(t, &source, ".", {"my_package.My_Struct: struct"}); } +@(test) +ast_generic_make_completion :: proc(t: ^testing.T) { + + source := test.Source { + main = `package test + + make :: proc{ + make_dynamic_array, + make_dynamic_array_len, + }; + + make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { + } + + make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { + } + + My_Struct :: struct { + my_int: int, + } + + main :: proc() { + my_array := make([dynamic]My_Struct, context.allocator); + my_array[2].* + } + `, + packages = {}, + }; + + test.expect_completion_details(t, &source, ".", {"My_Struct.my_int: int"}); +} + /* SymbolUntypedValue :: struct { -- cgit v1.2.3 From 9c2090e0395d68bb9a89cfd3f69f863375a27f54 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Sun, 9 May 2021 18:38:44 +0200 Subject: make now works again --- src/common/ast.odin | 15 +++------ src/index/indexer.odin | 1 - src/server/analysis.odin | 74 ++++++++++++++++++++++++++++++++++----------- src/server/completion.odin | 4 +-- src/server/signature.odin | 2 +- src/testing/testing.odin | 3 +- tests/completions_test.odin | 47 ++++++++++++++++++++++++++-- 7 files changed, 110 insertions(+), 36 deletions(-) (limited to 'src/server') diff --git a/src/common/ast.odin b/src/common/ast.odin index e6ab8ac..839c7f5 100644 --- a/src/common/ast.odin +++ b/src/common/ast.odin @@ -492,12 +492,6 @@ node_equal_node :: proc(a, b: ^ast.Node) -> bool { } case Poly_Type: return true; - //return node_equal(n.sp) - //if n, ok := a.derived.(Poly_Type); ok { - // ret := node_equal(n.type, m.type); - // ret &= node_equal(n.specialization, m.specialization); - // return ret; - //} case Ellipsis: if n, ok := a.derived.(Ellipsis); ok { return node_equal(n.expr, m.expr); @@ -549,8 +543,10 @@ node_equal_node :: proc(a, b: ^ast.Node) -> bool { } case Array_Type: if n, ok := a.derived.(Array_Type); ok { - ret := node_equal(n.len, m.len); - ret &= node_equal(n.elem, m.elem); + ret := node_equal(n.elem, m.elem); + if n.len != nil && m.len != nil { + ret &= node_equal(n.len, m.len); + } return ret; } case Dynamic_Array_Type: @@ -614,9 +610,6 @@ node_equal_node :: proc(a, b: ^ast.Node) -> bool { } case Typeid_Type: return true; - //if n, ok := a.derived.(Typeid_Type); ok { - // return node_equal(n.specialization, m.specialization); - //} case: log.warn("Unhandled poly node kind: %T", m); } diff --git a/src/index/indexer.odin b/src/index/indexer.odin index 2020992..ce031f1 100644 --- a/src/index/indexer.odin +++ b/src/index/indexer.odin @@ -59,7 +59,6 @@ lookup :: proc(name: string, pkg: string, loc := #caller_location) -> (Symbol, b } for built in indexer.built_in_packages { - if symbol, ok := memory_index_lookup(&indexer.static_index, name, built); ok { log.infof("lookup name: %v pkg: %v, symbol %v location %v", name, pkg, symbol, loc); return symbol, true; diff --git a/src/server/analysis.odin b/src/server/analysis.odin index d928f7c..c90e2fe 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -178,7 +178,7 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s case Implicit: case Undef: case Basic_Lit: - case Poly_Type: + case Poly_Type: if expr := get_poly_node_to_expr(call_node); expr != nil { poly_map[m.type.name] = expr; } @@ -354,7 +354,7 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast for param in params { - if param.default_value != nil { + if param.default_value == nil { count_required_params += 1; } @@ -372,6 +372,12 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast continue; } + if type_id, ok := param.type.derived.(Typeid_Type); ok { + if !common.node_equal(call_expr.args[i], type_id.specialization) { + return {}, false; + } + } + resolve_poly_spec_node(ast_context, call_expr.args[i], param.type, &poly_map); i += 1; @@ -392,7 +398,7 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast function_name = selector.field.name; function_range = common.get_token_range(selector, ast_context.file.src); } else { - return index.Symbol {}, false; + return {}, false; } symbol := index.Symbol { @@ -402,6 +408,7 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast }; return_types := make([dynamic]^ast.Field, context.temp_allocator); + argument_types := make([dynamic]^ast.Field, context.temp_allocator); for result in results { @@ -410,21 +417,40 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast } if ident, ok := result.type.derived.(Ident); ok { - field := cast(^Field)index.clone_node(result, context.temp_allocator, nil); if m, ok := poly_map[ident.name]; ok { - field.type = poly_map[ident.name]; + field := cast(^Field)index.clone_node(result, context.temp_allocator, nil); + field.type = m; append(&return_types, field); - } + } else { + append(&return_types, result); + } + } else { + append(&return_types, result); } } - if len(poly_map) != len(return_types) { - return {}, false; + for param in params { + + if len(param.names) == 0 { + continue; + } + + //check the name for poly + if poly_type, ok := param.names[0].derived.(ast.Poly_Type); ok && param.type != nil { + if m, ok := poly_map[poly_type.type.name]; ok { + field := cast(^Field)index.clone_node(param, context.temp_allocator, nil); + field.type = m; + append(&argument_types, field); + } + } else { + append(&argument_types, param); + } + } symbol.value = index.SymbolProcedureValue { return_types = return_types[:], - arg_types = params, + arg_types = argument_types[:], }; return symbol, true; @@ -449,8 +475,7 @@ resolve_generic_function_ast :: proc(ast_context: ^AstContext, proc_lit: ast.Pro return resolve_generic_function_symbol(ast_context, proc_lit.type.params.list, proc_lit.type.results.list); } -is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: index.Symbol) -> bool -{ +is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: index.Symbol) -> bool { //relying on the fact that a is the call argument to avoid checking both sides for untyped. if untyped, ok := a.value.(index.SymbolUntypedValue); ok { if basic, ok := b.value.(index.SymbolBasicValue); ok { @@ -627,6 +652,18 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou if procedure, ok := f.value.(index.SymbolProcedureValue); ok { + count_required_params := 0; + + for arg in procedure.arg_types { + if arg.default_value == nil { + count_required_params += 1; + } + } + + if count_required_params > len(call_expr.args) { + break next_fn; + } + if len(procedure.arg_types) < len(call_expr.args) { continue; } @@ -643,17 +680,21 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou call_symbol, ok = resolve_type_expression(ast_context, arg); - if !ok { + if !ok { break next_fn; } - arg_symbol, ok = resolve_type_expression(ast_context, procedure.arg_types[i].type); + if procedure.arg_types[i].type != nil { + arg_symbol, ok = resolve_type_expression(ast_context, procedure.arg_types[i].type); + } else { + arg_symbol, ok = resolve_type_expression(ast_context, procedure.arg_types[i].default_value); + } - if !ok { + if !ok { break next_fn; } - - if !is_symbol_same_typed(ast_context, call_symbol, arg_symbol) { + + if !is_symbol_same_typed(ast_context, call_symbol, arg_symbol) { break next_fn; } @@ -1019,7 +1060,6 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i return return_symbol, ok; } else if node.name == "context" { - //if there are more of these variables that hard builtin, move them to the indexer return index.lookup("Context", ast_context.current_package); } else if v, ok := common.keyword_map[node.name]; ok { //keywords diff --git a/src/server/completion.odin b/src/server/completion.odin index 86ed681..3fc4917 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -161,10 +161,10 @@ field_exists_in_comp_lit :: proc(comp_lit: ^ast.Comp_Lit, name: string) -> bool return false; } -get_attribute_completion :: proc(ast_context: ^AstContext, postition_context: ^DocumentPositionContext, list: ^CompletionList) { +get_attribute_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { } -get_directive_completion :: proc(ast_context: ^AstContext, postition_context: ^DocumentPositionContext, list: ^CompletionList) { +get_directive_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { list.isIncomplete = false; diff --git a/src/server/signature.odin b/src/server/signature.odin index fb3f8e6..c1cdbe3 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -128,7 +128,7 @@ get_signature_information :: proc(document: ^Document, position: common.Position if value, ok := call.value.(index.SymbolProcedureValue); ok { parameters := make([]ParameterInformation, len(value.arg_types), context.temp_allocator); - + for arg, i in value.arg_types { if arg.type != nil { diff --git a/src/testing/testing.odin b/src/testing/testing.odin index 7b30e93..ebaf4fc 100644 --- a/src/testing/testing.odin +++ b/src/testing/testing.odin @@ -73,6 +73,7 @@ setup :: proc(src: ^Source) { There is a lot code here that is used in the real code, then i'd like to see. */ + index.indexer.static_index = index.make_memory_index(index.make_symbol_collection(context.allocator, &common.config)); index.indexer.dynamic_index = index.make_memory_index(index.make_symbol_collection(context.allocator, &common.config)); for src_pkg in src.packages { @@ -108,7 +109,7 @@ setup :: proc(src: ^Source) { return; } - if ret := index.collect_symbols(&index.indexer.dynamic_index.collection, file, uri.uri); ret != .None { + if ret := index.collect_symbols(&index.indexer.static_index.collection, file, uri.uri); ret != .None { return; } } diff --git a/tests/completions_test.odin b/tests/completions_test.odin index 9cd5a6f..47f9e5a 100644 --- a/tests/completions_test.odin +++ b/tests/completions_test.odin @@ -304,6 +304,38 @@ index_package_completion :: proc(t: ^testing.T) { test.expect_completion_details(t, &source, ".", {"my_package.My_Struct: struct"}); } +@(test) +ast_generic_make_slice :: proc(t: ^testing.T) { + + source := test.Source { + main = `package test + Allocator :: struct { + + } + Context :: struct { + allocator: Allocator, + } + make_slice :: proc($T: typeid/[]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { + } + + My_Struct :: struct { + my_int: int, + } + + main :: proc() { + my_slice := make_slice([]My_Struct, 23); + my_slic* + } + `, + packages = {}, + }; + + test.expect_completion_details(t, &source, "", {"test.my_slice: []My_Struct"}); +} + +/* + Figure out whether i want to introduce the runtime to the tests + @(test) ast_generic_make_completion :: proc(t: ^testing.T) { @@ -313,20 +345,28 @@ ast_generic_make_completion :: proc(t: ^testing.T) { make :: proc{ make_dynamic_array, make_dynamic_array_len, + make_dynamic_array_len_cap, + make_map, + make_slice, }; - + make_slice :: proc($T: typeid/[]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { + } + make_map :: proc($T: typeid/map[$K]$E, auto_cast cap: int = DEFAULT_RESERVE_CAPACITY, allocator := context.allocator, loc := #caller_location) -> T { + } make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { } - make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { } + make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, auto_cast len: int, auto_cast cap: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { + } My_Struct :: struct { my_int: int, } main :: proc() { - my_array := make([dynamic]My_Struct, context.allocator); + allocator: Allocator; + my_array := make([dynamic]My_Struct, 343, allocator); my_array[2].* } `, @@ -335,6 +375,7 @@ ast_generic_make_completion :: proc(t: ^testing.T) { test.expect_completion_details(t, &source, ".", {"My_Struct.my_int: int"}); } +*/ /* -- cgit v1.2.3