aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Gavin <danielgavin5@hotmail.com>2022-01-17 12:54:17 +0100
committerDaniel Gavin <danielgavin5@hotmail.com>2022-01-17 12:54:17 +0100
commit64e56f1610a568331b19ab713ea033030f0eac2d (patch)
tree45674a85f8c4f29cc8c83d6af9715687b963a9fe /src
parent273de152aee21ed4855bf4b6fdbd08d494995863 (diff)
work on the new semantic tokens.
Diffstat (limited to 'src')
-rw-r--r--src/analysis/analysis.odin83
-rw-r--r--src/server/requests.odin12
-rw-r--r--src/server/semantic_tokens.odin374
3 files changed, 410 insertions, 59 deletions
diff --git a/src/analysis/analysis.odin b/src/analysis/analysis.odin
index cdf4f98..5d50e50 100644
--- a/src/analysis/analysis.odin
+++ b/src/analysis/analysis.odin
@@ -837,13 +837,20 @@ lookup_symbol_cache :: proc(ast_context: ^AstContext, node: ast.Node) -> (index.
return {}, false;
}
- if cached := &ast_context.symbol_cache[node.pos.offset]; cached != nil {
+ if cached := &ast_context.symbol_cache[node.end.offset]; cached != nil {
symbol := cast(^index.Symbol)cached^;
return symbol^, true;
}
return {}, false;
}
+store_symbol_cache :: proc(ast_context: ^AstContext, data: rawptr, offset: int) {
+ if ast_context.document_package != ast_context.current_package {
+ return;
+ }
+ ast_context.symbol_cache[offset] = cast(rawptr)data;
+}
+
resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (index.Symbol, bool) {
if symbol, ok := lookup_symbol_cache(ast_context, node^); ok {
return symbol, true;
@@ -853,7 +860,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i
if symbol, ok := internal_resolve_type_expression(ast_context, node); ok {
cached_symbol := index.new_clone_symbol(symbol);
- ast_context.symbol_cache[node.end.offset] = cast(rawptr)cached_symbol;
+ store_symbol_cache(ast_context, cached_symbol, node.end.offset);
return symbol, true;
}
@@ -1143,7 +1150,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i
if symbol, ok := internal_resolve_type_identifier(ast_context, node); ok {
cached_symbol := index.new_clone_symbol(symbol);
- ast_context.symbol_cache[node.end.offset] = cast(rawptr)cached_symbol;
+ store_symbol_cache(ast_context, cached_symbol, node.end.offset);
return symbol, true;
}
@@ -1536,7 +1543,6 @@ resolve_unresolved_symbol :: proc(ast_context: ^AstContext, symbol: ^index.Symbo
}
resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (index.Symbol, bool) {
-
symbol: index.Symbol;
if local := get_local(ast_context, node.pos.offset, node.name); local != nil {
@@ -1563,7 +1569,6 @@ resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -
}
resolve_first_symbol_from_binary_expression :: proc(ast_context: ^AstContext, binary: ^ast.Binary_Expr) -> (index.Symbol, bool) {
-
//Fairly simple function to find the earliest identifier symbol in binary expression.
if binary.left != nil {
@@ -1595,7 +1600,6 @@ resolve_first_symbol_from_binary_expression :: proc(ast_context: ^AstContext, bi
}
find_position_in_call_param :: proc(ast_context: ^AstContext, call: ast.Call_Expr) -> (int, bool) {
-
if call.args == nil {
return 0, false;
}
@@ -1646,7 +1650,6 @@ get_package_from_node :: proc(node: ast.Node) -> string {
}
get_using_packages :: proc(ast_context: ^AstContext) -> []string {
-
usings := make([]string, len(ast_context.usings), context.temp_allocator);
if len(ast_context.usings) == 0 {
@@ -1668,7 +1671,6 @@ get_using_packages :: proc(ast_context: ^AstContext) -> []string {
}
make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v: ast.Proc_Type, name: string) -> index.Symbol {
-
symbol := index.Symbol {
range = common.get_token_range(n^, ast_context.file.src),
type = .Function,
@@ -1706,7 +1708,6 @@ make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v
}
make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type) -> index.Symbol {
-
symbol := index.Symbol {
range = common.get_token_range(v.node, ast_context.file.src),
type = .Variable,
@@ -1728,7 +1729,6 @@ make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type)
}
make_symbol_dynamic_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Dynamic_Array_Type) -> index.Symbol {
-
symbol := index.Symbol {
range = common.get_token_range(v.node, ast_context.file.src),
type = .Variable,
@@ -1743,7 +1743,6 @@ make_symbol_dynamic_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Dyna
}
make_symbol_map_from_ast :: proc(ast_context: ^AstContext, v: ast.Map_Type) -> index.Symbol {
-
symbol := index.Symbol {
range = common.get_token_range(v.node, ast_context.file.src),
type = .Variable,
@@ -1759,7 +1758,6 @@ make_symbol_map_from_ast :: proc(ast_context: ^AstContext, v: ast.Map_Type) -> i
}
make_symbol_basic_type_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v: ^ast.Ident) -> index.Symbol {
-
symbol := index.Symbol {
range = common.get_token_range(n^, ast_context.file.src),
type = .Variable,
@@ -1774,7 +1772,6 @@ make_symbol_basic_type_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node,
}
make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, ident: string, inlined := false) -> index.Symbol {
-
symbol := index.Symbol {
range = common.get_token_range(v, ast_context.file.src),
type = .Union,
@@ -1848,7 +1845,6 @@ make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, id
}
make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Type, ident: string, inlined := false) -> index.Symbol {
-
symbol := index.Symbol {
range = common.get_token_range(v, ast_context.file.src),
type = .Enum,
@@ -1869,7 +1865,6 @@ make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Typ
}
make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type, ident: string, inlined := false) -> index.Symbol {
-
symbol := index.Symbol {
range = common.get_token_range(v, ast_context.file.src),
type = .Struct,
@@ -2038,7 +2033,6 @@ resolve_poly_struct :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_Li
}
get_globals :: proc(file: ast.File, ast_context: ^AstContext) {
-
ast_context.variables["context"] = true;
exprs := common.collect_globals(file);
@@ -2050,7 +2044,6 @@ get_globals :: proc(file: ast.File, ast_context: ^AstContext) {
}
get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^AstContext, results: ^[dynamic]^ast.Expr) {
-
using ast;
ast_context.use_locals = true;
@@ -2067,7 +2060,6 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A
}
}
}
-
case Comp_Lit:
if v.type != nil {
append(results, v.type);
@@ -2400,7 +2392,7 @@ get_locals_type_switch_stmt :: proc(file: ast.File, stmt: ast.Type_Switch_Stmt,
}
}
-get_locals_proc_param_and_results :: proc(file: ast.File, function: ^ast.Node, ast_context: ^AstContext, document_position: ^DocumentPositionContext) {
+get_locals_proc_param_and_results :: proc(file: ast.File, function: ast.Proc_Lit, ast_context: ^AstContext, document_position: ^DocumentPositionContext) {
proc_lit, ok := function.derived.(ast.Proc_Lit);
if !ok || proc_lit.body == nil {
@@ -2458,7 +2450,7 @@ get_locals :: proc(file: ast.File, function: ^ast.Node, ast_context: ^AstContext
return;
}
- get_locals_proc_param_and_results(file, function, ast_context, document_position);
+ get_locals_proc_param_and_results(file, proc_lit, ast_context, document_position);
block: ast.Block_Stmt;
block, ok = proc_lit.body.derived.(ast.Block_Stmt);
@@ -2480,26 +2472,22 @@ clear_locals :: proc(ast_context: ^AstContext) {
clear(&ast_context.usings);
}
-resolve_entire_file :: proc(document: ^common.Document, allocator := context.allocator) -> []index.Symbol {
- ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache);
-
- get_globals(document.ast, &ast_context);
+resolve_entire_file :: proc(document: ^common.Document, ast_context: ^AstContext, allocator := context.allocator) -> []index.Symbol {
+ get_globals(document.ast, ast_context);
ast_context.current_package = ast_context.document_package;
symbols := make([dynamic]index.Symbol, allocator);
- for decl in document.ast.decls {
- switch v in decl.derived {
+ for k, v in ast_context.globals {
+ switch n in v.expr.derived {
case ast.Proc_Lit:
- position_context: DocumentPositionContext;
- position_context.position = v.end.offset;
- //get_locals_proc_param_and_results
- //get_locals_stmt()
- resolve_entire_procedure(&ast_context, v, &symbols, allocator);
+ resolve_entire_procedure(ast_context, n, &symbols, allocator);
+ clear_local_group(ast_context, 0);
+ add_local_group(ast_context, 0);
}
}
-
+
return symbols[:];
}
@@ -2528,6 +2516,8 @@ resolve_entire_procedure :: proc(ast_context: ^AstContext, procedure: ast.Proc_L
}
data := cast(^Visit_Data)visitor.data;
ast_context := data.ast_context;
+ ast_context.use_locals = true;
+ ast_context.use_globals = true;
//It's somewhat silly to check the scope everytime, but the alternative is to implement my own walker function.
if len(data.scopes) > 0 {
@@ -2554,8 +2544,19 @@ resolve_entire_procedure :: proc(ast_context: ^AstContext, procedure: ast.Proc_L
scope.offset = node.end.offset;
data.id_counter += 1;
ast_context.local_id = scope.id;
+
append(&data.scopes, scope);
add_local_group(ast_context, scope.id);
+
+ position_context: DocumentPositionContext;
+ position_context.position = node.end.offset;
+ get_locals_stmt(ast_context.file, cast(^ast.Stmt)node, ast_context, &position_context);
+ }
+
+
+ switch v in &node.derived {
+ case ast.If_Stmt:
+ case ast.For_Stmt:
//get_locals_stmt(ast_context.file, v, ast_context, )
case ast.Ident:
if symbol, ok := resolve_type_identifier(ast_context, v); ok {
@@ -2575,12 +2576,20 @@ resolve_entire_procedure :: proc(ast_context: ^AstContext, procedure: ast.Proc_L
visit = visit,
}
- ast.walk(&visitor, procedure.body);
-
- if procedure.type != nil {
- ast.walk(&visitor, procedure.type.params);
- ast.walk(&visitor, procedure.type.results);
+ if procedure.body == nil {
+ return;
}
+
+ type_position_context: DocumentPositionContext;
+ type_position_context.position = procedure.end.offset;
+ get_locals_proc_param_and_results(ast_context.file, procedure, ast_context, &type_position_context);
+
+ body_position_context: DocumentPositionContext;
+ body_position_context.position = procedure.body.end.offset;
+
+ get_locals_stmt(ast_context.file, cast(^ast.Stmt)procedure.body, ast_context, &body_position_context);
+
+ ast.walk(&visitor, procedure.body);
}
concatenate_symbol_information :: proc {
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