aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorDanielGavin <danielgavin5@hotmail.com>2025-06-20 18:38:28 +0200
committerDanielGavin <danielgavin5@hotmail.com>2025-06-20 18:38:28 +0200
commitfa626ad544a171313ac1679e0865d9d7d822c63b (patch)
tree4d8755ee42984d69a71a26003745c9c11ce648ab /src/server
parent5caff349cf9dad7c697eb49250ac4c1e75e259fb (diff)
Move ast.odin to server + add resolve_when_condition
Diffstat (limited to 'src/server')
-rw-r--r--src/server/analysis.odin68
-rw-r--r--src/server/ast.odin1159
-rw-r--r--src/server/collector.odin18
-rw-r--r--src/server/completion.odin42
-rw-r--r--src/server/definition.odin5
-rw-r--r--src/server/generics.odin8
-rw-r--r--src/server/hover.odin10
-rw-r--r--src/server/inlay_hints.odin2
-rw-r--r--src/server/references.odin5
-rw-r--r--src/server/requests.odin8
-rw-r--r--src/server/semantic_tokens.odin2
-rw-r--r--src/server/signature.odin10
-rw-r--r--src/server/symbol.odin41
-rw-r--r--src/server/type_definition.odin6
-rw-r--r--src/server/when.odin118
15 files changed, 1389 insertions, 113 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index bc1ae69..e779547 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -83,7 +83,7 @@ DeferredDepth :: 35
AstContext :: struct {
locals: map[int]map[string][dynamic]DocumentLocal, //locals all the way to the document position
- globals: map[string]common.GlobalExpr,
+ globals: map[string]GlobalExpr,
recursion_map: map[rawptr]bool,
usings: [dynamic]string,
file: ast.File,
@@ -115,7 +115,7 @@ make_ast_context :: proc(
) -> AstContext {
ast_context := AstContext {
locals = make(map[int]map[string][dynamic]DocumentLocal, 0, allocator),
- globals = make(map[string]common.GlobalExpr, 0, allocator),
+ globals = make(map[string]GlobalExpr, 0, allocator),
usings = make([dynamic]string, allocator),
recursion_map = make(map[rawptr]bool, 0, allocator),
file = file,
@@ -235,7 +235,7 @@ resolve_type_comp_literal :: proc(
}
if field_value, ok := elem.derived.(^ast.Field_Value); ok { //named
- if comp_lit, ref_n, ok := common.unwrap_comp_literal(field_value.value); ok {
+ if comp_lit, ref_n, ok := unwrap_comp_literal(field_value.value); ok {
if s, ok := current_symbol.value.(SymbolStructValue); ok {
for name, i in s.names {
if name == field_value.field.derived.(^ast.Ident).name {
@@ -843,7 +843,7 @@ resolve_location_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Ex
// TODO: there is likely more of these that will need to be added
#partial switch n in node.derived {
case ^ast.Ident:
- if _, ok := common.keyword_map[n.name]; ok {
+ if _, ok := keyword_map[n.name]; ok {
return {}, true
}
return resolve_location_type_identifier(ast_context, n^)
@@ -1296,7 +1296,7 @@ internal_resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ide
set_ast_package_scoped(ast_context)
- if v, ok := common.keyword_map[node.name]; ok {
+ if v, ok := keyword_map[node.name]; ok {
//keywords
ident := new_type(Ident, node.pos, node.end, ast_context.allocator)
ident.name = node.name
@@ -1546,7 +1546,7 @@ internal_resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ide
return_symbol.type = .Variable
}
- return_symbol.doc = common.get_doc(global.docs, ast_context.allocator)
+ return_symbol.doc = get_doc(global.docs, ast_context.allocator)
return return_symbol, ok
} else {
@@ -2523,9 +2523,9 @@ make_symbol_procedure_from_ast :: proc(
diverging = v.diverging,
}
- if _, ok := common.get_attribute_objc_name(attributes); ok {
+ if _, ok := get_attribute_objc_name(attributes); ok {
symbol.flags |= {.ObjC}
- if common.get_attribute_objc_is_class_method(attributes) {
+ if get_attribute_objc_is_class_method(attributes) {
symbol.flags |= {.ObjCIsClassMethod}
}
}
@@ -2552,7 +2552,7 @@ make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type,
}
}
- if common.array_is_soa(v) {
+ if array_is_soa(v) {
symbol.flags |= {.Soa}
}
@@ -2576,7 +2576,7 @@ make_symbol_dynamic_array_from_ast :: proc(
}
- if common.dynamic_array_is_soa(v) {
+ if dynamic_array_is_soa(v) {
symbol.flags |= {.Soa}
}
@@ -2810,9 +2810,9 @@ make_symbol_struct_from_ast :: proc(
poly = v.poly_params,
}
- if _, ok := common.get_attribute_objc_class_name(attributes); ok {
+ if _, ok := get_attribute_objc_class_name(attributes); ok {
symbol.flags |= {.ObjC}
- if common.get_attribute_objc_is_class_method(attributes) {
+ if get_attribute_objc_is_class_method(attributes) {
symbol.flags |= {.ObjCIsClassMethod}
}
}
@@ -2869,7 +2869,7 @@ make_symbol_bit_field_from_ast :: proc(
}
get_globals :: proc(file: ast.File, ast_context: ^AstContext) {
- exprs := common.collect_globals(file)
+ exprs := collect_globals(file)
for expr in exprs {
ast_context.globals[expr.name] = expr
@@ -2913,7 +2913,7 @@ get_generic_assignment :: proc(
if len(v.args) == 1 {
if ident, ok := v.expr.derived.(^ast.Ident); ok {
//Handle the old way of type casting
- if v, ok := common.keyword_map[ident.name]; ok {
+ if v, ok := keyword_map[ident.name]; ok {
//keywords
type_ident := new_type(Ident, ident.pos, ident.end, ast_context.allocator)
type_ident.name = ident.name
@@ -3020,7 +3020,7 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co
if value_decl.type != nil {
for name, i in value_decl.names {
- str := common.get_ast_node_string(value_decl.names[i], file.src)
+ str := get_ast_node_string(value_decl.names[i], file.src)
store_local(
ast_context,
name,
@@ -3057,7 +3057,7 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co
for name, i in value_decl.names {
result_i := min(len(results) - 1, i)
- str := common.get_ast_node_string(name, file.src)
+ str := get_ast_node_string(name, file.src)
call := false
@@ -3653,7 +3653,7 @@ get_locals_proc_param_and_results :: proc(
for arg in proc_lit.type.params.list {
for name in arg.names {
if arg.type != nil {
- str := common.get_ast_node_string(name, file.src)
+ str := get_ast_node_string(name, file.src)
store_local(
ast_context,
name,
@@ -3675,7 +3675,7 @@ get_locals_proc_param_and_results :: proc(
get_locals_using_stmt(using_stmt, ast_context)
}
} else {
- str := common.get_ast_node_string(name, file.src)
+ str := get_ast_node_string(name, file.src)
store_local(
ast_context,
name,
@@ -3698,7 +3698,7 @@ get_locals_proc_param_and_results :: proc(
for result in proc_lit.type.results.list {
for name in result.names {
if result.type != nil {
- str := common.get_ast_node_string(name, file.src)
+ str := get_ast_node_string(name, file.src)
store_local(
ast_context,
name,
@@ -3713,7 +3713,7 @@ get_locals_proc_param_and_results :: proc(
true,
)
} else {
- str := common.get_ast_node_string(name, file.src)
+ str := get_ast_node_string(name, file.src)
store_local(
ast_context,
name,
@@ -3973,15 +3973,15 @@ get_signature :: proc(
is_variable := symbol.type == .Variable
- pointer_prefix := common.repeat("^", symbol.pointers, context.temp_allocator)
+ pointer_prefix := repeat("^", symbol.pointers, context.temp_allocator)
#partial switch v in symbol.value {
case SymbolBasicValue:
- return strings.concatenate({pointer_prefix, common.node_to_string(v.ident)}, ast_context.allocator)
+ return strings.concatenate({pointer_prefix, node_to_string(v.ident)}, ast_context.allocator)
case SymbolBitSetValue:
return strings.concatenate(
- a = {pointer_prefix, "bit_set[", common.node_to_string(v.expr), "]"},
+ a = {pointer_prefix, "bit_set[", node_to_string(v.expr), "]"},
allocator = ast_context.allocator,
)
case SymbolEnumValue:
@@ -4007,7 +4007,7 @@ get_signature :: proc(
return strings.to_string(builder)
case SymbolMapValue:
return strings.concatenate(
- a = {pointer_prefix, "map[", common.node_to_string(v.key), "]", common.node_to_string(v.value)},
+ a = {pointer_prefix, "map[", node_to_string(v.key), "]", node_to_string(v.value)},
allocator = ast_context.allocator,
)
case SymbolProcedureValue:
@@ -4050,7 +4050,7 @@ get_signature :: proc(
strings.write_string(&builder, "\t")
strings.write_string(&builder, v.names[i])
fmt.sbprintf(&builder, ":%*s", longestNameLen - len(v.names[i]) + 1, "")
- common.build_string_node(v.types[i], &builder, false)
+ build_string_node(v.types[i], &builder, false)
strings.write_string(&builder, ",\n")
}
strings.write_string(&builder, "}")
@@ -4071,7 +4071,7 @@ get_signature :: proc(
strings.write_string(&builder, "union {\n")
for i in 0 ..< len(v.types) {
strings.write_string(&builder, "\t")
- common.build_string_node(v.types[i], &builder, false)
+ build_string_node(v.types[i], &builder, false)
strings.write_string(&builder, ",\n")
}
strings.write_string(&builder, "}")
@@ -4084,22 +4084,22 @@ get_signature :: proc(
}
case SymbolMultiPointerValue:
return strings.concatenate(
- a = {pointer_prefix, "[^]", common.node_to_string(v.expr)},
+ a = {pointer_prefix, "[^]", node_to_string(v.expr)},
allocator = ast_context.allocator,
)
case SymbolDynamicArrayValue:
return strings.concatenate(
- a = {pointer_prefix, "[dynamic]", common.node_to_string(v.expr)},
+ a = {pointer_prefix, "[dynamic]", node_to_string(v.expr)},
allocator = ast_context.allocator,
)
case SymbolSliceValue:
return strings.concatenate(
- a = {pointer_prefix, "[]", common.node_to_string(v.expr)},
+ a = {pointer_prefix, "[]", node_to_string(v.expr)},
allocator = ast_context.allocator,
)
case SymbolFixedArrayValue:
return strings.concatenate(
- a = {pointer_prefix, "[", common.node_to_string(v.len), "]", common.node_to_string(v.expr)},
+ a = {pointer_prefix, "[", node_to_string(v.len), "]", node_to_string(v.expr)},
allocator = ast_context.allocator,
)
case SymbolMatrixValue:
@@ -4108,11 +4108,11 @@ get_signature :: proc(
pointer_prefix,
"matrix",
"[",
- common.node_to_string(v.x),
+ node_to_string(v.x),
",",
- common.node_to_string(v.y),
+ node_to_string(v.y),
"]",
- common.node_to_string(v.expr),
+ node_to_string(v.expr),
},
allocator = ast_context.allocator,
)
@@ -4248,7 +4248,7 @@ type_to_string :: proc(ast_context: ^AstContext, expr: ^ast.Expr) -> string {
}
}
- return common.node_to_string(expr)
+ return node_to_string(expr)
}
get_document_position_decls :: proc(decls: []^ast.Stmt, position_context: ^DocumentPositionContext) -> bool {
diff --git a/src/server/ast.odin b/src/server/ast.odin
new file mode 100644
index 0000000..d799e0d
--- /dev/null
+++ b/src/server/ast.odin
@@ -0,0 +1,1159 @@
+#+feature dynamic-literals
+package server
+
+import "core:fmt"
+import "core:log"
+import "core:mem"
+import "core:odin/ast"
+import "core:odin/parser"
+import path "core:path/slashpath"
+import "core:strings"
+
+keyword_map: map[string]bool = {
+ "typeid" = true,
+ "int" = true,
+ "uint" = true,
+ "string" = true,
+ "cstring" = true,
+ "u64" = true,
+ "f32" = true,
+ "f64" = true,
+ "i64" = true,
+ "i128" = true,
+ "i32" = true,
+ "i16" = true,
+ "u16" = true,
+ "bool" = true,
+ "rawptr" = true,
+ "any" = true,
+ "u32" = true,
+ "u128" = true,
+ "b8" = true,
+ "b16" = true,
+ "b32" = true,
+ "b64" = true,
+ "true" = true,
+ "false" = true,
+ "nil" = true,
+ "byte" = true,
+ "u8" = true,
+ "i8" = true,
+ "rune" = true,
+ "f16be" = true,
+ "f16le" = true,
+ "f32be" = true,
+ "f32le" = true,
+ "f64be" = true,
+ "f64le" = true,
+ "i16be" = true,
+ "i16le" = true,
+ "i32be" = true,
+ "i32le" = true,
+ "i64be" = true,
+ "i64le" = true,
+ "u16be" = true,
+ "u16le" = true,
+ "u32be" = true,
+ "u32le" = true,
+ "u64be" = true,
+ "u64le" = true,
+ "i128be" = true,
+ "i128le" = true,
+ "u128be" = true,
+ "u128le" = true,
+ "complex32" = true,
+ "complex64" = true,
+ "complex128" = true,
+ "quaternion64" = true,
+ "quaternion128" = true,
+ "quaternion256" = true,
+ "uintptr" = true,
+}
+
+GlobalExpr :: struct {
+ name: string,
+ name_expr: ^ast.Expr,
+ expr: ^ast.Expr,
+ mutable: bool,
+ docs: ^ast.Comment_Group,
+ attributes: []^ast.Attribute,
+ deprecated: bool,
+ private: parser.Private_Flag,
+ builtin: bool,
+}
+
+get_attribute_objc_type :: proc(attributes: []^ast.Attribute) -> ^ast.Expr {
+ for attribute in attributes {
+ for elem in attribute.elems {
+ if assign, ok := elem.derived.(^ast.Field_Value); ok {
+ if ident, ok := assign.field.derived.(^ast.Ident); ok && ident.name == "objc_type" {
+ return assign.value
+ }
+ }
+ }
+ }
+
+ return nil
+}
+
+get_attribute_objc_name :: proc(attributes: []^ast.Attribute) -> (string, bool) {
+ for attribute in attributes {
+ for elem in attribute.elems {
+ if assign, ok := elem.derived.(^ast.Field_Value); ok {
+ if ident, ok := assign.field.derived.(^ast.Ident); ok && ident.name == "objc_name" {
+ if lit, ok := assign.value.derived.(^ast.Basic_Lit); ok && len(lit.tok.text) > 2 {
+ return lit.tok.text[1:len(lit.tok.text) - 1], true
+ }
+ }
+
+ }
+ }
+ }
+
+ return "", false
+}
+
+get_attribute_objc_class_name :: proc(attributes: []^ast.Attribute) -> (string, bool) {
+ for attribute in attributes {
+ for elem in attribute.elems {
+ if assign, ok := elem.derived.(^ast.Field_Value); ok {
+ if ident, ok := assign.field.derived.(^ast.Ident); ok && ident.name == "objc_class" {
+ if lit, ok := assign.value.derived.(^ast.Basic_Lit); ok && len(lit.tok.text) > 2 {
+ return lit.tok.text[1:len(lit.tok.text) - 1], true
+ }
+ }
+
+ }
+ }
+ }
+
+ return "", false
+}
+
+
+get_attribute_objc_is_class_method :: proc(attributes: []^ast.Attribute) -> bool {
+ for attribute in attributes {
+ for elem in attribute.elems {
+ if assign, ok := elem.derived.(^ast.Field_Value); ok {
+ if ident, ok := assign.field.derived.(^ast.Ident); ok && ident.name == "objc_is_class_method" {
+ if field_value, ok := assign.value.derived.(^ast.Ident); ok && field_value.name == "true" {
+ return true
+ }
+ }
+
+ }
+ }
+ }
+ return false
+}
+
+unwrap_comp_literal :: proc(expr: ^ast.Expr) -> (^ast.Comp_Lit, int, bool) {
+ n := 0
+ expr := expr
+ for expr != nil {
+ if unary, ok := expr.derived.(^ast.Unary_Expr); ok {
+ if unary.op.kind == .And {
+ expr = unary.expr
+ n += 1
+ }
+ } else {
+ break
+ }
+ }
+
+ if expr != nil {
+ if comp_literal, ok := expr.derived.(^ast.Comp_Lit); ok {
+ return comp_literal, n, ok
+ }
+
+ return {}, n, false
+ }
+
+ return {}, n, false
+}
+
+unwrap_pointer_ident :: proc(expr: ^ast.Expr) -> (ast.Ident, int, bool) {
+ n := 0
+ expr := expr
+ for expr != nil {
+ if pointer, ok := expr.derived.(^ast.Pointer_Type); ok {
+ expr = pointer.elem
+ n += 1
+ } else {
+ break
+ }
+ }
+
+ // Check for parapoly specialization
+ if expr != nil {
+ if poly, ok := expr.derived.(^ast.Poly_Type); ok {
+ expr = poly.specialization
+ }
+ }
+
+ // Check for parapoly self
+ if expr != nil {
+ if call, ok := expr.derived.(^ast.Call_Expr); ok {
+ expr = call.expr
+ }
+ }
+
+ if expr != nil {
+ if ident, ok := expr.derived.(^ast.Ident); ok {
+ return ident^, n, ok
+ }
+
+ return {}, n, false
+ }
+
+ return {}, n, false
+}
+
+unwrap_pointer_expr :: proc(expr: ^ast.Expr) -> (^ast.Expr, int, bool) {
+ n := 0
+ expr := expr
+ for expr != nil {
+ if pointer, ok := expr.derived.(^ast.Pointer_Type); ok {
+ expr = pointer.elem
+ n += 1
+ } else {
+ break
+ }
+ }
+
+ if expr == nil {
+ return {}, n, false
+ }
+
+ return expr, n, true
+}
+
+array_is_soa :: proc(array: ast.Array_Type) -> bool {
+ if array.tag != nil {
+ if basic, ok := array.tag.derived.(^ast.Basic_Directive); ok && basic.name == "soa" {
+ return true
+ }
+ }
+ return false
+}
+
+dynamic_array_is_soa :: proc(array: ast.Dynamic_Array_Type) -> bool {
+ if array.tag != nil {
+ if basic, ok := array.tag.derived.(^ast.Basic_Directive); ok && basic.name == "soa" {
+ return true
+ }
+ }
+ return false
+}
+
+expr_contains_poly :: proc(expr: ^ast.Expr) -> bool {
+ if expr == nil {
+ return false
+ }
+
+ visit :: proc(visitor: ^ast.Visitor, node: ^ast.Node) -> ^ast.Visitor {
+ if node == nil {
+ return nil
+ }
+ if _, ok := node.derived.(^ast.Poly_Type); ok {
+ b := cast(^bool)visitor.data
+ b^ = true
+ return nil
+ }
+ return visitor
+ }
+
+ found := false
+
+ visitor := ast.Visitor {
+ visit = visit,
+ data = &found,
+ }
+
+ ast.walk(&visitor, expr)
+
+ return found
+}
+
+is_expr_basic_lit :: proc(expr: ^ast.Expr) -> bool {
+ _, ok := expr.derived.(^ast.Basic_Lit)
+ return ok
+}
+
+collect_value_decl :: proc(
+ exprs: ^[dynamic]GlobalExpr,
+ file: ast.File,
+ file_tags: parser.File_Tags,
+ stmt: ^ast.Node,
+ skip_private: bool,
+) {
+ value_decl, is_value_decl := stmt.derived.(^ast.Value_Decl)
+
+ if !is_value_decl {
+ return
+ }
+
+ global_expr := GlobalExpr {
+ mutable = value_decl.is_mutable,
+ docs = value_decl.docs,
+ attributes = value_decl.attributes[:],
+ private = file_tags.private,
+ }
+
+ for attribute in value_decl.attributes {
+ for elem in attribute.elems {
+ ident: ^ast.Ident
+ value: ast.Any_Node
+
+ #partial switch v in elem.derived {
+ case ^ast.Field_Value:
+ ident = v.field.derived.(^ast.Ident) or_continue
+ value = v.value.derived
+ case ^ast.Ident:
+ ident = v
+ case:
+ continue
+ }
+
+ switch ident.name {
+ case "deprecated":
+ global_expr.deprecated = true
+ case "builtin":
+ global_expr.builtin = true
+ case "private":
+ if val, ok := value.(^ast.Basic_Lit); ok {
+ switch val.tok.text {
+ case "\"file\"":
+ global_expr.private = .File
+ case "\"package\"":
+ global_expr.private = .Package
+ }
+ } else {
+ global_expr.private = .Package
+ }
+ }
+ }
+ }
+
+ if file_tags.ignore {
+ global_expr.private = .File
+ }
+
+ if skip_private && global_expr.private == .File {
+ return
+ }
+
+ for name, i in value_decl.names {
+ global_expr.name = get_ast_node_string(name, file.src)
+ global_expr.name_expr = name
+
+ if value_decl.type != nil {
+ global_expr.expr = value_decl.type
+ append(exprs, global_expr)
+ } else if len(value_decl.values) > i {
+ global_expr.expr = value_decl.values[i]
+ append(exprs, global_expr)
+ }
+ }
+}
+
+collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr {
+ exprs := make([dynamic]GlobalExpr, context.temp_allocator)
+ defer shrink(&exprs)
+
+ file_tags := parser.parse_file_tags(file, context.temp_allocator)
+
+ _next_decl: for decl in file.decls {
+ if value_decl, ok := decl.derived.(^ast.Value_Decl); ok {
+ collect_value_decl(&exprs, file, file_tags, decl, skip_private)
+ } else if when_decl, ok := decl.derived.(^ast.When_Stmt); ok {
+ if when_decl.cond == nil {
+ continue
+ }
+
+ if when_decl.body == nil {
+ continue
+ }
+
+ if resolve_when_condition(when_decl.cond) {
+ if block, ok := when_decl.body.derived.(^ast.Block_Stmt); ok {
+ for stmt in block.stmts {
+ collect_value_decl(&exprs, file, file_tags, stmt, skip_private)
+ }
+ }
+ continue
+ } else {
+ else_stmt := when_decl.else_stmt
+
+ for else_stmt != nil {
+ if else_when, ok := else_stmt.derived.(^ast.When_Stmt); ok {
+ if resolve_when_condition(else_when.cond) {
+ if block, ok := else_when.body.derived.(^ast.Block_Stmt); ok {
+ for stmt in block.stmts {
+ collect_value_decl(&exprs, file, file_tags, stmt, skip_private)
+ }
+ }
+ continue _next_decl
+ }
+ else_stmt = else_when.else_stmt
+ } else {
+ continue _next_decl
+ }
+ }
+ }
+
+
+ } else if foreign_decl, ok := decl.derived.(^ast.Foreign_Block_Decl); ok {
+ if foreign_decl.body == nil {
+ continue
+ }
+
+ if block, ok := foreign_decl.body.derived.(^ast.Block_Stmt); ok {
+ for stmt in block.stmts {
+ collect_value_decl(&exprs, file, file_tags, stmt, skip_private)
+ }
+ }
+ }
+ }
+
+ return exprs[:]
+}
+
+get_ast_node_string :: proc(node: ^ast.Node, src: string) -> string {
+ return string(src[node.pos.offset:node.end.offset])
+}
+
+get_doc :: proc(comment: ^ast.Comment_Group, allocator: mem.Allocator) -> string {
+ if comment != nil {
+ tmp: string
+
+ for doc in comment.list {
+ tmp = strings.concatenate({tmp, "\n", doc.text}, context.temp_allocator)
+ }
+
+ if tmp != "" {
+ no_lines, _ := strings.replace_all(tmp, "//", "", context.temp_allocator)
+ no_begin_comments, _ := strings.replace_all(no_lines, "/*", "", context.temp_allocator)
+ no_end_comments, _ := strings.replace_all(no_begin_comments, "*/", "", context.temp_allocator)
+ return strings.clone(no_end_comments, allocator)
+ }
+ }
+
+ return ""
+}
+
+free_ast :: proc {
+ free_ast_node,
+ free_ast_array,
+ free_ast_dynamic_array,
+ free_ast_comment,
+}
+
+free_ast_comment :: proc(a: ^ast.Comment_Group, allocator: mem.Allocator) {
+ if a == nil {
+ return
+ }
+
+ if len(a.list) > 0 {
+ delete(a.list, allocator)
+ }
+
+ free(a, allocator)
+}
+
+free_ast_array :: proc(array: $A/[]^$T, allocator: mem.Allocator) {
+ for elem, i in array {
+ free_ast(elem, allocator)
+ }
+ delete(array, allocator)
+}
+
+free_ast_dynamic_array :: proc(array: $A/[dynamic]^$T, allocator: mem.Allocator) {
+ for elem, i in array {
+ free_ast(elem, allocator)
+ }
+
+ delete(array)
+}
+
+free_ast_node :: proc(node: ^ast.Node, allocator: mem.Allocator) {
+ using ast
+
+ if node == nil {
+ return
+ }
+
+ if node.derived != nil do #partial switch n in node.derived {
+ case ^Bad_Expr:
+ case ^Ident:
+ case ^Implicit:
+ case ^Undef:
+ case ^Basic_Directive:
+ case ^Basic_Lit:
+ case ^Ellipsis:
+ free_ast(n.expr, allocator)
+ case ^Proc_Lit:
+ free_ast(n.type, allocator)
+ free_ast(n.body, allocator)
+ free_ast(n.where_clauses, allocator)
+ case ^Comp_Lit:
+ free_ast(n.type, allocator)
+ free_ast(n.elems, allocator)
+ case ^Tag_Expr:
+ free_ast(n.expr, allocator)
+ case ^Unary_Expr:
+ free_ast(n.expr, allocator)
+ case ^Binary_Expr:
+ free_ast(n.left, allocator)
+ free_ast(n.right, allocator)
+ case ^Paren_Expr:
+ free_ast(n.expr, allocator)
+ case ^Call_Expr:
+ free_ast(n.expr, allocator)
+ free_ast(n.args, allocator)
+ case ^Selector_Expr:
+ free_ast(n.expr, allocator)
+ free_ast(n.field, allocator)
+ case ^Implicit_Selector_Expr:
+ free_ast(n.field, allocator)
+ case ^Index_Expr:
+ free_ast(n.expr, allocator)
+ free_ast(n.index, allocator)
+ case ^Deref_Expr:
+ free_ast(n.expr, allocator)
+ case ^Slice_Expr:
+ free_ast(n.expr, allocator)
+ free_ast(n.low, allocator)
+ free_ast(n.high, allocator)
+ case ^Field_Value:
+ free_ast(n.field, allocator)
+ free_ast(n.value, allocator)
+ case ^Ternary_If_Expr:
+ free_ast(n.x, allocator)
+ free_ast(n.cond, allocator)
+ free_ast(n.y, allocator)
+ case ^Ternary_When_Expr:
+ free_ast(n.x, allocator)
+ free_ast(n.cond, allocator)
+ free_ast(n.y, allocator)
+ case ^Type_Assertion:
+ free_ast(n.expr, allocator)
+ free_ast(n.type, allocator)
+ case ^Type_Cast:
+ free_ast(n.type, allocator)
+ free_ast(n.expr, allocator)
+ case ^Auto_Cast:
+ free_ast(n.expr, allocator)
+ case ^Bad_Stmt:
+ case ^Empty_Stmt:
+ case ^Expr_Stmt:
+ free_ast(n.expr, allocator)
+ case ^Tag_Stmt:
+ r := cast(^Expr_Stmt)node
+ free_ast(r.expr, allocator)
+ case ^Assign_Stmt:
+ free_ast(n.lhs, allocator)
+ free_ast(n.rhs, allocator)
+ case ^Block_Stmt:
+ free_ast(n.label, allocator)
+ free_ast(n.stmts, allocator)
+ case ^If_Stmt:
+ free_ast(n.label, allocator)
+ free_ast(n.init, allocator)
+ free_ast(n.cond, allocator)
+ free_ast(n.body, allocator)
+ free_ast(n.else_stmt, allocator)
+ case ^When_Stmt:
+ free_ast(n.cond, allocator)
+ free_ast(n.body, allocator)
+ free_ast(n.else_stmt, allocator)
+ case ^Return_Stmt:
+ free_ast(n.results, allocator)
+ case ^Defer_Stmt:
+ free_ast(n.stmt, allocator)
+ case ^For_Stmt:
+ free_ast(n.label, allocator)
+ free_ast(n.init, allocator)
+ free_ast(n.cond, allocator)
+ free_ast(n.post, allocator)
+ free_ast(n.body, allocator)
+ case ^Range_Stmt:
+ free_ast(n.label, allocator)
+ free_ast(n.vals, allocator)
+ free_ast(n.expr, allocator)
+ free_ast(n.body, allocator)
+ case ^Case_Clause:
+ free_ast(n.list, allocator)
+ free_ast(n.body, allocator)
+ case ^Switch_Stmt:
+ free_ast(n.label, allocator)
+ free_ast(n.init, allocator)
+ free_ast(n.cond, allocator)
+ free_ast(n.body, allocator)
+ case ^Type_Switch_Stmt:
+ free_ast(n.label, allocator)
+ free_ast(n.tag, allocator)
+ free_ast(n.expr, allocator)
+ free_ast(n.body, allocator)
+ case ^Branch_Stmt:
+ free_ast(n.label, allocator)
+ case ^Using_Stmt:
+ free_ast(n.list, allocator)
+ case ^Bad_Decl:
+ case ^Value_Decl:
+ free_ast(n.attributes, allocator)
+ free_ast(n.names, allocator)
+ free_ast(n.type, allocator)
+ free_ast(n.values, allocator)
+ case ^Package_Decl:
+ case ^Import_Decl:
+ case ^Foreign_Block_Decl:
+ free_ast(n.attributes, allocator)
+ free_ast(n.foreign_library, allocator)
+ free_ast(n.body, allocator)
+ case ^Foreign_Import_Decl:
+ free_ast(n.name, allocator)
+ free_ast(n.attributes, allocator)
+ case ^Proc_Group:
+ free_ast(n.args, allocator)
+ case ^Attribute:
+ free_ast(n.elems, allocator)
+ case ^Field:
+ free_ast(n.names, allocator)
+ free_ast(n.type, allocator)
+ free_ast(n.default_value, allocator)
+ //free_ast(n.docs);
+ //free_ast(n.comment);
+ case ^Field_List:
+ free_ast(n.list, allocator)
+ case ^Typeid_Type:
+ free_ast(n.specialization, allocator)
+ case ^Helper_Type:
+ free_ast(n.type, allocator)
+ case ^Distinct_Type:
+ free_ast(n.type, allocator)
+ case ^Poly_Type:
+ free_ast(n.type, allocator)
+ free_ast(n.specialization, allocator)
+ case ^Proc_Type:
+ free_ast(n.params, allocator)
+ free_ast(n.results, allocator)
+ case ^Pointer_Type:
+ free_ast(n.elem, allocator)
+ case ^Array_Type:
+ free_ast(n.len, allocator)
+ free_ast(n.elem, allocator)
+ free_ast(n.tag, allocator)
+ case ^Dynamic_Array_Type:
+ free_ast(n.elem, allocator)
+ free_ast(n.tag, allocator)
+ case ^Struct_Type:
+ free_ast(n.poly_params, allocator)
+ free_ast(n.align, allocator)
+ free_ast(n.fields, allocator)
+ free_ast(n.where_clauses, allocator)
+ case ^Union_Type:
+ free_ast(n.poly_params, allocator)
+ free_ast(n.align, allocator)
+ free_ast(n.variants, allocator)
+ free_ast(n.where_clauses, allocator)
+ case ^Enum_Type:
+ free_ast(n.base_type, allocator)
+ free_ast(n.fields, allocator)
+ case ^Bit_Set_Type:
+ free_ast(n.elem, allocator)
+ free_ast(n.underlying, allocator)
+ case ^Map_Type:
+ free_ast(n.key, allocator)
+ free_ast(n.value, allocator)
+ case ^Multi_Pointer_Type:
+ free_ast(n.elem, allocator)
+ case ^Matrix_Type:
+ free_ast(n.elem, allocator)
+ case ^Relative_Type:
+ free_ast(n.tag, allocator)
+ free_ast(n.type, allocator)
+ case ^Bit_Field_Type:
+ free_ast(n.backing_type, allocator)
+ for field in n.fields do free_ast(field, allocator)
+ case ^Bit_Field_Field:
+ free_ast(n.name, allocator)
+ free_ast(n.type, allocator)
+ free_ast(n.bit_size, allocator)
+ case ^ast.Or_Else_Expr:
+ free_ast(n.x, allocator)
+ free_ast(n.y, allocator)
+ case ^ast.Or_Return_Expr:
+ free_ast(n.expr, allocator)
+ case:
+ panic(fmt.aprintf("free Unhandled node kind: %v", node.derived))
+ }
+
+ mem.free(node, allocator)
+}
+
+free_ast_file :: proc(file: ast.File, allocator := context.allocator) {
+ for decl in file.decls {
+ free_ast(decl, allocator)
+ }
+
+ free_ast(file.pkg_decl, allocator)
+
+ for comment in file.comments {
+ free_ast(comment, allocator)
+ }
+
+ delete(file.comments)
+ delete(file.imports)
+ delete(file.decls)
+}
+
+node_equal :: proc {
+ node_equal_node,
+ node_equal_array,
+ node_equal_dynamic_array,
+}
+
+node_equal_array :: proc(a, b: $A/[]^$T) -> bool {
+ ret := true
+
+ if len(a) != len(b) {
+ return false
+ }
+
+ for elem, i in a {
+ ret &= node_equal(elem, b[i])
+ }
+
+ return ret
+}
+
+node_equal_dynamic_array :: proc(a, b: $A/[dynamic]^$T) -> bool {
+ ret := true
+
+ if len(a) != len(b) {
+ return false
+ }
+
+ for elem, i in a {
+ ret &= node_equal(elem, b[i])
+ }
+
+ return ret
+}
+
+node_equal_node :: proc(a, b: ^ast.Node) -> bool {
+ using ast
+
+ if a == nil || b == nil {
+ return false
+ }
+
+ #partial switch m in b.derived {
+ case ^Bad_Expr:
+ if n, ok := a.derived.(^Bad_Expr); ok {
+ return true
+ }
+ case ^Ident:
+ if n, ok := a.derived.(^Ident); ok {
+ return true
+ //return n.name == m.name;
+ }
+ case ^Implicit:
+ if n, ok := a.derived.(^Implicit); ok {
+ return true
+ }
+ case ^Undef:
+ if n, ok := a.derived.(^Undef); ok {
+ return true
+ }
+ case ^Basic_Lit:
+ if n, ok := a.derived.(^Basic_Lit); ok {
+ return true
+ }
+ case ^Poly_Type:
+ return true
+ case ^Ellipsis:
+ if n, ok := a.derived.(^Ellipsis); ok {
+ return node_equal(n.expr, m.expr)
+ }
+ case ^Tag_Expr:
+ if n, ok := a.derived.(^Tag_Expr); ok {
+ return node_equal(n.expr, m.expr)
+ }
+ case ^Unary_Expr:
+ if n, ok := a.derived.(^Unary_Expr); ok {
+ return node_equal(n.expr, m.expr)
+ }
+ case ^Binary_Expr:
+ if n, ok := a.derived.(^Binary_Expr); ok {
+ ret := node_equal(n.left, m.left)
+ ret &= node_equal(n.right, m.right)
+ return ret
+ }
+ case ^Paren_Expr:
+ if n, ok := a.derived.(^Paren_Expr); ok {
+ return node_equal(n.expr, m.expr)
+ }
+ case ^Selector_Expr:
+ if n, ok := a.derived.(^Selector_Expr); ok {
+ ret := node_equal(n.expr, m.expr)
+ ret &= node_equal(n.field, m.field)
+ return ret
+ }
+ case ^Slice_Expr:
+ if n, ok := a.derived.(^Slice_Expr); ok {
+ ret := node_equal(n.expr, m.expr)
+ ret &= node_equal(n.low, m.low)
+ ret &= node_equal(n.high, m.high)
+ return ret
+ }
+ case ^Distinct_Type:
+ if n, ok := a.derived.(^Distinct_Type); ok {
+ return node_equal(n.type, m.type)
+ }
+ case ^Proc_Type:
+ if n, ok := a.derived.(^Proc_Type); ok {
+ ret := node_equal(n.params, m.params)
+ ret &= node_equal(n.results, m.results)
+ return ret
+ }
+ case ^Pointer_Type:
+ if n, ok := a.derived.(^Pointer_Type); ok {
+ return node_equal(n.elem, m.elem)
+ }
+ case ^Array_Type:
+ if n, ok := a.derived.(^Array_Type); ok {
+ ret := node_equal(n.elem, m.elem)
+ if n.len != nil && m.len != nil {
+ ret &= node_equal(n.len, m.len)
+ }
+ return ret
+ }
+ case ^Dynamic_Array_Type:
+ if n, ok := a.derived.(^Dynamic_Array_Type); ok {
+ return node_equal(n.elem, m.elem)
+ }
+ case ^ast.Multi_Pointer_Type:
+ if n, ok := a.derived.(^Multi_Pointer_Type); ok {
+ return node_equal(n.elem, m.elem)
+ }
+ case ^Struct_Type:
+ if n, ok := a.derived.(^Struct_Type); ok {
+ ret := node_equal(n.poly_params, m.poly_params)
+ ret &= node_equal(n.align, m.align)
+ ret &= node_equal(n.fields, m.fields)
+ return ret
+ }
+ case ^Field:
+ if n, ok := a.derived.(^Field); ok {
+ ret := node_equal(n.names, m.names)
+ ret &= node_equal(n.type, m.type)
+ ret &= node_equal(n.default_value, m.default_value)
+ return ret
+ }
+ case ^Field_List:
+ if n, ok := a.derived.(^Field_List); ok {
+ return node_equal(n.list, m.list)
+ }
+ case ^Field_Value:
+ if n, ok := a.derived.(^Field_Value); ok {
+ ret := node_equal(n.field, m.field)
+ ret &= node_equal(n.value, m.value)
+ return ret
+ }
+ case ^Union_Type:
+ if n, ok := a.derived.(^Union_Type); ok {
+ ret := node_equal(n.poly_params, m.poly_params)
+ ret &= node_equal(n.align, m.align)
+ ret &= node_equal(n.variants, m.variants)
+ return ret
+ }
+ case ^Enum_Type:
+ if n, ok := a.derived.(^Enum_Type); ok {
+ ret := node_equal(n.base_type, m.base_type)
+ ret &= node_equal(n.fields, m.fields)
+ return ret
+ }
+ case ^Bit_Set_Type:
+ if n, ok := a.derived.(^Bit_Set_Type); ok {
+ ret := node_equal(n.elem, m.elem)
+ ret &= node_equal(n.underlying, m.underlying)
+ return ret
+ }
+ case ^Map_Type:
+ if n, ok := a.derived.(^Map_Type); ok {
+ ret := node_equal(n.key, m.key)
+ ret &= node_equal(n.value, m.value)
+ return ret
+ }
+ case ^Call_Expr:
+ if n, ok := a.derived.(^Call_Expr); ok {
+ ret := node_equal(n.expr, m.expr)
+ ret &= node_equal(n.args, m.args)
+ return ret
+ }
+ case ^Bit_Field_Type:
+ if n, ok := a.derived.(^Bit_Field_Type); ok {
+ if len(n.fields) != len(m.fields) do return false
+ ret := node_equal(n.backing_type, m.backing_type)
+ for i in 0 ..< len(n.fields) {
+ ret &= node_equal(n.fields[i], m.fields[i])
+ }
+ return ret
+ }
+ case ^Bit_Field_Field:
+ if n, ok := a.derived.(^Bit_Field_Field); ok {
+ ret := node_equal(n.name, m.name)
+ ret &= node_equal(n.type, m.type)
+ ret &= node_equal(n.bit_size, m.bit_size)
+ return ret
+ }
+ case ^Typeid_Type:
+ return true
+ case:
+ }
+
+ return false
+}
+
+/*
+ Returns the string representation of a type. This allows us to print the signature without storing it in the indexer as a string(saving memory).
+*/
+
+node_to_string :: proc(node: ^ast.Node, remove_pointers := false) -> string {
+ builder := strings.builder_make(context.temp_allocator)
+
+ build_string(node, &builder, remove_pointers)
+
+ return strings.to_string(builder)
+}
+
+build_string :: proc {
+ build_string_ast_array,
+ build_string_dynamic_array,
+ build_string_node,
+}
+
+build_string_dynamic_array :: proc(array: $A/[]^$T, builder: ^strings.Builder, remove_pointers: bool) {
+ for elem, i in array {
+ build_string(elem, builder, remove_pointers)
+ }
+}
+
+build_string_ast_array :: proc(array: $A/[dynamic]^$T, builder: ^strings.Builder, remove_pointers: bool) {
+ for elem, i in array {
+ build_string(elem, builder, remove_pointers)
+ }
+}
+
+build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder, remove_pointers: bool) {
+ using ast
+
+ if node == nil {
+ return
+ }
+
+ #partial switch n in node.derived {
+ case ^Bad_Expr:
+ case ^Ident:
+ if strings.contains(n.name, "/") {
+ strings.write_string(builder, path.base(n.name, false, context.temp_allocator))
+ } else {
+ strings.write_string(builder, n.name)
+ }
+ case ^Implicit:
+ strings.write_string(builder, n.tok.text)
+ case ^Undef:
+ case ^Basic_Lit:
+ strings.write_string(builder, n.tok.text)
+ case ^Basic_Directive:
+ strings.write_string(builder, "#")
+ strings.write_string(builder, n.name)
+ case ^Implicit_Selector_Expr:
+ strings.write_string(builder, ".")
+ build_string(n.field, builder, remove_pointers)
+ case ^Ellipsis:
+ strings.write_string(builder, "..")
+ build_string(n.expr, builder, remove_pointers)
+ case ^Proc_Lit:
+ build_string(n.type, builder, remove_pointers)
+ build_string(n.body, builder, remove_pointers)
+ case ^Comp_Lit:
+ build_string(n.type, builder, remove_pointers)
+ strings.write_string(builder, "{")
+ for elem, i in n.elems {
+ build_string(elem, builder, remove_pointers)
+ if len(n.elems) - 1 != i {
+ strings.write_string(builder, ", ")
+ }
+ }
+ strings.write_string(builder, "}")
+ case ^Tag_Expr:
+ build_string(n.expr, builder, remove_pointers)
+ case ^Unary_Expr:
+ strings.write_string(builder, n.op.text)
+ build_string(n.expr, builder, remove_pointers)
+ case ^Binary_Expr:
+ build_string(n.left, builder, remove_pointers)
+ strings.write_string(builder, " ")
+ strings.write_string(builder, n.op.text)
+ strings.write_string(builder, " ")
+ build_string(n.right, builder, remove_pointers)
+ case ^Paren_Expr:
+ strings.write_string(builder, "(")
+ build_string(n.expr, builder, remove_pointers)
+ strings.write_string(builder, ")")
+ case ^Call_Expr:
+ build_string(n.expr, builder, remove_pointers)
+ strings.write_string(builder, "(")
+ for arg, i in n.args {
+ build_string(arg, builder, remove_pointers)
+ if len(n.args) - 1 != i {
+ strings.write_string(builder, ", ")
+ }
+ }
+ strings.write_string(builder, ")")
+ case ^Selector_Expr:
+ build_string(n.expr, builder, remove_pointers)
+ strings.write_string(builder, ".")
+ build_string(n.field, builder, remove_pointers)
+ case ^Index_Expr:
+ build_string(n.expr, builder, remove_pointers)
+ strings.write_string(builder, "[")
+ build_string(n.index, builder, remove_pointers)
+ strings.write_string(builder, "]")
+ case ^Deref_Expr:
+ build_string(n.expr, builder, remove_pointers)
+ case ^Slice_Expr:
+ build_string(n.expr, builder, remove_pointers)
+ build_string(n.low, builder, remove_pointers)
+ build_string(n.high, builder, remove_pointers)
+ case ^Field_Value:
+ build_string(n.field, builder, remove_pointers)
+ strings.write_string(builder, ": ")
+ build_string(n.value, builder, remove_pointers)
+ case ^Type_Cast:
+ build_string(n.type, builder, remove_pointers)
+ build_string(n.expr, builder, remove_pointers)
+ case ^Bad_Stmt:
+ case ^Bad_Decl:
+ case ^Attribute:
+ build_string(n.elems, builder, remove_pointers)
+ case ^Field:
+ for name, i in n.names {
+ build_string(name, builder, remove_pointers)
+ if len(n.names) - 1 != i {
+ strings.write_string(builder, ", ")
+ }
+ }
+
+ if len(n.names) > 0 && n.type != nil {
+ strings.write_string(builder, ": ")
+ build_string(n.type, builder, remove_pointers)
+
+ if n.default_value != nil && n.type != nil {
+ strings.write_string(builder, " = ")
+ }
+
+ } else if len(n.names) > 0 && n.default_value != nil {
+ strings.write_string(builder, " := ")
+ } else {
+ build_string(n.type, builder, remove_pointers)
+ }
+
+ build_string(n.default_value, builder, remove_pointers)
+ case ^Field_List:
+ for field, i in n.list {
+ build_string(field, builder, remove_pointers)
+ if len(n.list) - 1 != i {
+ strings.write_string(builder, ",")
+ }
+ }
+ case ^Typeid_Type:
+ strings.write_string(builder, "typeid")
+ build_string(n.specialization, builder, remove_pointers)
+ case ^Helper_Type:
+ build_string(n.type, builder, remove_pointers)
+ case ^Distinct_Type:
+ build_string(n.type, builder, remove_pointers)
+ case ^Poly_Type:
+ strings.write_string(builder, "$")
+
+ build_string(n.type, builder, remove_pointers)
+
+ if n.specialization != nil {
+ strings.write_string(builder, "/")
+ build_string(n.specialization, builder, remove_pointers)
+ }
+ case ^Proc_Type:
+ strings.write_string(builder, "proc(")
+ build_string(n.params, builder, remove_pointers)
+ strings.write_string(builder, ")")
+ if n.results != nil {
+ strings.write_string(builder, " -> ")
+ build_string(n.results, builder, remove_pointers)
+ }
+ case ^Pointer_Type:
+ if !remove_pointers {
+ strings.write_string(builder, "^")
+ }
+ build_string(n.elem, builder, remove_pointers)
+ case ^Array_Type:
+ strings.write_string(builder, "[")
+ build_string(n.len, builder, remove_pointers)
+ strings.write_string(builder, "]")
+ build_string(n.elem, builder, remove_pointers)
+ case ^Dynamic_Array_Type:
+ strings.write_string(builder, "[dynamic]")
+ build_string(n.elem, builder, remove_pointers)
+ case ^Struct_Type:
+ build_string(n.poly_params, builder, remove_pointers)
+ build_string(n.align, builder, remove_pointers)
+ build_string(n.fields, builder, remove_pointers)
+ case ^Union_Type:
+ build_string(n.poly_params, builder, remove_pointers)
+ build_string(n.align, builder, remove_pointers)
+ build_string(n.variants, builder, remove_pointers)
+ case ^Enum_Type:
+ build_string(n.base_type, builder, remove_pointers)
+ build_string(n.fields, builder, remove_pointers)
+ case ^Bit_Set_Type:
+ strings.write_string(builder, "bit_set")
+ strings.write_string(builder, "[")
+ build_string(n.elem, builder, remove_pointers)
+ strings.write_string(builder, "]")
+ build_string(n.underlying, builder, remove_pointers)
+ case ^Map_Type:
+ strings.write_string(builder, "map")
+ strings.write_string(builder, "[")
+ build_string(n.key, builder, remove_pointers)
+ strings.write_string(builder, "]")
+ build_string(n.value, builder, remove_pointers)
+ case ^ast.Multi_Pointer_Type:
+ strings.write_string(builder, "[^]")
+ build_string(n.elem, builder, remove_pointers)
+ case ^ast.Bit_Field_Type:
+ strings.write_string(builder, "bit_field")
+ build_string(n.backing_type, builder, remove_pointers)
+ for field, i in n.fields {
+ build_string(field, builder, remove_pointers)
+ if len(n.fields) - 1 != i {
+ strings.write_string(builder, ",")
+ }
+ }
+ case ^ast.Bit_Field_Field:
+ build_string(n.name, builder, remove_pointers)
+ strings.write_string(builder, ": ")
+ build_string(n.type, builder, remove_pointers)
+ strings.write_string(builder, " | ")
+ build_string(n.bit_size, builder, remove_pointers)
+ }
+}
+
+repeat :: proc(value: string, count: int, allocator := context.allocator) -> string {
+ if count <= 0 {
+ return ""
+ }
+ return strings.repeat(value, count, allocator)
+}
diff --git a/src/server/collector.odin b/src/server/collector.odin
index 037f43a..f29f3aa 100644
--- a/src/server/collector.odin
+++ b/src/server/collector.odin
@@ -368,7 +368,7 @@ collect_method :: proc(collection: ^SymbolCollection, symbol: Symbol) {
return
}
- expr, _, ok := common.unwrap_pointer_ident(value.arg_types[0].type)
+ expr, _, ok := unwrap_pointer_ident(value.arg_types[0].type)
if !ok {
return
@@ -406,9 +406,9 @@ collect_objc :: proc(collection: ^SymbolCollection, attributes: []^ast.Attribute
pkg := &collection.packages[symbol.pkg]
if value, ok := symbol.value.(SymbolProcedureValue); ok {
- objc_name, found_objc_name := common.get_attribute_objc_name(attributes)
+ objc_name, found_objc_name := get_attribute_objc_name(attributes)
- if objc_type := common.get_attribute_objc_type(attributes); objc_type != nil && found_objc_name {
+ if objc_type := get_attribute_objc_type(attributes); objc_type != nil && found_objc_name {
if struct_ident, ok := objc_type.derived.(^ast.Ident); ok {
struct_name := get_index_unique_string_collection(collection, struct_ident.name)
@@ -446,7 +446,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
directory := path.dir(forward, context.temp_allocator)
package_map := get_package_mapping(file, collection.config, directory)
- exprs := common.collect_globals(file, true)
+ exprs := collect_globals(file, true)
collect_imports(collection, file)
@@ -492,9 +492,9 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
)
}
- if _, is_objc := common.get_attribute_objc_name(expr.attributes); is_objc {
+ if _, is_objc := get_attribute_objc_name(expr.attributes); is_objc {
symbol.flags |= {.ObjC}
- if common.get_attribute_objc_is_class_method(expr.attributes) {
+ if get_attribute_objc_is_class_method(expr.attributes) {
symbol.flags |= {.ObjCIsClassMethod}
}
}
@@ -521,9 +521,9 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
symbol.value = collect_struct_fields(collection, v^, package_map, file)
symbol.signature = "struct"
- if _, is_objc := common.get_attribute_objc_class_name(expr.attributes); is_objc {
+ if _, is_objc := get_attribute_objc_class_name(expr.attributes); is_objc {
symbol.flags |= {.ObjC}
- if common.get_attribute_objc_is_class_method(expr.attributes) {
+ if get_attribute_objc_is_class_method(expr.attributes) {
symbol.flags |= {.ObjCIsClassMethod}
}
}
@@ -605,7 +605,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
symbol.range = common.get_token_range(expr.name_expr, file.src)
symbol.name = get_index_unique_string(collection, name)
symbol.type = token_type
- symbol.doc = common.get_doc(expr.docs, collection.allocator)
+ symbol.doc = get_doc(expr.docs, collection.allocator)
if expr.builtin || strings.contains(uri, "builtin.odin") {
symbol.pkg = "$builtin"
diff --git a/src/server/completion.odin b/src/server/completion.odin
index df4c260..31c21f5 100644
--- a/src/server/completion.odin
+++ b/src/server/completion.odin
@@ -282,7 +282,7 @@ get_comp_lit_completion :: proc(
item := CompletionItem {
label = name,
kind = .Field,
- detail = fmt.tprintf("%v.%v: %v", symbol.name, name, common.node_to_string(v.types[i])),
+ detail = fmt.tprintf("%v.%v: %v", symbol.name, name, node_to_string(v.types[i])),
documentation = resolved.doc,
}
@@ -305,7 +305,7 @@ get_comp_lit_completion :: proc(
item := CompletionItem {
label = name,
kind = .Field,
- detail = fmt.tprintf("%v.%v: %v", symbol.name, name, common.node_to_string(v.types[i])),
+ detail = fmt.tprintf("%v.%v: %v", symbol.name, name, node_to_string(v.types[i])),
documentation = resolved.doc,
}
@@ -415,7 +415,7 @@ get_selector_completion :: proc(
item := CompletionItem {
label = fmt.tprintf("%v%v", field, k),
kind = .Property,
- detail = fmt.tprintf("%v%v: %v", field, k, common.node_to_string(v.expr)),
+ detail = fmt.tprintf("%v%v: %v", field, k, node_to_string(v.expr)),
}
append(&items, item)
}
@@ -432,7 +432,7 @@ get_selector_completion :: proc(
item := CompletionItem {
label = fmt.tprintf("%v%v", field, k),
kind = .Property,
- detail = fmt.tprintf("%v%v: %v", field, k, common.node_to_string(v.expr)),
+ detail = fmt.tprintf("%v%v: %v", field, k, node_to_string(v.expr)),
}
append(&items, item)
}
@@ -449,7 +449,7 @@ get_selector_completion :: proc(
item := CompletionItem {
label = fmt.tprintf("%v%v", field, k),
kind = .Property,
- detail = fmt.tprintf("%v%v: [%v]%v", field, k, containsColor, common.node_to_string(v.expr)),
+ detail = fmt.tprintf("%v%v: [%v]%v", field, k, containsColor, node_to_string(v.expr)),
}
append(&items, item)
}
@@ -464,7 +464,7 @@ get_selector_completion :: proc(
item := CompletionItem {
label = fmt.tprintf("%v%v", field, k),
kind = .Property,
- detail = fmt.tprintf("%v%v: [%v]%v", field, k, containsCoord, common.node_to_string(v.expr)),
+ detail = fmt.tprintf("%v%v: [%v]%v", field, k, containsCoord, node_to_string(v.expr)),
}
append(&items, item)
}
@@ -493,15 +493,15 @@ get_selector_completion :: proc(
is_selector {
item.label = fmt.aprintf(
"(%v%v)",
- common.repeat("^", symbol.pointers, context.temp_allocator),
- common.node_to_string(type, true),
+ repeat("^", symbol.pointers, context.temp_allocator),
+ node_to_string(type, true),
)
} else {
item.label = fmt.aprintf(
"(%v%v.%v)",
- common.repeat("^", symbol.pointers, context.temp_allocator),
+ repeat("^", symbol.pointers, context.temp_allocator),
get_symbol_pkg_name(ast_context, symbol),
- common.node_to_string(type, true),
+ node_to_string(type, true),
)
}
@@ -603,7 +603,7 @@ get_selector_completion :: proc(
item := CompletionItem {
label = symbol.name,
kind = .Field,
- detail = fmt.tprintf("%v: %v", name, common.node_to_string(v.types[i])),
+ detail = fmt.tprintf("%v: %v", name, node_to_string(v.types[i])),
documentation = symbol.doc,
}
@@ -640,7 +640,7 @@ get_selector_completion :: proc(
item := CompletionItem {
label = symbol.name,
kind = .Field,
- detail = fmt.tprintf("%v: %v", name, common.node_to_string(v.types[i])),
+ detail = fmt.tprintf("%v: %v", name, node_to_string(v.types[i])),
documentation = symbol.doc,
}
@@ -1380,7 +1380,7 @@ get_identifier_completion :: proc(
}
}
- for keyword, _ in common.keyword_map {
+ for keyword, _ in keyword_map {
symbol := Symbol {
name = keyword,
type = .Keyword,
@@ -1643,15 +1643,11 @@ get_type_switch_completion :: proc(
}
if symbol.pkg == ast_context.document_package {
- item.label = fmt.aprintf(
- "%v%v",
- common.repeat("^", symbol.pointers, context.temp_allocator),
- name,
- )
+ item.label = fmt.aprintf("%v%v", repeat("^", symbol.pointers, context.temp_allocator), name)
} else {
item.label = fmt.aprintf(
"%v%v.%v",
- common.repeat("^", symbol.pointers, context.temp_allocator),
+ repeat("^", symbol.pointers, context.temp_allocator),
get_symbol_pkg_name(ast_context, symbol),
name,
)
@@ -1734,7 +1730,7 @@ append_magic_map_completion :: proc(
symbol_str := get_expression_string_from_position_context(position_context)
deref_suffix := ""
if symbol.pointers > 1 {
- deref_suffix = common.repeat("^", symbol.pointers - 1, context.temp_allocator)
+ deref_suffix = repeat("^", symbol.pointers - 1, context.temp_allocator)
}
dereferenced_symbol_str := fmt.tprint(symbol_str, deref_suffix, sep = "")
@@ -1790,7 +1786,7 @@ append_magic_map_completion :: proc(
suffix := ""
if symbol.pointers > 0 {
prefix = ""
- suffix = common.repeat("^", symbol.pointers - 1, context.temp_allocator)
+ suffix = repeat("^", symbol.pointers - 1, context.temp_allocator)
}
ptr_symbol_str := fmt.tprint(prefix, symbol_str, suffix, sep = "")
@@ -1879,7 +1875,7 @@ append_magic_array_like_completion :: proc(
symbol_str := get_expression_string_from_position_context(position_context)
deref_suffix := ""
if symbol.pointers > 1 {
- deref_suffix = common.repeat("^", symbol.pointers - 1, context.temp_allocator)
+ deref_suffix = repeat("^", symbol.pointers - 1, context.temp_allocator)
}
dereferenced_symbol_str := fmt.tprint(symbol_str, deref_suffix, sep = "")
@@ -1950,7 +1946,7 @@ append_magic_array_like_completion :: proc(
suffix := ""
if symbol.pointers > 0 {
prefix = ""
- suffix = common.repeat("^", symbol.pointers - 1, context.temp_allocator)
+ suffix = repeat("^", symbol.pointers - 1, context.temp_allocator)
}
ptr_symbol_str := fmt.tprint(prefix, symbol_str, suffix, sep = "")
diff --git a/src/server/definition.odin b/src/server/definition.odin
index e7cd8a1..fbcbcf8 100644
--- a/src/server/definition.odin
+++ b/src/server/definition.odin
@@ -79,7 +79,8 @@ get_definition_location :: proc(document: ^Document, position: common.Position)
}
} else if position_context.selector_expr != nil {
//if the base selector is the client wants to go to.
- if position_in_node(position_context.selector, position_context.position) && position_context.identifier != nil {
+ if position_in_node(position_context.selector, position_context.position) &&
+ position_context.identifier != nil {
ident := position_context.identifier.derived.(^ast.Ident)
if resolved, ok := resolve_location_identifier(&ast_context, ident^); ok {
location.range = resolved.range
@@ -106,7 +107,7 @@ get_definition_location :: proc(document: ^Document, position: common.Position)
}
} else if position_context.field_value != nil &&
position_context.comp_lit != nil &&
- !common.is_expr_basic_lit(position_context.field_value.field) &&
+ !is_expr_basic_lit(position_context.field_value.field) &&
position_in_node(position_context.field_value.field, position_context.position) {
if resolved, ok := resolve_location_comp_lit_field(&ast_context, &position_context); ok {
location.range = resolved.range
diff --git a/src/server/generics.odin b/src/server/generics.odin
index 769a925..db7ad88 100644
--- a/src/server/generics.odin
+++ b/src/server/generics.odin
@@ -32,7 +32,7 @@ resolve_poly :: proc(
type: ^ast.Expr
poly_node := poly_node
- poly_node, _, _ = common.unwrap_pointer_expr(poly_node)
+ poly_node, _, _ = unwrap_pointer_expr(poly_node)
#partial switch v in poly_node.derived {
case ^ast.Typeid_Type:
@@ -126,7 +126,7 @@ resolve_poly :: proc(
case ^ast.Dynamic_Array_Type:
if call_array, ok := call_node.derived.(^ast.Dynamic_Array_Type); ok {
- if common.dynamic_array_is_soa(p^) != common.dynamic_array_is_soa(call_array^) {
+ if dynamic_array_is_soa(p^) != dynamic_array_is_soa(call_array^) {
return false
}
@@ -155,7 +155,7 @@ resolve_poly :: proc(
if call_array, ok := call_node.derived.(^ast.Array_Type); ok {
found := false
- if common.array_is_soa(p^) != common.array_is_soa(call_array^) {
+ if array_is_soa(p^) != array_is_soa(call_array^) {
return false
}
@@ -634,7 +634,7 @@ is_procedure_generic :: proc(proc_type: ^ast.Proc_Type) -> bool {
continue
}
- if common.expr_contains_poly(param.type) {
+ if expr_contains_poly(param.type) {
return true
}
}
diff --git a/src/server/hover.odin b/src/server/hover.odin
index 89b75eb..afeab99 100644
--- a/src/server/hover.odin
+++ b/src/server/hover.odin
@@ -90,7 +90,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
if position_context.identifier != nil {
if ident, ok := position_context.identifier.derived.(^ast.Ident); ok {
- if _, ok := common.keyword_map[ident.name]; ok {
+ if _, ok := keyword_map[ident.name]; ok {
hover.contents.kind = "plaintext"
hover.range = common.get_token_range(position_context.identifier^, ast_context.file.src)
return hover, true, true
@@ -151,7 +151,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 = comp_symbol.name
- symbol.signature = common.node_to_string(v.types[i])
+ symbol.signature = node_to_string(v.types[i])
hover.contents = write_hover_content(&ast_context, symbol)
return hover, true, true
}
@@ -164,7 +164,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 = comp_symbol.name
- symbol.signature = common.node_to_string(v.types[i])
+ symbol.signature = node_to_string(v.types[i])
hover.contents = write_hover_content(&ast_context, symbol)
return hover, true, true
}
@@ -255,7 +255,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 = common.node_to_string(v.types[i])
+ symbol.signature = node_to_string(v.types[i])
hover.contents = write_hover_content(&ast_context, symbol)
return hover, true, true
}
@@ -310,7 +310,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
}
}
}
- }
+ }
return {}, false, true
} else if position_context.identifier != nil {
reset_ast_context(&ast_context)
diff --git a/src/server/inlay_hints.odin b/src/server/inlay_hints.odin
index d36b3e9..6c51245 100644
--- a/src/server/inlay_hints.odin
+++ b/src/server/inlay_hints.odin
@@ -114,7 +114,7 @@ get_inlay_hints :: proc(
continue loop
}
- value := common.node_to_string(arg.default_value)
+ value := node_to_string(arg.default_value)
call_range := common.get_token_range(call, string(document.text))
diff --git a/src/server/references.odin b/src/server/references.odin
index 4456978..2b44fc7 100644
--- a/src/server/references.odin
+++ b/src/server/references.odin
@@ -121,7 +121,7 @@ prepare_references :: proc(
} else if position_context.field_value != nil &&
position_context.comp_lit != nil &&
- !common.is_expr_basic_lit(position_context.field_value.field) &&
+ !is_expr_basic_lit(position_context.field_value.field) &&
position_in_node(position_context.field_value.field, position_context.position) {
symbol, ok = resolve_location_comp_lit_field(ast_context, position_context)
@@ -136,7 +136,8 @@ prepare_references :: proc(
resolve_flag = .Field
} else if position_context.selector_expr != nil {
- if position_in_node(position_context.selector, position_context.position) && position_context.identifier != nil {
+ if position_in_node(position_context.selector, position_context.position) &&
+ position_context.identifier != nil {
ident := position_context.identifier.derived.(^ast.Ident)
symbol, ok = resolve_location_identifier(ast_context, ident^)
diff --git a/src/server/requests.odin b/src/server/requests.odin
index 837bc9b..19a99b7 100644
--- a/src/server/requests.odin
+++ b/src/server/requests.odin
@@ -228,7 +228,7 @@ call_map: map[string]proc(_: json.Value, _: RequestId, _: ^common.Config, _: ^Wr
"textDocument/didClose" = notification_did_close,
"textDocument/didSave" = notification_did_save,
"textDocument/definition" = request_definition,
- "textDocument/typeDefinition" = request_type_definition,
+ "textDocument/typeDefinition" = request_type_definition,
"textDocument/completion" = request_completion,
"textDocument/signatureHelp" = request_signature_help,
"textDocument/documentSymbol" = request_document_symbols,
@@ -410,7 +410,11 @@ read_ols_initialize_options :: proc(config: ^common.Config, ols_config: OlsConfi
}
if config.profile.os == "" {
- config.profile.os = os_enum_to_string[ODIN_OS]
+ config.profile.os = fmt.aprint(ODIN_OS)
+ }
+
+ if config.profile.arch == "" {
+ config.profile.arch = fmt.aprint(ODIN_ARCH)
}
config.checker_targets = slice.clone(ols_config.checker_targets, context.allocator)
diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin
index da3a2ce..3aa5c9d 100644
--- a/src/server/semantic_tokens.odin
+++ b/src/server/semantic_tokens.odin
@@ -184,7 +184,7 @@ write_semantic_node :: proc(
return
}
- name := common.get_ast_node_string(node, builder.src)
+ name := get_ast_node_string(node, builder.src)
write_semantic_at_pos(builder, node.pos.offset, len(name), type, modifiers)
}
diff --git a/src/server/signature.odin b/src/server/signature.odin
index da4c6ce..07e487e 100644
--- a/src/server/signature.odin
+++ b/src/server/signature.odin
@@ -64,7 +64,7 @@ build_procedure_symbol_signature :: proc(symbol: ^Symbol, short_signature := tru
strings.write_string(&builder, "proc {\n")
for symbol in value.symbols {
if value, ok := symbol.value.(SymbolProcedureValue); ok {
- fmt.sbprintf(&builder, "\t%s :: ",symbol.name)
+ fmt.sbprintf(&builder, "\t%s :: ", symbol.name)
write_procedure_symbol_signature(&builder, &value)
strings.write_string(&builder, ",\n")
}
@@ -78,7 +78,7 @@ write_procedure_symbol_signature :: proc(sb: ^strings.Builder, value: ^SymbolPro
strings.write_string(sb, "proc")
strings.write_string(sb, "(")
for arg, i in value.orig_arg_types {
- strings.write_string(sb, common.node_to_string(arg))
+ strings.write_string(sb, node_to_string(arg))
if i != len(value.orig_arg_types) - 1 {
strings.write_string(sb, ", ")
}
@@ -93,7 +93,7 @@ write_procedure_symbol_signature :: proc(sb: ^strings.Builder, value: ^SymbolPro
}
for arg, i in value.orig_return_types {
- strings.write_string(sb, common.node_to_string(arg))
+ strings.write_string(sb, node_to_string(arg))
if i != len(value.orig_return_types) - 1 {
strings.write_string(sb, ", ")
}
@@ -192,7 +192,7 @@ get_signature_information :: proc(document: ^Document, position: common.Position
}
}
- parameters[i].label = common.node_to_string(arg)
+ parameters[i].label = node_to_string(arg)
}
build_procedure_symbol_signature(&call)
@@ -218,7 +218,7 @@ get_signature_information :: proc(document: ^Document, position: common.Position
}
}
- parameters[i].label = common.node_to_string(arg)
+ parameters[i].label = node_to_string(arg)
}
build_procedure_symbol_signature(&symbol)
diff --git a/src/server/symbol.odin b/src/server/symbol.odin
index fd12a87..49ada35 100644
--- a/src/server/symbol.odin
+++ b/src/server/symbol.odin
@@ -33,7 +33,8 @@ SymbolBitFieldValue :: struct {
types: []^ast.Expr,
}
-SymbolPackageValue :: struct {}
+SymbolPackageValue :: struct {
+}
SymbolProcedureValue :: struct {
return_types: []^ast.Field,
@@ -207,52 +208,52 @@ free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) {
switch v in symbol.value {
case SymbolMatrixValue:
- common.free_ast(v.expr, allocator)
- common.free_ast(v.x, allocator)
- common.free_ast(v.y, allocator)
+ free_ast(v.expr, allocator)
+ free_ast(v.x, allocator)
+ free_ast(v.y, allocator)
case SymbolMultiPointerValue:
- common.free_ast(v.expr, allocator)
+ free_ast(v.expr, allocator)
case SymbolProcedureValue:
- common.free_ast(v.return_types, allocator)
- common.free_ast(v.arg_types, allocator)
+ free_ast(v.return_types, allocator)
+ free_ast(v.arg_types, allocator)
case SymbolStructValue:
delete(v.names, allocator)
delete(v.ranges, allocator)
- common.free_ast(v.types, allocator)
+ free_ast(v.types, allocator)
case SymbolGenericValue:
- common.free_ast(v.expr, allocator)
+ free_ast(v.expr, allocator)
case SymbolProcedureGroupValue:
- common.free_ast(v.group, allocator)
+ free_ast(v.group, allocator)
case SymbolEnumValue:
delete(v.names, allocator)
delete(v.ranges, allocator)
case SymbolUnionValue:
- common.free_ast(v.types, allocator)
+ free_ast(v.types, allocator)
case SymbolBitSetValue:
- common.free_ast(v.expr, allocator)
+ free_ast(v.expr, allocator)
case SymbolDynamicArrayValue:
- common.free_ast(v.expr, allocator)
+ free_ast(v.expr, allocator)
case SymbolFixedArrayValue:
- common.free_ast(v.expr, allocator)
- common.free_ast(v.len, allocator)
+ free_ast(v.expr, allocator)
+ free_ast(v.len, allocator)
case SymbolSliceValue:
- common.free_ast(v.expr, allocator)
+ free_ast(v.expr, allocator)
case SymbolBasicValue:
- common.free_ast(v.ident, allocator)
+ free_ast(v.ident, allocator)
case SymbolAggregateValue:
for symbol in v.symbols {
free_symbol(symbol, allocator)
}
case SymbolMapValue:
- common.free_ast(v.key, allocator)
- common.free_ast(v.value, allocator)
+ free_ast(v.key, allocator)
+ free_ast(v.value, allocator)
case SymbolUntypedValue:
delete(v.tok.text)
case SymbolPackageValue:
case SymbolBitFieldValue:
delete(v.names, allocator)
delete(v.ranges, allocator)
- common.free_ast(v.types, allocator)
+ free_ast(v.types, allocator)
}
}
diff --git a/src/server/type_definition.odin b/src/server/type_definition.odin
index 2b5ec81..900c060 100644
--- a/src/server/type_definition.odin
+++ b/src/server/type_definition.odin
@@ -3,8 +3,8 @@ package server
import "core:fmt"
import "core:log"
import "core:mem"
-import "core:strings"
import "core:odin/ast"
+import "core:strings"
import "src:common"
@@ -56,7 +56,7 @@ get_type_definition_locations :: proc(document: ^Document, position: common.Posi
if position_context.identifier != nil {
if ident, ok := position_context.identifier.derived.(^ast.Ident); ok {
- if _, ok := common.keyword_map[ident.name]; ok {
+ if _, ok := keyword_map[ident.name]; ok {
return {}, false
}
@@ -65,7 +65,7 @@ get_type_definition_locations :: proc(document: ^Document, position: common.Posi
}
}
}
-
+
if position_context.call != nil {
if call, ok := position_context.call.derived.(^ast.Call_Expr); ok {
if !position_in_exprs(call.args, position_context.position) {
diff --git a/src/server/when.odin b/src/server/when.odin
index f1407fe..dc06c4f 100644
--- a/src/server/when.odin
+++ b/src/server/when.odin
@@ -1,7 +1,121 @@
package server
+import "core:fmt"
+import "core:log"
import "core:odin/ast"
+import "core:strconv"
-resolve_when_stmt :: proc(ast_context: ^AstContext, when_stmt: ^ast.When_Stmt) -> bool {
- return false
+import "src:common"
+
+When_Expr :: union {
+ int, //Integers types
+ bool, //Boolean types
+ string, //Enum types - those are the hardcoded options from i.e. ODIN_OS
+ ^ast.Expr,
+}
+
+resolve_when_ident :: proc(when_expr_map: map[string]When_Expr, ident: string) -> (When_Expr, bool) {
+ switch ident {
+ case "ODIN_OS":
+ if common.config.profile.os != "" {
+ return common.config.profile.os, true
+ } else {
+ return fmt.tprint(ODIN_OS), true
+ }
+ case "ODIN_ARCH":
+ if common.config.profile.arch != "" {
+ return common.config.profile.arch, true
+ } else {
+ return fmt.tprint(ODIN_ARCH), true
+ }
+ }
+
+ if ident in when_expr_map {
+ value := when_expr_map[ident]
+ return value, true
+ }
+
+ if v, ok := strconv.parse_int(ident); ok {
+ return v, true
+ } else if v, ok := strconv.parse_bool(ident); ok {
+ return v, true
+ }
+
+ return ident, true
+}
+
+resolve_when_expr :: proc(
+ when_expr_map: map[string]When_Expr,
+ when_expr: When_Expr,
+) -> (
+ _when_expr: When_Expr,
+ ok: bool,
+) {
+
+ switch expr in when_expr {
+ case int:
+ return expr, true
+ case bool:
+ return expr, true
+ case string:
+ return expr, true
+ case ^ast.Expr:
+ #partial switch odin_expr in expr.derived {
+ case ^ast.Ident:
+ return resolve_when_ident(when_expr_map, odin_expr.name)
+ case ^ast.Basic_Lit:
+ return resolve_when_ident(when_expr_map, odin_expr.tok.text)
+ case ^ast.Implicit_Selector_Expr:
+ return odin_expr.field.name, true
+ case ^ast.Binary_Expr:
+ lhs := resolve_when_expr(when_expr_map, odin_expr.left) or_return
+ rhs := resolve_when_expr(when_expr_map, odin_expr.right) or_return
+
+ lhs_bool, lhs_is_bool := lhs.(bool)
+ rhs_bool, rhs_is_bool := rhs.(bool)
+
+ lhs_int, lhs_is_int := lhs.(int)
+ rhs_int, rhs_is_int := rhs.(int)
+
+ lhs_string, lhs_is_string := lhs.(string)
+ rhs_string, rhs_is_string := rhs.(string)
+
+ if lhs_is_string && rhs_is_string {
+ #partial switch odin_expr.op.kind {
+ case .Cmp_Eq:
+ return lhs_string == rhs_string, true
+ case .Not_Eq:
+ return lhs_string != rhs_string, true
+ }
+ } else if lhs_is_bool && rhs_is_bool {
+ #partial switch odin_expr.op.kind {
+ case .Cmp_And:
+ return lhs_bool && rhs_bool, true
+ case .Cmp_Or:
+ return lhs_bool || rhs_bool, true
+ }
+ }
+
+ return {}, false
+ }
+ }
+
+
+ return {}, false
+}
+
+
+resolve_when_condition :: proc(condition: ^ast.Expr) -> bool {
+ when_expr_map := make(map[string]When_Expr, context.temp_allocator)
+
+ for key, value in common.config.profile.defines {
+ when_expr_map[key] = resolve_when_ident(when_expr_map, value) or_continue
+ }
+
+ if when_expr, ok := resolve_when_expr(when_expr_map, condition); ok {
+ b, is_bool := when_expr.(bool)
+ return is_bool && b
+ }
+
+ return false
}