diff options
| author | Daniel Gavin <danielgavin5@hotmail.com> | 2022-01-17 12:54:17 +0100 |
|---|---|---|
| committer | Daniel Gavin <danielgavin5@hotmail.com> | 2022-01-17 12:54:17 +0100 |
| commit | 64e56f1610a568331b19ab713ea033030f0eac2d (patch) | |
| tree | 45674a85f8c4f29cc8c83d6af9715687b963a9fe /src/server | |
| parent | 273de152aee21ed4855bf4b6fdbd08d494995863 (diff) | |
work on the new semantic tokens.
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/requests.odin | 12 | ||||
| -rw-r--r-- | src/server/semantic_tokens.odin | 374 |
2 files changed, 364 insertions, 22 deletions
diff --git a/src/server/requests.odin b/src/server/requests.odin index 8d965c7..c4bd7b9 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -589,7 +589,6 @@ request_initialized :: proc (task: ^common.Task) { } request_shutdown :: proc (task: ^common.Task) { - info := get_request_info(task); using info; @@ -607,7 +606,6 @@ request_shutdown :: proc (task: ^common.Task) { } request_definition :: proc (task: ^common.Task) { - info := get_request_info(task); using info; @@ -648,7 +646,6 @@ request_definition :: proc (task: ^common.Task) { } request_completion :: proc (task: ^common.Task) { - info := get_request_info(task); using info; @@ -692,7 +689,6 @@ request_completion :: proc (task: ^common.Task) { } request_signature_help :: proc (task: ^common.Task) { - info := get_request_info(task); using info; @@ -733,7 +729,6 @@ request_signature_help :: proc (task: ^common.Task) { } request_format_document :: proc (task: ^common.Task) { - info := get_request_info(task); using info; @@ -786,7 +781,6 @@ notification_exit :: proc (task: ^common.Task) { } notification_did_open :: proc (task: ^common.Task) { - info := get_request_info(task); using info; @@ -818,7 +812,6 @@ notification_did_open :: proc (task: ^common.Task) { } notification_did_change :: proc (task: ^common.Task) { - info := get_request_info(task); using info; @@ -846,7 +839,6 @@ notification_did_change :: proc (task: ^common.Task) { } notification_did_close :: proc (task: ^common.Task) { - info := get_request_info(task); using info; @@ -952,7 +944,6 @@ notification_did_save :: proc (task: ^common.Task) { } request_semantic_token_full :: proc (task: ^common.Task) { - info := get_request_info(task); using info; @@ -1001,7 +992,6 @@ request_semantic_token_full :: proc (task: ^common.Task) { } request_semantic_token_range :: proc (task: ^common.Task) { - info := get_request_info(task); using info; @@ -1040,7 +1030,6 @@ request_semantic_token_range :: proc (task: ^common.Task) { } request_document_symbols :: proc (task: ^common.Task) { - info := get_request_info(task); using info; @@ -1075,7 +1064,6 @@ request_document_symbols :: proc (task: ^common.Task) { } request_hover :: proc (task: ^common.Task) { - info := get_request_info(task); using info; diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin index f7d01dd..095bb91 100644 --- a/src/server/semantic_tokens.odin +++ b/src/server/semantic_tokens.odin @@ -81,7 +81,7 @@ SemanticTokenBuilder :: struct { make_token_builder :: proc(allocator := context.temp_allocator) -> SemanticTokenBuilder { return { - tokens = make([dynamic]u32, context.temp_allocator), + tokens = make([dynamic]u32, 1000, context.temp_allocator), }; } @@ -100,11 +100,15 @@ get_semantic_tokens :: proc(document: ^common.Document, range: common.Range) -> write_semantic_token(&builder, document.ast.pkg_token, document.ast.src, .Keyword, .None); } - resolve_entire_file(document, context.temp_allocator); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); + + //resolve_entire_file(document, &ast_context, context.temp_allocator); + + ast_context.current_package = ast_context.document_package; for decl in document.ast.decls { if range.start.line <= decl.pos.line && decl.end.line <= range.end.line { - + visit(decl, &builder, &ast_context); } } @@ -113,27 +117,377 @@ get_semantic_tokens :: proc(document: ^common.Document, range: common.Range) -> write_semantic_node :: proc(builder: ^SemanticTokenBuilder, node: ^ast.Node, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { position := common.get_relative_token_position(node.pos.offset, transmute([]u8)src, builder.current_start); - name := common.get_ast_node_string(node, src); - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, 0); - builder.current_start = node.pos.offset; } write_semantic_token :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { position := common.get_relative_token_position(token.pos.offset, transmute([]u8)src, builder.current_start); - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(token.text), cast(u32)type, 0); - builder.current_start = token.pos.offset; } write_semantic_string :: proc(builder: ^SemanticTokenBuilder, pos: tokenizer.Pos, name: string, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { position := common.get_relative_token_position(pos.offset, transmute([]u8)src, builder.current_start); - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, 0); - builder.current_start = pos.offset; } +visit :: proc { + visit_node, + visit_dynamic_array, + visit_array, + visit_stmt, +}; + +visit_array :: proc(array: $A/[]^$T, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { + for elem, i in array { + visit(elem, builder, ast_context); + } +} + +visit_dynamic_array :: proc(array: $A/[dynamic]^$T, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { + for elem, i in array { + visit(elem, builder, ast_context); + } +} + +visit_stmt :: proc(node: ^ast.Stmt, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { + visit_node(node, builder, ast_context); +} + +visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { + using ast; + + if node == nil { + return; + } + + switch n in node.derived { + case Ellipsis: + write_semantic_string(builder, node.pos, "..", ast_context.file.src, .Operator, .None); + visit(n.expr, builder, ast_context); + case Ident: + if true { + write_semantic_node(builder, node, ast_context.file.src, .Variable, .None); + return; + } + if symbol, ok := analysis.lookup_symbol_cache(ast_context, n); ok { + if symbol.type == .Variable { + write_semantic_node(builder, node, ast_context.file.src, .Variable, .None); + } + + #partial switch v in symbol.value { + case index.SymbolPackageValue: + write_semantic_node(builder, node, ast_context.file.src, .Namespace, .None); + case index.SymbolStructValue: + write_semantic_node(builder, node, ast_context.file.src, .Struct, .None); + case index.SymbolEnumValue: + write_semantic_node(builder, node, ast_context.file.src, .Enum, .None); + case index.SymbolUnionValue: + write_semantic_node(builder, node, ast_context.file.src, .Enum, .None); + case index.SymbolProcedureValue: + write_semantic_node(builder, node, ast_context.file.src, .Function, .None); + case index.SymbolProcedureGroupValue: + write_semantic_node(builder, node, ast_context.file.src, .Function, .None); + } + } + case Selector_Expr: + visit_selector(cast(^Selector_Expr)node, builder, ast_context); + case Pointer_Type: + write_semantic_string(builder, node.pos, "^", ast_context.file.src, .Operator, .None); + visit(n.elem, builder, ast_context); + case Value_Decl: + visit_value_decl(n, builder, ast_context); + case Block_Stmt: + visit(n.stmts, builder, ast_context); + case Expr_Stmt: + visit(n.expr, builder, ast_context); + case Range_Stmt: + write_semantic_string(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None); + + for val in n.vals { + if ident, ok := val.derived.(Ident); ok { + write_semantic_node(builder, val, ast_context.file.src, .Variable, .None); + } + } + + write_semantic_string(builder, n.in_pos, "in", ast_context.file.src, .Keyword, .None); + visit(n.expr, builder, ast_context); + visit(n.body, builder, ast_context); + case If_Stmt: + write_semantic_string(builder, n.if_pos, "if", ast_context.file.src, .Keyword, .None); + visit(n.init, builder, ast_context); + visit(n.cond, builder, ast_context); + visit(n.body, builder, ast_context); + if n.else_stmt != nil { + write_semantic_string(builder, n.else_pos, "else", ast_context.file.src, .Keyword, .None); + visit(n.else_stmt, builder, ast_context); + } + case For_Stmt: + write_semantic_string(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None); + visit(n.init, builder, ast_context); + visit(n.cond, builder, ast_context); + visit(n.post, builder, ast_context); + visit(n.body, builder, ast_context); + case Switch_Stmt: + write_semantic_string(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None); + visit(n.init, builder, ast_context); + visit(n.cond, builder, ast_context); + visit(n.body, builder, ast_context); + case Type_Switch_Stmt: + write_semantic_string(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None); + visit(n.tag, builder, ast_context); + visit(n.expr, builder, ast_context); + visit(n.body, builder, ast_context); + case Assign_Stmt: + for l in n.lhs { + if ident, ok := l.derived.(Ident); ok { + write_semantic_node(builder, l, ast_context.file.src, .Variable, .None); + } else { + visit(l, builder, ast_context); + } + } + + visit_token_op(builder, n.op, ast_context.file.src); + visit(n.rhs, builder, ast_context); + case Case_Clause: + write_semantic_string(builder, n.case_pos, "case", ast_context.file.src, .Keyword, .None); + visit(n.list, builder, ast_context); + visit(n.body, builder, ast_context); + case Call_Expr: + if ident, ok := n.expr.derived.(Ident); ok { + write_semantic_node(builder, n.expr, ast_context.file.src, .Function, .None); + } else { + visit(n.expr, builder, ast_context); + } + visit(n.args, builder, ast_context); + case Implicit_Selector_Expr: + write_semantic_node(builder, n.field, ast_context.file.src, .Enum, .None); + case Array_Type: + visit(n.elem, builder, ast_context); + case Binary_Expr: + visit(n.left, builder, ast_context); + visit_token_op(builder, n.op, ast_context.file.src); + visit(n.right, builder, ast_context); + case Comp_Lit: + visit(n.type, builder, ast_context); + visit(n.elems, builder, ast_context); + case Struct_Type: + write_semantic_string(builder, n.pos, "struct", ast_context.file.src, .Keyword, .None); + visit_struct_fields(n, builder, ast_context); + case Type_Assertion: + visit(n.expr, builder, ast_context); + visit(n.type, builder, ast_context); + case Type_Cast: + write_semantic_string(builder, n.pos, "cast", ast_context.file.src, .Keyword, .None); + visit(n.type, builder, ast_context); + visit(n.expr, builder, ast_context); + case Paren_Expr: + visit(n.expr, builder, ast_context); + case Deref_Expr: + visit(n.expr, builder, ast_context); + case Return_Stmt: + write_semantic_string(builder, n.pos, "return", ast_context.file.src, .Keyword, .None); + visit(n.results, builder, ast_context); + case Dynamic_Array_Type: + write_semantic_string(builder, n.dynamic_pos, "dynamic", ast_context.file.src, .Keyword, .None); + visit(n.elem, builder, ast_context); + case Field_Value: + if ident, ok := n.field.derived.(Ident); ok { + write_semantic_node(builder, n.field, ast_context.file.src, .Property, .None); + } + + visit(n.value, builder, ast_context); + case Index_Expr: + visit(n.expr, builder, ast_context); + visit(n.index, builder, ast_context); + case Basic_Lit: + visit_basic_lit(n, builder, ast_context); + case Unary_Expr: + visit(n.expr, builder, ast_context); + case Implicit: + case Slice_Expr: + visit(n.expr, builder, ast_context); + case Using_Stmt: + write_semantic_string(builder, n.pos, "using", ast_context.file.src, .Keyword, .None); + visit(n.list, builder, ast_context); + case Map_Type: + write_semantic_string(builder, n.tok_pos, "map", ast_context.file.src, .Keyword, .None); + visit(n.key, builder, ast_context); + visit(n.value, builder, ast_context); + case Defer_Stmt: + write_semantic_string(builder, n.pos, "defer", ast_context.file.src, .Keyword, .None); + visit(n.stmt, builder, ast_context); + case Import_Decl: + write_semantic_token(builder, n.import_tok, ast_context.file.src, .Keyword, .None); + + if n.name.text != "" { + write_semantic_token(builder, n.name, ast_context.file.src, .Namespace, .None); + } + + write_semantic_token(builder, n.relpath, ast_context.file.src, .String, .None); + case: + log.warnf("unhandled write node %v", n); + } +} + +visit_basic_lit :: proc(basic_lit: ast.Basic_Lit, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { + using analysis; + + if symbol, ok := resolve_basic_lit(ast_context, basic_lit); ok { + + if generic, ok := symbol.value.(index.SymbolGenericValue); ok { + + ident := generic.expr.derived.(ast.Ident); + + if ident.name == "string" { + write_semantic_node(builder, generic.expr, ast_context.file.src, .String, .None); + } else if ident.name == "int" { + write_semantic_node(builder, generic.expr, ast_context.file.src, .Number, .None); + } else { + } + } + } +} + +visit_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { + using ast; + + if value_decl.type != nil { + for name in value_decl.names { + write_semantic_node(builder, name, ast_context.file.src, .Variable, .None); + } + + visit(value_decl.type, builder, ast_context); + + return; + } + + if len(value_decl.values) == 1 { + switch v in value_decl.values[0].derived { + case Struct_Type: + write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Struct, .None); + write_semantic_string(builder, v.pos, "struct", ast_context.file.src, .Keyword, .None); + visit_struct_fields(v, builder, ast_context); + case Enum_Type: + write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Enum, .None); + write_semantic_string(builder, v.pos, "enum", ast_context.file.src, .Keyword, .None); + visit_enum_fields(v, builder, ast_context); + case Proc_Group: + write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Function, .None); + write_semantic_string(builder, v.pos, "proc", ast_context.file.src, .Keyword, .None); + for arg in v.args { + if ident, ok := arg.derived.(Ident); ok { + write_semantic_node(builder, arg, ast_context.file.src, .Function, .None); + } + } + case Proc_Lit: + write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Function, .None); + write_semantic_string(builder, v.pos, "proc", ast_context.file.src, .Keyword, .None); + visit_proc_type(v.type, builder, ast_context); + + visit(v.body, builder, ast_context); + case: + for name in value_decl.names { + write_semantic_node(builder, name, ast_context.file.src, .Variable, .None); + } + + visit(value_decl.values[0], builder, ast_context); + } + } else { + for name in value_decl.names { + write_semantic_node(builder, name, ast_context.file.src, .Variable, .None); + } + + for value in value_decl.values { + visit(value, builder, ast_context); + } + } +} + +visit_token_op :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: string) { + if token.text == "in" { + write_semantic_string(builder, token.pos, token.text, src, .Keyword, .None); + } else { + write_semantic_string(builder, token.pos, token.text, src, .Operator, .None); + } +} + +visit_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { + using ast; + + if node == nil { + return; + } + + if node.params != nil { + for param in node.params.list { + for name in param.names { + if ident, ok := name.derived.(Ident); ok { + write_semantic_node(builder, name, ast_context.file.src, .Parameter, .None); + } + } + + visit(param.type, builder, ast_context); + } + } + + if node.results != nil { + for result in node.results.list { + for name in result.names { + if ident, ok := name.derived.(Ident); ok { + //write_semantic_node(builder, name, ast_context.file.src, .Parameter, .None); + } + } + + visit(result.type, builder, ast_context); + } + } +} + +visit_enum_fields :: proc(node: ast.Enum_Type, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { + using ast; + + if node.fields == nil { + return; + } + + for field in node.fields { + + if ident, ok := field.derived.(Ident); ok { + write_semantic_node(builder, field, ast_context.file.src, .EnumMember, .None); + } + else if f, ok := field.derived.(Field_Value); ok { + if ident, ok := f.field.derived.(Ident); ok { + write_semantic_node(builder, f.field, ast_context.file.src, .EnumMember, .None); + } + visit(f.value, builder, ast_context); + } + } +} + +visit_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { + using ast; + + if node.fields == nil { + return; + } + + for field in node.fields.list { + + for name in field.names { + if ident, ok := name.derived.(Ident); ok { + write_semantic_node(builder, name, ast_context.file.src, .Property, .None); + } + } + + visit(field.type, builder, ast_context); + } +} + +visit_selector :: proc(selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { + using analysis; + using ast; +}
\ No newline at end of file |