aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Lewis <22850972+BradLewis@users.noreply.github.com>2025-09-07 21:24:33 -0400
committerBrad Lewis <22850972+BradLewis@users.noreply.github.com>2025-09-07 21:38:30 -0400
commit19ee061feef6f74b54a4ca5e36a8e3711907935b (patch)
tree0f9649a1bc288959f14da6712cff65274fc63d06
parent7d334f6c9fff565b5d51c30e13db810f466e6241 (diff)
Distinguish between variables and types when parsing globals
-rw-r--r--src/server/analysis.odin13
-rw-r--r--src/server/ast.odin47
-rw-r--r--src/server/collector.odin10
-rw-r--r--src/server/semantic_tokens.odin44
-rw-r--r--src/server/symbol.odin3
5 files changed, 61 insertions, 56 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index ac3680c..22324f4 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -1733,7 +1733,7 @@ resolve_global_identifier :: proc(ast_context: ^AstContext, node: ast.Ident, glo
}
if ok = internal_resolve_type_expression(ast_context, v.expr, &return_symbol); ok {
- return_types := get_proc_return_types(ast_context, return_symbol, v, global.mutable)
+ return_types := get_proc_return_types(ast_context, return_symbol, v, .Mutable in global.flags)
if len(return_types) > 0 {
ok = internal_resolve_type_expression(ast_context, return_types[0], &return_symbol)
}
@@ -1799,7 +1799,7 @@ resolve_global_identifier :: proc(ast_context: ^AstContext, node: ast.Ident, glo
case ^ast.Basic_Lit:
return_symbol, ok = resolve_basic_lit(ast_context, v^)
return_symbol.name = node.name
- return_symbol.type = global.mutable ? .Variable : .Constant
+ return_symbol.type = .Mutable in global.flags ? .Variable : .Constant
case:
ok = internal_resolve_type_expression(ast_context, global.expr, &return_symbol)
}
@@ -1809,10 +1809,17 @@ resolve_global_identifier :: proc(ast_context: ^AstContext, node: ast.Ident, glo
return_symbol.flags |= {.Distinct}
}
- if global.mutable {
+ if .Mutable in global.flags {
return_symbol.type = .Variable
}
+ if .Variable in global.flags {
+ return_symbol.flags |= {.Variable}
+ }
+ if .Mutable in global.flags {
+ return_symbol.flags |= {.Mutable}
+ }
+
if global.docs != nil {
return_symbol.doc = get_doc(global.name_expr, global.docs, ast_context.allocator)
}
diff --git a/src/server/ast.odin b/src/server/ast.odin
index e658123..2580338 100644
--- a/src/server/ast.odin
+++ b/src/server/ast.odin
@@ -82,11 +82,16 @@ are_keyword_aliases :: proc(a, b: string) -> bool {
return false
}
+GlobalFlags :: enum {
+ Mutable, // or constant
+ Variable, // or type
+}
+
GlobalExpr :: struct {
name: string,
name_expr: ^ast.Expr,
expr: ^ast.Expr,
- mutable: bool,
+ flags: bit_set[GlobalFlags],
docs: ^ast.Comment_Group,
comment: ^ast.Comment_Group,
attributes: []^ast.Attribute,
@@ -353,6 +358,17 @@ merge_attributes :: proc(attrs: []^ast.Attribute, foreign_attrs: []^ast.Attribut
return new_attrs[:]
}
+// TODO: it seems the global symbols don't distinguish between a type decl and
+// a const variable declaration, so we do a quick check here to distinguish the cases.
+is_variable_declaration :: proc(expr: ^ast.Expr) -> bool {
+ #partial switch v in expr.derived {
+ case ^ast.Comp_Lit, ^ast.Basic_Lit, ^ast.Type_Cast, ^ast.Call_Expr:
+ return true
+ case:
+ return false
+ }
+}
+
collect_value_decl :: proc(
exprs: ^[dynamic]GlobalExpr,
file: ast.File,
@@ -370,13 +386,16 @@ collect_value_decl :: proc(
attributes := merge_attributes(value_decl.attributes[:], foreign_attrs)
global_expr := GlobalExpr {
- mutable = value_decl.is_mutable,
docs = value_decl.docs,
comment = comment,
attributes = attributes,
private = file_tags.private,
}
+ if value_decl.is_mutable {
+ global_expr.flags += {.Mutable}
+ }
+
for attribute in attributes {
for elem in attribute.elems {
ident, value, ok := unwrap_attr_elem(elem)
@@ -414,6 +433,11 @@ collect_value_decl :: proc(
global_expr.name = get_ast_node_string(name, file.src)
global_expr.name_expr = name
+ if len(value_decl.values) > i {
+ if is_variable_declaration(value_decl.values[i]) {
+ global_expr.flags += {.Variable}
+ }
+ }
if value_decl.type != nil {
global_expr.expr = value_decl.type
append(exprs, global_expr)
@@ -477,13 +501,7 @@ collect_when_body :: proc(
if foreign_decl.body != nil {
if foreign_block, ok := foreign_decl.body.derived.(^ast.Block_Stmt); ok {
for foreign_stmt in foreign_block.stmts {
- collect_value_decl(
- exprs,
- file,
- file_tags,
- foreign_stmt,
- foreign_decl.attributes[:],
- )
+ collect_value_decl(exprs, file, file_tags, foreign_stmt, foreign_decl.attributes[:])
}
}
}
@@ -732,8 +750,8 @@ free_ast_node :: proc(node: ^ast.Node, allocator: mem.Allocator) {
free_ast(n.names, allocator)
free_ast(n.type, allocator)
free_ast(n.default_value, allocator)
- free_ast_comment(n.docs, allocator);
- free_ast_comment(n.comment, allocator);
+ free_ast_comment(n.docs, allocator)
+ free_ast_comment(n.comment, allocator)
case ^Field_List:
free_ast(n.list, allocator)
case ^Typeid_Type:
@@ -1306,7 +1324,12 @@ construct_struct_field_docs :: proc(file: ast.File, v: ^ast.Struct_Type, allocat
field.comment.list = list[:1]
}
if len(list) > 1 {
- next_field.docs = new_type(ast.Comment_Group, list[1].pos, parser.end_pos(list[len(list) - 2]), allocator)
+ next_field.docs = new_type(
+ ast.Comment_Group,
+ list[1].pos,
+ parser.end_pos(list[len(list) - 2]),
+ allocator,
+ )
next_field.docs.list = list[1:]
} else {
next_field.docs = nil
diff --git a/src/server/collector.odin b/src/server/collector.odin
index 4588a39..a702546 100644
--- a/src/server/collector.odin
+++ b/src/server/collector.odin
@@ -663,7 +663,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
token = v^
symbol.value = collect_generic(collection, col_expr, package_map, uri)
- if expr.mutable {
+ if .Mutable in expr.flags {
token_type = .Variable
} else {
token_type = .Unresolved
@@ -671,7 +671,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
case ^ast.Comp_Lit:
generic := collect_generic(collection, col_expr, package_map, uri)
- if expr.mutable {
+ if .Mutable in expr.flags {
token_type = .Variable
} else {
token_type = .Unresolved
@@ -685,7 +685,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
// default
symbol.value = collect_generic(collection, col_expr, package_map, uri)
- if expr.mutable {
+ if .Mutable in expr.flags {
token_type = .Variable
} else {
token_type = .Unresolved
@@ -734,6 +734,10 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
symbol.flags |= {.PrivatePackage}
}
+ if .Variable in expr.flags {
+ symbol.flags |= {.Variable}
+ }
+
pkg: ^SymbolPackage
ok: bool
diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin
index 7210ccf..703a0cb 100644
--- a/src/server/semantic_tokens.odin
+++ b/src/server/semantic_tokens.odin
@@ -390,44 +390,14 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder) {
}
}
-// TODO: it seems the global symbols don't distinguish between a type decl and
-// a const variable declaration, so we do a quick check here to distinguish the cases.
-is_variable_declaration :: proc(expr: ^ast.Expr) -> bool {
- #partial switch v in expr.derived {
- case ^ast.Comp_Lit, ^ast.Basic_Lit, ^ast.Type_Cast, ^ast.Call_Expr:
- return true
- case:
- return false
- }
-}
-
visit_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuilder) {
using ast
modifiers: SemanticTokenModifiers = value_decl.is_mutable ? {} : {.ReadOnly}
- // Check if we are a comp lit or a type declaration
-
- // a, b, c :: 1, 2, 3
- // a := 1
- if len(value_decl.values) == len(value_decl.names) {
- for name, i in value_decl.names {
- ident := name.derived.(^Ident) or_continue
- is_var_decl := is_variable_declaration(value_decl.values[i])
- visit_ident(ident, ident, modifiers, builder, is_var_decl)
- }
- } else if len(value_decl.values) > 0 {
- // a, b: int
- is_var_decl := is_variable_declaration(value_decl.values[0])
- for name in value_decl.names {
- ident := name.derived.(^Ident) or_continue
- visit_ident(ident, ident, modifiers, builder, is_var_decl)
- }
- } else {
- for name in value_decl.names {
- ident := name.derived.(^Ident) or_continue
- visit_ident(ident, ident, modifiers, builder)
- }
+ for name in value_decl.names {
+ ident := name.derived.(^Ident) or_continue
+ visit_ident(ident, ident, modifiers, builder)
}
visit_node(value_decl.type, builder)
@@ -559,7 +529,6 @@ visit_ident :: proc(
symbol_ptr: rawptr,
modifiers: SemanticTokenModifiers,
builder: ^SemanticTokenBuilder,
- is_variable_decl := false,
) {
using ast
@@ -571,14 +540,15 @@ visit_ident :: proc(
modifiers := modifiers
- if symbol.type != .Variable {
+ if .Mutable not_in symbol.flags {
modifiers += {.ReadOnly}
}
- if is_variable_decl {
+ if .Variable in symbol.flags {
write_semantic_node(builder, ident, .Variable, modifiers)
return
}
+
/* variable idents */
#partial switch symbol.type {
case .Variable, .Constant, .Function:
@@ -612,7 +582,7 @@ visit_ident :: proc(
SymbolMapValue,
SymbolMultiPointerValue,
SymbolBasicValue,
- SymbolPolyTypeValue:
+ SymbolPolyTypeValue:
write_semantic_node(builder, ident, .Type, modifiers)
case SymbolUntypedValue:
// handled by static syntax highlighting
diff --git a/src/server/symbol.odin b/src/server/symbol.odin
index 2090f3b..9e220c5 100644
--- a/src/server/symbol.odin
+++ b/src/server/symbol.odin
@@ -194,7 +194,8 @@ SymbolFlag :: enum {
PrivateFile,
PrivatePackage,
Anonymous, //Usually applied to structs that are defined inline inside another struct
- Variable, //Symbols that are variable, this means their value decl was mutable
+ Variable, // or type
+ Mutable, // or constant
Local,
ObjC,
ObjCIsClassMethod, // should be set true only when ObjC is enabled