From 0ca38c9f44b47c87ae9e810087eabec0f01c0d9c Mon Sep 17 00:00:00 2001 From: Damian Tarnawski Date: Sat, 27 Apr 2024 22:13:05 +0200 Subject: [PATCH 1/2] Simplify and improve semantic tokens system further - Remove the remaining tokens for operators, those will be handled by syntax highlighting - Improve `visit_value_decl` mostly around making aliases: ```odin foo :: proc() {} bar :: foo ``` now `bar` will be highlighted as a `.Function` - Add `src` to `SemanticTokenBuilder` to avoid it being passed around to every proc - Tried to reduce the amount of procedures and repeated code Now most of the work is done by `visit_node`, which walks the ast looking for identifiers, and `visit_ident`, which writes the token for that identifier based on it's symbol --- src/server/semantic_tokens.odin | 881 +++++++++----------------------- 1 file changed, 240 insertions(+), 641 deletions(-) diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin index 95e286ba..bd95d485 100644 --- a/src/server/semantic_tokens.odin +++ b/src/server/semantic_tokens.odin @@ -109,16 +109,7 @@ SemanticTokenBuilder :: struct { tokens: [dynamic]u32, symbols: map[uintptr]SymbolAndNode, selector: bool, -} - -make_token_builder :: proc( - allocator := context.temp_allocator, -) -> SemanticTokenBuilder { - return {tokens = make([dynamic]u32, 10000, context.temp_allocator)} -} - -get_tokens :: proc(builder: SemanticTokenBuilder) -> SemanticTokens { - return {data = builder.tokens[:]} + src: string, } get_semantic_tokens :: proc( @@ -126,8 +117,6 @@ get_semantic_tokens :: proc( range: common.Range, symbols: map[uintptr]SymbolAndNode, ) -> SemanticTokens { - builder := make_token_builder() - ast_context := make_ast_context( document.ast, document.imports, @@ -135,137 +124,91 @@ get_semantic_tokens :: proc( document.uri.uri, document.fullpath, ) - - builder.symbols = symbols - ast_context.current_package = ast_context.document_package + builder: SemanticTokenBuilder = { + tokens = make([dynamic]u32, 10000, context.temp_allocator), + symbols = symbols, + src = ast_context.file.src, + } + for decl in document.ast.decls { if range.start.line <= decl.pos.line && decl.end.line <= range.end.line { - visit(decl, &builder, &ast_context) + visit_node(decl, &builder) } } - return get_tokens(builder) + return {data = builder.tokens[:]} } -write_semantic_node :: proc( +write_semantic_at_pos :: proc( builder: ^SemanticTokenBuilder, - node: ^ast.Node, - src: string, + pos: int, + len: int, type: SemanticTokenTypes, modifiers: SemanticTokenModifiers = {}, ) { - //Sometimes odin ast uses "_" for empty params. - if ident, ok := node.derived.(^ast.Ident); ok && ident.name == "_" { - return - } - position := common.get_relative_token_position( - node.pos.offset, - transmute([]u8)src, + pos, + transmute([]u8)builder.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)len, cast(u32)type, transmute(u32)modifiers, ) - builder.current_start = node.pos.offset + builder.current_start = pos } -write_semantic_token :: proc( +write_semantic_node :: proc( builder: ^SemanticTokenBuilder, - token: tokenizer.Token, - src: string, + node: ^ast.Node, type: SemanticTokenTypes, modifiers: 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, - transmute(u32)modifiers, + //Sometimes odin ast uses "_" for empty params. + if ident, ok := node.derived.(^ast.Ident); ok && ident.name == "_" { + return + } + + name := common.get_ast_node_string(node, builder.src) + + write_semantic_at_pos( + builder, + node.pos.offset, + len(name), + type, + modifiers, ) - builder.current_start = token.pos.offset } -write_semantic_string :: proc( +write_semantic_token :: proc( builder: ^SemanticTokenBuilder, - pos: tokenizer.Pos, - name: string, - src: string, + token: tokenizer.Token, type: SemanticTokenTypes, modifiers: 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, - transmute(u32)modifiers, + write_semantic_at_pos( + builder, + token.pos.offset, + len(token.text), + type, + modifiers, ) - 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: ^AstContext, -) { - for elem, i in array { - visit(elem, builder, ast_context) - } } -visit_dynamic_array :: proc( - array: $A/[dynamic]^$T, - builder: ^SemanticTokenBuilder, - ast_context: ^AstContext, -) { - for elem, i in array { - visit(elem, builder, ast_context) +visit_nodes :: proc(array: []$T/^ast.Node, builder: ^SemanticTokenBuilder) { + for elem in array { + visit_node(elem, builder) } } -visit_stmt :: proc( - node: ^ast.Stmt, - builder: ^SemanticTokenBuilder, - ast_context: ^AstContext, -) { - visit_node(node, builder, ast_context) -} - -visit_node :: proc( - node: ^ast.Node, - builder: ^SemanticTokenBuilder, - ast_context: ^AstContext, -) { +visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder) { using ast if node == nil { @@ -274,509 +217,203 @@ visit_node :: proc( #partial switch n in node.derived { case ^Ellipsis: - visit(n.expr, builder, ast_context) + visit_node(n.expr, builder) case ^Ident: - modifiers: SemanticTokenModifiers - - symbol_and_node := builder.symbols[cast(uintptr)node] or_break - - if symbol_and_node.symbol.type == .Constant || - symbol_and_node.symbol.type != .Variable { - modifiers += {.ReadOnly} - } - - if .Distinct in symbol_and_node.symbol.flags && - symbol_and_node.symbol.type == .Constant { - write_semantic_node( - builder, - node, - ast_context.file.src, - .Type, - ) - return - } - - #partial switch symbol_and_node.symbol.type { - case .Variable, .Constant: - #partial switch _ in symbol_and_node.symbol.value { - case SymbolProcedureValue: - write_semantic_node( - builder, - node, - ast_context.file.src, - .Function, - modifiers, - ) - case: - write_semantic_node( - builder, - node, - ast_context.file.src, - .Variable, - modifiers, - ) - } - case .Type_Function: - write_semantic_node( - builder, - node, - ast_context.file.src, - .Type, - modifiers, - ) - } - - switch v in symbol_and_node.symbol.value { - case SymbolPackageValue: - write_semantic_node( - builder, - node, - ast_context.file.src, - .Namespace, - ) - case SymbolStructValue, - SymbolBitFieldValue: - write_semantic_node( - builder, - node, - ast_context.file.src, - .Struct, - modifiers, - ) - case SymbolEnumValue, - SymbolUnionValue: - write_semantic_node( - builder, - node, - ast_context.file.src, - .Enum, - modifiers, - ) - case SymbolProcedureValue, - SymbolProcedureGroupValue, - SymbolAggregateValue: - write_semantic_node( - builder, - node, - ast_context.file.src, - .Function, - modifiers, - ) - case SymbolMatrixValue, - SymbolBitSetValue, - SymbolDynamicArrayValue, - SymbolFixedArrayValue, - SymbolSliceValue, - SymbolMapValue, - SymbolMultiPointer: - write_semantic_node( - builder, - node, - ast_context.file.src, - .Type, - modifiers, - ) - case SymbolBasicValue, SymbolUntypedValue: - // handled by static syntax analysis - case SymbolGenericValue: - // unused - case: - //log.errorf("Unexpected symbol value: %v", symbol.value); - //panic(fmt.tprintf("Unexpected symbol value: %v", symbol.value)); - } + visit_ident(n, {}, builder) case ^Selector_Expr: - visit_selector(cast(^Selector_Expr)node, builder, ast_context) + visit_selector(cast(^Selector_Expr)node, builder) builder.selector = false case ^When_Stmt: - visit(n.cond, builder, ast_context) - visit(n.body, builder, ast_context) - visit(n.else_stmt, builder, ast_context) + visit_node(n.cond, builder) + visit_node(n.body, builder) + visit_node(n.else_stmt, builder) case ^Pointer_Type: - write_semantic_string( - builder, - node.pos, - "^", - ast_context.file.src, - .Operator, - ) - visit(n.elem, builder, ast_context) + visit_node(n.elem, builder) case ^Value_Decl: - visit_value_decl(n^, builder, ast_context) + visit_value_decl(n^, builder) case ^Block_Stmt: - visit(n.stmts, builder, ast_context) - case ^ast.Foreign_Block_Decl: - visit(n.body, builder, ast_context) + visit_nodes(n.stmts, builder) + case ^Foreign_Block_Decl: + visit_node(n.body, builder) case ^Expr_Stmt: - visit(n.expr, builder, ast_context) + visit_node(n.expr, builder) case ^Matrix_Type: - visit(n.row_count, builder, ast_context) - visit(n.column_count, builder, ast_context) - visit(n.elem, builder, ast_context) - case ^ast.Matrix_Index_Expr: - visit(n.expr, builder, ast_context) - visit(n.row_index, builder, ast_context) - visit(n.column_index, builder, ast_context) + visit_node(n.row_count, builder) + visit_node(n.column_count, builder) + visit_node(n.elem, builder) + case ^Matrix_Index_Expr: + visit_node(n.expr, builder) + visit_node(n.row_index, builder) + visit_node(n.column_index, builder) case ^Poly_Type: - write_semantic_string( - builder, - n.dollar, - "$", - ast_context.file.src, - .Operator, - ) - visit(n.type, builder, ast_context) - visit(n.specialization, builder, ast_context) + visit_node(n.type, builder) + visit_node(n.specialization, builder) case ^Range_Stmt: for val in n.vals { if ident, ok := val.derived.(^Ident); ok { - write_semantic_node( - builder, - val, - ast_context.file.src, - .Variable, - ) + write_semantic_node(builder, val, .Variable) } } - visit(n.expr, builder, ast_context) - visit(n.body, builder, ast_context) + visit_node(n.expr, builder) + visit_node(n.body, builder) case ^If_Stmt: - visit(n.init, builder, ast_context) - visit(n.cond, builder, ast_context) - visit(n.body, builder, ast_context) + visit_node(n.init, builder) + visit_node(n.cond, builder) + visit_node(n.body, builder) if n.else_stmt != nil { - visit(n.else_stmt, builder, ast_context) + visit_node(n.else_stmt, builder) } case ^For_Stmt: - visit(n.init, builder, ast_context) - visit(n.cond, builder, ast_context) - visit(n.post, builder, ast_context) - visit(n.body, builder, ast_context) + visit_node(n.init, builder) + visit_node(n.cond, builder) + visit_node(n.post, builder) + visit_node(n.body, builder) case ^Switch_Stmt: - visit(n.init, builder, ast_context) - visit(n.cond, builder, ast_context) - visit(n.body, builder, ast_context) + visit_node(n.init, builder) + visit_node(n.cond, builder) + visit_node(n.body, builder) case ^Type_Switch_Stmt: - visit(n.tag, builder, ast_context) - visit(n.expr, builder, ast_context) - visit(n.body, builder, ast_context) + visit_node(n.tag, builder) + visit_node(n.expr, builder) + visit_node(n.body, builder) 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, - ) + write_semantic_node(builder, l, .Variable) } else { - visit(l, builder, ast_context) + visit_node(l, builder) } } - - visit_token_op(builder, n.op, ast_context.file.src) - visit(n.rhs, builder, ast_context) + visit_nodes(n.rhs, builder) case ^Case_Clause: - visit(n.list, builder, ast_context) - visit(n.body, builder, ast_context) + visit_nodes(n.list, builder) + visit_nodes(n.body, builder) case ^Call_Expr: - visit(n.expr, builder, ast_context) - visit(n.args, builder, ast_context) + visit_node(n.expr, builder) + visit_nodes(n.args, builder) case ^Implicit_Selector_Expr: write_semantic_node( builder, n.field, - ast_context.file.src, .EnumMember, ) case ^Array_Type: - visit(n.len, builder, ast_context) - visit(n.elem, builder, ast_context) + visit_node(n.len, builder) + visit_node(n.elem, builder) 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) + visit_node(n.left, builder) + visit_node(n.right, builder) case ^Comp_Lit: - visit(n.type, builder, ast_context) - visit(n.elems, builder, ast_context) + visit_node(n.type, builder) + visit_nodes(n.elems, builder) case ^Struct_Type: - visit_struct_fields(n^, builder, ast_context) + visit_struct_fields(n^, builder) case ^Type_Assertion: - visit(n.expr, builder, ast_context) - visit(n.type, builder, ast_context) + visit_node(n.expr, builder) + visit_node(n.type, builder) case ^Type_Cast: - visit(n.type, builder, ast_context) - visit(n.expr, builder, ast_context) + visit_node(n.type, builder) + visit_node(n.expr, builder) case ^Paren_Expr: - visit(n.expr, builder, ast_context) + visit_node(n.expr, builder) case ^Deref_Expr: - visit(n.expr, builder, ast_context) + visit_node(n.expr, builder) case ^Return_Stmt: - visit(n.results, builder, ast_context) + visit_nodes(n.results, builder) case ^Dynamic_Array_Type: - visit(n.elem, builder, ast_context) + visit_node(n.elem, builder) case ^Multi_Pointer_Type: - visit(n.elem, builder, ast_context) + visit_node(n.elem, builder) case ^Field_Value: if ident, ok := n.field.derived.(^Ident); ok { - write_semantic_node( - builder, - n.field, - ast_context.file.src, - .Property, - ) + write_semantic_node(builder, n.field, .Property) } else { - visit(n.field, builder, ast_context) + visit_node(n.field, builder) } - visit(n.value, builder, ast_context) + visit_node(n.value, builder) 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) + visit_node(n.expr, builder) + visit_node(n.index, builder) case ^Unary_Expr: - visit(n.expr, builder, ast_context) + visit_node(n.expr, builder) case ^Implicit: case ^Slice_Expr: - visit(n.expr, builder, ast_context) + visit_node(n.expr, builder) case ^Using_Stmt: - visit(n.list, builder, ast_context) + visit_nodes(n.list, builder) case ^Map_Type: - visit(n.key, builder, ast_context) - visit(n.value, builder, ast_context) + visit_node(n.key, builder) + visit_node(n.value, builder) case ^Bit_Set_Type: - visit(n.elem, builder, ast_context) - visit(n.underlying, builder, ast_context) + visit_node(n.elem, builder) + visit_node(n.underlying, builder) case ^Defer_Stmt: - visit(n.stmt, builder, ast_context) + visit_node(n.stmt, builder) case ^Import_Decl: if n.name.text != "" { - write_semantic_token( - builder, - n.name, - ast_context.file.src, - .Namespace, - ) + write_semantic_token(builder, n.name, .Namespace) } case ^Or_Return_Expr: - visit(n.expr, builder, ast_context) + visit_node(n.expr, builder) case ^Or_Else_Expr: - visit(n.x, builder, ast_context) - visit(n.y, builder, ast_context) + visit_node(n.x, builder) + visit_node(n.y, builder) case ^Ternary_If_Expr: if n.op1.text == "if" { - visit(n.x, builder, ast_context) - visit(n.cond, builder, ast_context) - visit(n.y, builder, ast_context) + visit_node(n.x, builder) + visit_node(n.cond, builder) + visit_node(n.y, builder) } else { - visit(n.cond, builder, ast_context) - visit(n.x, builder, ast_context) - visit(n.y, builder, ast_context) + visit_node(n.cond, builder) + visit_node(n.x, builder) + visit_node(n.y, builder) } case ^Ternary_When_Expr: - visit(n.cond, builder, ast_context) - visit(n.x, builder, ast_context) - visit(n.y, builder, ast_context) + visit_node(n.cond, builder) + visit_node(n.x, builder) + visit_node(n.y, builder) case ^Union_Type: - visit(n.variants, builder, ast_context) - case ^ast.Enum_Type: - visit_enum_fields(n^, builder, ast_context) + visit_nodes(n.variants, builder) + case ^Enum_Type: + visit_enum_fields(n^, builder) case ^Proc_Type: - visit_proc_type(n, builder, ast_context) + visit_proc_type(n, builder) case ^Proc_Lit: - visit_proc_type(n.type, builder, ast_context) - - visit(n.body, builder, ast_context) + visit_proc_type(n.type, builder) + visit_node(n.body, builder) + case ^Proc_Group: + for arg in n.args { + ident := arg.derived.(^Ident) or_continue + write_semantic_node(builder, arg, .Function) + } case ^Bit_Field_Type: - visit_bit_field_fields(n^, builder, ast_context) + visit_bit_field_fields(n^, builder) case: } } -visit_basic_lit :: proc( - basic_lit: ast.Basic_Lit, - builder: ^SemanticTokenBuilder, - ast_context: ^AstContext, -) { - if symbol, ok := resolve_basic_lit(ast_context, basic_lit); ok { - if untyped, ok := symbol.value.(SymbolUntypedValue); ok { - #partial switch untyped.type { - case .Bool: - write_semantic_token( - builder, - basic_lit.tok, - ast_context.file.src, - .Keyword, - ) - case .Float, .Integer: - write_semantic_token( - builder, - basic_lit.tok, - ast_context.file.src, - .Number, - ) - } - } - } -} - -visit_value_decl :: proc( - value_decl: ast.Value_Decl, - builder: ^SemanticTokenBuilder, - ast_context: ^AstContext, -) { +visit_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuilder) { using ast modifiers: SemanticTokenModifiers = value_decl.is_mutable ? {} : {.ReadOnly} - - if value_decl.type != nil { - for name in value_decl.names { - write_semantic_node( - builder, - name, - ast_context.file.src, - .Variable, - modifiers, - ) - } - - visit(value_decl.type, builder, ast_context) - - if len(value_decl.values) == 1 { - visit(value_decl.values[0], builder, ast_context) - } - - return - } - - if len(value_decl.values) != 1 { - for name in value_decl.names { - write_semantic_node( - builder, - name, - ast_context.file.src, - .Variable, - modifiers, - ) - } - - for value in value_decl.values { - visit(value, builder, ast_context) - } + + for name in value_decl.names { + ident := name.derived.(^Ident) or_continue + visit_ident(ident, modifiers, builder) } - #partial switch v in value_decl.values[0].derived { - case ^Union_Type: - write_semantic_node( - builder, - value_decl.names[0], - ast_context.file.src, - .Enum, - modifiers, - ) - visit(value_decl.values[0], builder, ast_context) - case ^Struct_Type: - write_semantic_node( - builder, - value_decl.names[0], - ast_context.file.src, - .Struct, - modifiers, - ) - visit(value_decl.values[0], builder, ast_context) - case ^Enum_Type: - write_semantic_node( - builder, - value_decl.names[0], - ast_context.file.src, - .Enum, - modifiers, - ) - visit(value_decl.values[0], builder, ast_context) - case ^Bit_Set_Type: - write_semantic_node( - builder, - value_decl.names[0], - ast_context.file.src, - .Type, - modifiers, - ) - visit(value_decl.values[0], builder, ast_context) - case ^Proc_Group: - write_semantic_node( - builder, - value_decl.names[0], - ast_context.file.src, - .Function, - modifiers, - ) - for arg in v.args { - if ident, ok := arg.derived.(^Ident); ok { - write_semantic_node( - builder, - arg, - ast_context.file.src, - .Function, - ) - } - } - case ^Proc_Lit: - write_semantic_node( - builder, - value_decl.names[0], - ast_context.file.src, - .Function, - modifiers, - ) - visit(value_decl.values[0], builder, ast_context) - case ^Proc_Type: - write_semantic_node( - builder, - value_decl.names[0], - ast_context.file.src, - .Type, - modifiers, - ) - visit_proc_type(v, builder, ast_context) - case: - for name in value_decl.names { - write_semantic_node( - builder, - name, - ast_context.file.src, - .Variable, - modifiers, - ) - } + visit_node(value_decl.type, builder) - visit(value_decl.values[0], builder, ast_context) + for value in value_decl.values { + visit_node(value, builder) } } -visit_token_op :: proc( - builder: ^SemanticTokenBuilder, - token: tokenizer.Token, - src: string, -) { - if token.text != "in" { - write_semantic_string( - builder, - token.pos, - token.text, - src, - .Operator, - ) - } -} - -visit_proc_type :: proc( - node: ^ast.Proc_Type, - builder: ^SemanticTokenBuilder, - ast_context: ^AstContext, -) { +visit_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder) { using ast if node == nil { @@ -787,32 +424,23 @@ visit_proc_type :: proc( 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, - ) + write_semantic_node(builder, name, .Parameter) } } - visit(param.type, builder, ast_context) + visit_node(param.type, builder) } } if node.results != nil { for result in node.results.list { - visit(result.names, builder, ast_context) - visit(result.type, builder, ast_context) + visit_nodes(result.names, builder) + visit_node(result.type, builder) } } } -visit_enum_fields :: proc( - node: ast.Enum_Type, - builder: ^SemanticTokenBuilder, - ast_context: ^AstContext, -) { +visit_enum_fields :: proc(node: ast.Enum_Type, builder: ^SemanticTokenBuilder) { using ast if node.fields == nil { @@ -821,149 +449,120 @@ visit_enum_fields :: proc( for field in node.fields { if ident, ok := field.derived.(^Ident); ok { - write_semantic_node( - builder, - field, - ast_context.file.src, - .EnumMember, - ) + write_semantic_node(builder, field, .EnumMember) } else if f, ok := field.derived.(^Field_Value); ok { if _, ok := f.field.derived.(^Ident); ok { - write_semantic_node( - builder, - f.field, - ast_context.file.src, - .EnumMember, - ) + write_semantic_node(builder, f.field, .EnumMember) } - visit(f.value, builder, ast_context) + visit_node(f.value, builder) } } } -visit_struct_fields :: proc( - node: ast.Struct_Type, - builder: ^SemanticTokenBuilder, - ast_context: ^AstContext, -) { - using ast - +visit_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilder) { 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, - ) + if ident, ok := name.derived.(^ast.Ident); ok { + write_semantic_node(builder, ident, .Property) } } - visit(field.type, builder, ast_context) + visit_node(field.type, builder) } } -visit_bit_field_fields :: proc( - node: ast.Bit_Field_Type, - builder: ^SemanticTokenBuilder, - ast_context: ^AstContext, -) { +visit_bit_field_fields :: proc(node: ast.Bit_Field_Type, builder: ^SemanticTokenBuilder) { + if node.fields == nil { + return + } + for field in node.fields { if ident, ok := field.name.derived.(^ast.Ident); ok { - write_semantic_node( - builder, - ident, - ast_context.file.src, - .Property, - ) + write_semantic_node(builder, ident, .Property) } - visit(field.type, builder, ast_context) - visit(field.bit_size, builder, ast_context) + visit_node(field.type, builder) + visit_node(field.bit_size, builder) } } -visit_selector :: proc( - selector: ^ast.Selector_Expr, - builder: ^SemanticTokenBuilder, - ast_context: ^AstContext, -) { - if _, ok := selector.expr.derived.(^ast.Selector_Expr); ok { - visit_selector( - cast(^ast.Selector_Expr)selector.expr, - builder, - ast_context, - ) +visit_selector :: proc(selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuilder) { + if v, ok := selector.expr.derived.(^ast.Selector_Expr); ok { + visit_selector(v, builder) } else { - visit(selector.expr, builder, ast_context) + visit_node(selector.expr, builder) builder.selector = true } - if symbol_and_node, ok := builder.symbols[cast(uintptr)selector]; ok { - if symbol_and_node.symbol.type == .Variable { - write_semantic_node( - builder, - selector.field, - ast_context.file.src, - .Property, - ) - } else { - switch v in symbol_and_node.symbol.value { - case SymbolPackageValue: - write_semantic_node( - builder, - selector.field, - ast_context.file.src, - .Namespace, - ) - case SymbolStructValue, - SymbolBitFieldValue: - write_semantic_node( - builder, - selector.field, - ast_context.file.src, - .Struct, - ) - case SymbolEnumValue, - SymbolUnionValue: - write_semantic_node( - builder, - selector.field, - ast_context.file.src, - .Enum, - ) - case SymbolProcedureValue, - SymbolProcedureGroupValue, - SymbolAggregateValue: - write_semantic_node( - builder, - selector.field, - ast_context.file.src, - .Function, - ) - case SymbolMatrixValue, - SymbolBitSetValue, - SymbolDynamicArrayValue, - SymbolFixedArrayValue, - SymbolSliceValue, - SymbolMapValue, - SymbolMultiPointer: - write_semantic_node( - builder, - selector.field, - ast_context.file.src, - .Type, - ) - case SymbolBasicValue, SymbolUntypedValue: - // handled by static syntax analysis - case SymbolGenericValue: - // unused - } + visit_ident(selector.field, {}, builder) +} + +visit_ident :: proc( + ident: ^ast.Ident, + modifiers: SemanticTokenModifiers, + builder: ^SemanticTokenBuilder, +) { + using ast + + symbol_and_node, in_symbols := builder.symbols[cast(uintptr)ident] + if !in_symbols { + return + } + symbol := symbol_and_node.symbol + + modifiers := modifiers + if symbol.type != .Variable { + modifiers += {.ReadOnly} + } + + if .Distinct in symbol.flags && symbol.type == .Constant { + write_semantic_node(builder, ident, .Type) + return + } + + #partial switch symbol.type { + case .Variable, .Constant: + #partial switch _ in symbol.value { + case SymbolProcedureValue: + write_semantic_node(builder, ident, .Function, modifiers) + case: + write_semantic_node(builder, ident, .Variable, modifiers) } + case .Type_Function: + write_semantic_node(builder, ident, .Type, modifiers) + } + + switch v in symbol.value { + case SymbolPackageValue: + write_semantic_node(builder, ident, .Namespace, modifiers) + case SymbolStructValue, + SymbolBitFieldValue: + write_semantic_node(builder, ident, .Struct, modifiers) + case SymbolEnumValue, + SymbolUnionValue: + write_semantic_node(builder, ident, .Enum, modifiers) + case SymbolProcedureValue, + SymbolProcedureGroupValue, + SymbolAggregateValue: + write_semantic_node(builder, ident, .Function, modifiers) + case SymbolMatrixValue, + SymbolBitSetValue, + SymbolDynamicArrayValue, + SymbolFixedArrayValue, + SymbolSliceValue, + SymbolMapValue, + SymbolMultiPointer: + write_semantic_node(builder, ident, .Type, modifiers) + case SymbolBasicValue, SymbolUntypedValue: + // handled by static syntax analysis + case SymbolGenericValue: + // unused + case: + // log.errorf("Unexpected symbol value: %v", symbol.value); + // panic(fmt.tprintf("Unexpected symbol value: %v", symbol.value)); } } From 9623d701e92725401a221da9cca0e33d1a8a4635 Mon Sep 17 00:00:00 2001 From: Damian Tarnawski Date: Sat, 27 Apr 2024 22:53:13 +0200 Subject: [PATCH 2/2] Fix getting wrong symbol for selectors --- src/server/semantic_tokens.odin | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin index bd95d485..d2240f8d 100644 --- a/src/server/semantic_tokens.odin +++ b/src/server/semantic_tokens.odin @@ -219,7 +219,7 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder) { case ^Ellipsis: visit_node(n.expr, builder) case ^Ident: - visit_ident(n, {}, builder) + visit_ident(n, n, {}, builder) case ^Selector_Expr: visit_selector(cast(^Selector_Expr)node, builder) builder.selector = false @@ -403,7 +403,7 @@ visit_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuil for name in value_decl.names { ident := name.derived.(^Ident) or_continue - visit_ident(ident, modifiers, builder) + visit_ident(ident, ident, modifiers, builder) } visit_node(value_decl.type, builder) @@ -498,17 +498,18 @@ visit_selector :: proc(selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuil builder.selector = true } - visit_ident(selector.field, {}, builder) + visit_ident(selector.field, selector, {}, builder) } visit_ident :: proc( ident: ^ast.Ident, + symbol_ptr: rawptr, modifiers: SemanticTokenModifiers, builder: ^SemanticTokenBuilder, ) { using ast - symbol_and_node, in_symbols := builder.symbols[cast(uintptr)ident] + symbol_and_node, in_symbols := builder.symbols[cast(uintptr)symbol_ptr] if !in_symbols { return }