diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2025-06-20 18:38:28 +0200 |
|---|---|---|
| committer | DanielGavin <danielgavin5@hotmail.com> | 2025-06-20 18:38:28 +0200 |
| commit | fa626ad544a171313ac1679e0865d9d7d822c63b (patch) | |
| tree | 4d8755ee42984d69a71a26003745c9c11ce648ab /src/server | |
| parent | 5caff349cf9dad7c697eb49250ac4c1e75e259fb (diff) | |
Move ast.odin to server + add resolve_when_condition
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/analysis.odin | 68 | ||||
| -rw-r--r-- | src/server/ast.odin | 1159 | ||||
| -rw-r--r-- | src/server/collector.odin | 18 | ||||
| -rw-r--r-- | src/server/completion.odin | 42 | ||||
| -rw-r--r-- | src/server/definition.odin | 5 | ||||
| -rw-r--r-- | src/server/generics.odin | 8 | ||||
| -rw-r--r-- | src/server/hover.odin | 10 | ||||
| -rw-r--r-- | src/server/inlay_hints.odin | 2 | ||||
| -rw-r--r-- | src/server/references.odin | 5 | ||||
| -rw-r--r-- | src/server/requests.odin | 8 | ||||
| -rw-r--r-- | src/server/semantic_tokens.odin | 2 | ||||
| -rw-r--r-- | src/server/signature.odin | 10 | ||||
| -rw-r--r-- | src/server/symbol.odin | 41 | ||||
| -rw-r--r-- | src/server/type_definition.odin | 6 | ||||
| -rw-r--r-- | src/server/when.odin | 118 |
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 } |