diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2021-05-09 19:37:24 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-09 19:37:24 +0200 |
| commit | 84d844bd4ad9320d00ea5f025a9ca44bf74c6ee7 (patch) | |
| tree | 87c7e9d164e1da62c5cf4a3dff0cc9dea3f6e1d1 /src/server | |
| parent | 87d4464e91f8b5784ba20e6ef78c818092afb9a9 (diff) | |
| parent | 9c2090e0395d68bb9a89cfd3f69f863375a27f54 (diff) | |
Merge pull request #39 from DanielGavin/procedure-arguments
begun argument underlining
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/analysis.odin | 158 | ||||
| -rw-r--r-- | src/server/completion.odin | 39 | ||||
| -rw-r--r-- | src/server/hover.odin | 5 | ||||
| -rw-r--r-- | src/server/signature.odin | 138 | ||||
| -rw-r--r-- | src/server/types.odin | 31 |
5 files changed, 285 insertions, 86 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin index cd505ce..c90e2fe 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 { @@ -177,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; } @@ -335,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 { @@ -366,12 +372,22 @@ 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; } } + 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; @@ -382,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 { @@ -392,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 { @@ -400,20 +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 := &poly_map[ident.name]; m != nil { - field.type = poly_map[ident.name]; + if m, ok := poly_map[ident.name]; ok { + field := cast(^Field)index.clone_node(result, context.temp_allocator, nil); + field.type = m; append(&return_types, field); } else { - return index.Symbol {}, false; + append(&return_types, result); } + } else { + append(&return_types, result); } } + 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; @@ -438,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 { @@ -616,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; } @@ -632,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; } @@ -943,8 +995,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); } @@ -999,8 +1049,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); } @@ -1012,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 @@ -1364,21 +1411,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 { @@ -2048,8 +2089,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); @@ -2057,7 +2096,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); } @@ -2201,7 +2240,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); } } @@ -2209,7 +2248,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); } } } @@ -2285,6 +2324,45 @@ get_document_symbols :: proc(document: ^Document) -> []DocumentSymbol { } /* + 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); + + 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 { + + 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); + } + } + } + } + + position_context.call_commas = commas[:]; +} + +/* 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) { @@ -2357,6 +2435,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; } @@ -2584,6 +2666,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/completion.odin b/src/server/completion.odin index 66893e0..3fc4917 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, @@ -156,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; @@ -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, index.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, }; @@ -364,7 +369,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 +379,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, }; @@ -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 d14cd34..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 != "" { @@ -126,7 +129,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 883bd2e..c1cdbe3 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -16,6 +16,77 @@ 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, + activeParameter: int, +} + +/* + 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) { @@ -30,6 +101,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; } @@ -40,30 +112,80 @@ 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 { + + 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, + parameters = parameters, }; 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), - documentation = symbol.doc, - }; - append(&signature_information, info); + + symbol := 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, + parameters = parameters, + }; + + append(&signature_information, info); + } } } signature_help.signatures = signature_information[:]; - signature_help.activeSignature = 0; - signature_help.activeParameter = 0; return signature_help, true; }
\ No newline at end of file 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, |