diff options
Diffstat (limited to 'src/server')
31 files changed, 4430 insertions, 1670 deletions
diff --git a/src/server/action.odin b/src/server/action.odin index 44b3458..ba1b367 100644 --- a/src/server/action.odin +++ b/src/server/action.odin @@ -13,4 +13,4 @@ CodeActionClientCapabilities :: struct { CodeActionOptions :: struct { codeActionKinds: []CodeActionKind, resolveProvider: bool, -}
\ No newline at end of file +} diff --git a/src/server/analysis.odin b/src/server/analysis.odin index facc202..6113b63 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -29,30 +29,30 @@ DocumentPositionContext :: struct { position: common.AbsolutePosition, line: int, function: ^ast.Proc_Lit, //used to help with type resolving in function scope - selector: ^ast.Expr, //used for completion + selector: ^ast.Expr, //used for completion selector_expr: ^ast.Selector_Expr, identifier: ^ast.Node, implicit_context: ^ast.Implicit, tag: ^ast.Node, - field: ^ast.Expr, //used for completion - call: ^ast.Expr, //used for signature help + field: ^ast.Expr, //used for completion + call: ^ast.Expr, //used for signature help returns: ^ast.Return_Stmt, //used for completion - comp_lit: ^ast.Comp_Lit, //used for completion - parent_comp_lit: ^ast.Comp_Lit, //used for completion + comp_lit: ^ast.Comp_Lit, //used for completion + parent_comp_lit: ^ast.Comp_Lit, //used for completion struct_type: ^ast.Struct_Type, union_type: ^ast.Union_Type, bitset_type: ^ast.Bit_Set_Type, enum_type: ^ast.Enum_Type, field_value: ^ast.Field_Value, - implicit: bool, //used for completion + implicit: bool, //used for completion arrow: bool, - binary: ^ast.Binary_Expr, //used for completion - parent_binary: ^ast.Binary_Expr, //used for completion - assign: ^ast.Assign_Stmt, //used for completion - switch_stmt: ^ast.Switch_Stmt, //used for completion + binary: ^ast.Binary_Expr, //used for completion + parent_binary: ^ast.Binary_Expr, //used for completion + assign: ^ast.Assign_Stmt, //used for completion + switch_stmt: ^ast.Switch_Stmt, //used for completion switch_type_stmt: ^ast.Type_Switch_Stmt, //used for completion - case_clause: ^ast.Case_Clause, //used for completion - value_decl: ^ast.Value_Decl, //used for completion + case_clause: ^ast.Case_Clause, //used for completion + value_decl: ^ast.Value_Decl, //used for completion abort_completion: bool, hint: DocumentPositionContextHint, global_lhs_stmt: bool, @@ -61,10 +61,10 @@ DocumentPositionContext :: struct { } DocumentLocal :: struct { - lhs: ^ast.Expr, - rhs: ^ast.Expr, + lhs: ^ast.Expr, + rhs: ^ast.Expr, offset: int, - id: int, //Id that can used to connect the local to something, i.e. for stmt begin offset + id: int, //Id that can used to connect the local to something, i.e. for stmt begin offset } AstContext :: struct { @@ -81,7 +81,7 @@ AstContext :: struct { document_package: string, use_globals: bool, use_locals: bool, - local_id: int, + local_id: int, call: ^ast.Call_Expr, //used to determene the types for generics and the correct function for overloaded functions position: common.AbsolutePosition, value_decl: ^ast.Value_Decl, @@ -91,23 +91,34 @@ AstContext :: struct { recursion_counter: int, //Sometimes the ast is so malformed that it causes infinite recursion. } -make_ast_context :: proc(file: ast.File, imports: []Package, package_name: string, uri: string, fullpath: string, allocator := context.temp_allocator) -> AstContext { +make_ast_context :: proc( + file: ast.File, + imports: []Package, + package_name: string, + uri: string, + fullpath: string, + allocator := context.temp_allocator, +) -> AstContext { ast_context := AstContext { - locals = make(map[int]map[string][dynamic]DocumentLocal, 0, allocator), - globals = make(map[string]common.GlobalExpr, 0, allocator), - variables = make(map[string]bool, 0, allocator), - usings = make([dynamic]string, allocator), - parameters = make(map[string]bool, 0, allocator), - in_package = make(map[string]string, 0, allocator), - file = file, - imports = imports, - use_locals = true, - use_globals = true, + locals = make( + map[int]map[string][dynamic]DocumentLocal, + 0, + allocator, + ), + globals = make(map[string]common.GlobalExpr, 0, allocator), + variables = make(map[string]bool, 0, allocator), + usings = make([dynamic]string, allocator), + parameters = make(map[string]bool, 0, allocator), + in_package = make(map[string]string, 0, allocator), + file = file, + imports = imports, + use_locals = true, + use_globals = true, document_package = package_name, - current_package = package_name, - uri = uri, - fullpath = fullpath, - allocator = allocator, + current_package = package_name, + uri = uri, + fullpath = fullpath, + allocator = allocator, } add_local_group(&ast_context, 0) @@ -128,7 +139,12 @@ resolve_poly_spec :: proc { resolve_poly_spec_dynamic_array, } -resolve_poly_spec_array :: proc(ast_context: ^AstContext, call_array: $A/[]^$T, spec_array: $D/[]^$K, poly_map: ^map[string]^ast.Expr) { +resolve_poly_spec_array :: proc( + ast_context: ^AstContext, + call_array: $A/[]^$T, + spec_array: $D/[]^$K, + poly_map: ^map[string]^ast.Expr, +) { if len(call_array) != len(spec_array) { return } @@ -138,7 +154,12 @@ resolve_poly_spec_array :: proc(ast_context: ^AstContext, call_array: $A/[]^$T, } } -resolve_poly_spec_dynamic_array :: proc(ast_context: ^AstContext, call_array: $A/[dynamic]^$T, spec_array: $D/[dynamic]^$K, poly_map: ^map[string]^ast.Expr) { +resolve_poly_spec_dynamic_array :: proc( + ast_context: ^AstContext, + call_array: $A/[dynamic]^$T, + spec_array: $D/[dynamic]^$K, + poly_map: ^map[string]^ast.Expr, +) { if len(call_array) != len(spec_array) { return } @@ -163,7 +184,12 @@ get_poly_node_to_expr :: proc(node: ^ast.Node) -> ^ast.Expr { return nil } -resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, spec_node: ^ast.Node, poly_map: ^map[string]^ast.Expr) { +resolve_poly_spec_node :: proc( + ast_context: ^AstContext, + call_node: ^ast.Node, + spec_node: ^ast.Node, + poly_map: ^map[string]^ast.Expr, +) { using ast if call_node == nil || spec_node == nil { @@ -176,7 +202,7 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s case ^Implicit: case ^Undef: case ^Basic_Lit: - case ^Poly_Type: + case ^Poly_Type: if expr := get_poly_node_to_expr(call_node); expr != nil { poly_map[m.type.name] = expr } @@ -236,7 +262,12 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s } case ^Struct_Type: if n, ok := call_node.derived.(^Struct_Type); ok { - resolve_poly_spec(ast_context, n.poly_params, m.poly_params, poly_map) + resolve_poly_spec( + ast_context, + n.poly_params, + m.poly_params, + poly_map, + ) resolve_poly_spec(ast_context, n.align, m.align, poly_map) resolve_poly_spec(ast_context, n.fields, m.fields, poly_map) } @@ -244,7 +275,12 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s if n, ok := call_node.derived.(^Field); ok { resolve_poly_spec(ast_context, n.names, m.names, poly_map) resolve_poly_spec(ast_context, n.type, m.type, poly_map) - resolve_poly_spec(ast_context, n.default_value, m.default_value, poly_map) + resolve_poly_spec( + ast_context, + n.default_value, + m.default_value, + poly_map, + ) } case ^Field_List: if n, ok := call_node.derived.(^Field_List); ok { @@ -257,7 +293,12 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s } case ^Union_Type: if n, ok := call_node.derived.(^Union_Type); ok { - resolve_poly_spec(ast_context, n.poly_params, m.poly_params, poly_map) + resolve_poly_spec( + ast_context, + n.poly_params, + m.poly_params, + poly_map, + ) resolve_poly_spec(ast_context, n.align, m.align, poly_map) resolve_poly_spec(ast_context, n.variants, m.variants, poly_map) } @@ -269,7 +310,12 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s case ^Bit_Set_Type: if n, ok := call_node.derived.(^Bit_Set_Type); ok { resolve_poly_spec(ast_context, n.elem, m.elem, poly_map) - resolve_poly_spec(ast_context, n.underlying, m.underlying, poly_map) + resolve_poly_spec( + ast_context, + n.underlying, + m.underlying, + poly_map, + ) } case ^Map_Type: if n, ok := call_node.derived.(^Map_Type); ok { @@ -283,14 +329,28 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s } case ^Typeid_Type: if n, ok := call_node.derived.(^Typeid_Type); ok { - resolve_poly_spec(ast_context, n.specialization, m.specialization, poly_map) + resolve_poly_spec( + ast_context, + n.specialization, + m.specialization, + poly_map, + ) } case: log.error("Unhandled poly node kind: %T", m) } } -resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, current_symbol: Symbol, current_comp_lit: ^ast.Comp_Lit) -> (Symbol, ^ast.Comp_Lit, bool) { +resolve_type_comp_literal :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + current_symbol: Symbol, + current_comp_lit: ^ast.Comp_Lit, +) -> ( + Symbol, + ^ast.Comp_Lit, + bool, +) { if position_context.comp_lit == current_comp_lit { return current_symbol, current_comp_lit, true } else if current_comp_lit == nil { @@ -301,7 +361,7 @@ resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^D prev_package := ast_context.current_package ast_context.current_package = current_symbol.pkg - + defer ast_context.current_package = prev_package for elem, i in current_comp_lit.elems { @@ -314,35 +374,53 @@ resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^D if !position_in_node(elem, position_context.position) { continue } - - if field_value, ok := elem.derived.(^ast.Field_Value); ok { //named + + if field_value, ok := elem.derived.(^ast.Field_Value); ok { //named if comp_lit, ok := field_value.value.derived.(^ast.Comp_Lit); ok { if s, ok := current_symbol.value.(SymbolStructValue); ok { for name, i in s.names { - if name == field_value.field.derived.(^ast.Ident).name { - if symbol, ok := resolve_type_expression(ast_context, s.types[i]); ok { + if name == + field_value.field.derived.(^ast.Ident).name { + if symbol, ok := resolve_type_expression( + ast_context, + s.types[i], + ); ok { //Stop at bitset, because we don't want to enter a comp_lit of a bitset - if _, ok := symbol.value.(SymbolBitSetValue); ok { + if _, ok := symbol.value.(SymbolBitSetValue); + ok { return current_symbol, current_comp_lit, true } - return resolve_type_comp_literal(ast_context, position_context, symbol, cast(^ast.Comp_Lit)field_value.value) + return resolve_type_comp_literal( + ast_context, + position_context, + symbol, + cast(^ast.Comp_Lit)field_value.value, + ) } } } } } - } else if comp_value, ok := elem.derived.(^ast.Comp_Lit); ok { //indexed + } else if comp_value, ok := elem.derived.(^ast.Comp_Lit); ok { //indexed if s, ok := current_symbol.value.(SymbolStructValue); ok { if len(s.types) <= element_index { return {}, {}, false } - if symbol, ok := resolve_type_expression(ast_context, s.types[element_index]); ok { + if symbol, ok := resolve_type_expression( + ast_context, + s.types[element_index], + ); ok { //Stop at bitset, because we don't want to enter a comp_lit of a bitset if _, ok := symbol.value.(SymbolBitSetValue); ok { return current_symbol, current_comp_lit, true } - return resolve_type_comp_literal(ast_context, position_context, symbol, comp_value) + return resolve_type_comp_literal( + ast_context, + position_context, + symbol, + comp_value, + ) } } } @@ -356,7 +434,14 @@ resolve_generic_function :: proc { resolve_generic_function_symbol, } -resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast.Field, results: []^ast.Field) -> (Symbol, bool) { +resolve_generic_function_symbol :: proc( + ast_context: ^AstContext, + params: []^ast.Field, + results: []^ast.Field, +) -> ( + Symbol, + bool, +) { if params == nil { return {}, false } @@ -372,7 +457,7 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast call_expr := ast_context.call poly_map := make(map[string]^ast.Expr, 0, context.temp_allocator) i := 0 - count_required_params := 0 + count_required_params := 0 for param in params { if param.default_value == nil { @@ -393,18 +478,29 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast } if type_id, ok := param.type.derived.(^ast.Typeid_Type); ok { - if type_id.specialization != nil && !common.node_equal(call_expr.args[i], type_id.specialization) { + if type_id.specialization != nil && + !common.node_equal( + call_expr.args[i], + type_id.specialization, + ) { return {}, false } } - resolve_poly_spec_node(ast_context, call_expr.args[i], param.type, &poly_map) + resolve_poly_spec_node( + ast_context, + call_expr.args[i], + param.type, + &poly_map, + ) i += 1 } } - if count_required_params > len(call_expr.args) || count_required_params == 0 || len(call_expr.args) == 0 { + if count_required_params > len(call_expr.args) || + count_required_params == 0 || + len(call_expr.args) == 0 { return {}, false } @@ -423,8 +519,8 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast symbol := Symbol { range = function_range, - type = .Function, - name = function_name, + type = .Function, + name = function_name, } return_types := make([dynamic]^ast.Field, ast_context.allocator) @@ -439,7 +535,11 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast if ok { if m, ok := poly_map[ident.name]; ok { - field := cast(^ast.Field)clone_node(result, ast_context.allocator, nil) + field := cast(^ast.Field)clone_node( + result, + ast_context.allocator, + nil, + ) field.type = m append(&return_types, field) } else { @@ -456,9 +556,14 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast } //check the name for poly - if poly_type, ok := param.names[0].derived.(^ast.Poly_Type); ok && param.type != nil { + if poly_type, ok := param.names[0].derived.(^ast.Poly_Type); + ok && param.type != nil { if m, ok := poly_map[poly_type.type.name]; ok { - field := cast(^ast.Field)clone_node(param, ast_context.allocator, nil) + field := cast(^ast.Field)clone_node( + param, + ast_context.allocator, + nil, + ) field.type = m append(&argument_types, field) } @@ -469,55 +574,78 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast symbol.value = SymbolProcedureValue { return_types = return_types[:], - arg_types = argument_types[:], + arg_types = argument_types[:], } return symbol, true } -resolve_generic_function_ast :: proc(ast_context: ^AstContext, proc_lit: ast.Proc_Lit) -> (Symbol, bool) { +resolve_generic_function_ast :: proc( + ast_context: ^AstContext, + proc_lit: ast.Proc_Lit, +) -> ( + Symbol, + bool, +) { using ast if proc_lit.type.params == nil { - return Symbol {}, false + return Symbol{}, false } if proc_lit.type.results == nil { - return Symbol {}, false + return Symbol{}, false } if ast_context.call == nil { - return Symbol {}, false + return Symbol{}, false } - return resolve_generic_function_symbol(ast_context, proc_lit.type.params.list, proc_lit.type.results.list) + return resolve_generic_function_symbol( + ast_context, + proc_lit.type.params.list, + proc_lit.type.results.list, + ) } -is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: Symbol, flags: ast.Field_Flags = {}) -> bool { +is_symbol_same_typed :: proc( + ast_context: ^AstContext, + a, + b: Symbol, + flags: ast.Field_Flags = {}, +) -> bool { //relying on the fact that a is the call argument to avoid checking both sides for untyped. if untyped, ok := a.value.(SymbolUntypedValue); ok { if basic, ok := b.value.(SymbolBasicValue); ok { switch untyped.type { case .Integer: switch basic.ident.name { - case "int", "uint", "u32", "i32", "u8", "i8", "u64", "u16", "i16": return true - case: return false + case "int", "uint", "u32", "i32", "u8", "i8", "u64", "u16", "i16": + return true + case: + return false } case .Bool: switch basic.ident.name { - case "bool", "b32", "b64": return true - case: return false + case "bool", "b32", "b64": + return true + case: + return false } case .String: switch basic.ident.name { - case "string", "cstring": return true - case: return false + case "string", "cstring": + return true + case: + return false } case .Float: switch basic.ident.name { - case "f32", "f64": return true - case: return false + case "f32", "f64": + return true + case: + return false } } } @@ -538,12 +666,12 @@ is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: Symbol, flags: ast. return false } - if .Distinct in a.flags == .Distinct in b.flags && + if .Distinct in a.flags == .Distinct in b.flags && .Distinct in a.flags && a.name == b.name && a.pkg == b.pkg { return true - } + } #partial switch b_value in b.value { case SymbolBasicValue: @@ -553,9 +681,10 @@ is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: Symbol, flags: ast. //Temporary - make a function that finds the base type of basic values //This code only works with non distinct ints switch a.name { - case "int", "uint", "u32", "i32", "u8", "i8", "u64", "u16", "i16": return true + case "int", "uint", "u32", "i32", "u8", "i8", "u64", "u16", "i16": + return true } - } + } } #partial switch a_value in a.value { @@ -664,32 +793,47 @@ is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: Symbol, flags: ast. return false } - a_value_symbol, ok = resolve_type_expression(ast_context, a_value.value) + a_value_symbol, ok = resolve_type_expression( + ast_context, + a_value.value, + ) if !ok { return false } - b_value_symbol, ok = resolve_type_expression(ast_context, b_value.value) + b_value_symbol, ok = resolve_type_expression( + ast_context, + b_value.value, + ) if !ok { return false } - return is_symbol_same_typed(ast_context, a_key_symbol, b_key_symbol) && is_symbol_same_typed(ast_context, a_value_symbol, b_value_symbol) + return( + is_symbol_same_typed(ast_context, a_key_symbol, b_key_symbol) && + is_symbol_same_typed(ast_context, a_value_symbol, b_value_symbol) \ + ) } - + return false } -get_field_list_name_index :: proc(name: string, field_list: []^ast.Field) -> (int, bool) { +get_field_list_name_index :: proc( + name: string, + field_list: []^ast.Field, +) -> ( + int, + bool, +) { for field, i in field_list { for field_name in field.names { if ident, ok := field_name.derived.(^ast.Ident); ok { if name == ident.name { return i, true } - } + } } } @@ -699,7 +843,13 @@ get_field_list_name_index :: proc(name: string, field_list: []^ast.Field) -> (in /* Figure out which function the call expression is using out of the list from proc group */ -resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Group) -> (Symbol, bool) { +resolve_function_overload :: proc( + ast_context: ^AstContext, + group: ast.Proc_Group, +) -> ( + Symbol, + bool, +) { using ast call_expr := ast_context.call @@ -707,7 +857,8 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou candidates := make([dynamic]Symbol, context.temp_allocator) for arg_expr in group.args { - next_fn: if f, ok := resolve_type_expression(ast_context, arg_expr); ok { + next_fn: if f, ok := resolve_type_expression(ast_context, arg_expr); + ok { if call_expr == nil || len(call_expr.args) == 0 { append(&candidates, f) break next_fn @@ -730,8 +881,8 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou ast_context.use_locals = true call_symbol: Symbol - arg_symbol: Symbol - ok: bool + arg_symbol: Symbol + ok: bool i := i if _, ok = arg.derived.(^ast.Bad_Expr); ok { @@ -739,22 +890,33 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou } //named parameter - if field, is_field := arg.derived.(^ast.Field_Value); is_field { - call_symbol, ok = resolve_type_expression(ast_context, field.value) + if field, is_field := arg.derived.(^ast.Field_Value); + is_field { + call_symbol, ok = resolve_type_expression( + ast_context, + field.value, + ) if !ok { break next_fn } - if ident, is_ident := field.field.derived.(^ast.Ident); is_ident { - i, ok = get_field_list_name_index(field.field.derived.(^ast.Ident).name, procedure.arg_types) + if ident, is_ident := field.field.derived.(^ast.Ident); + is_ident { + i, ok = get_field_list_name_index( + field.field.derived.(^ast.Ident).name, + procedure.arg_types, + ) } else { break next_fn } } else { - call_symbol, ok = resolve_type_expression(ast_context, arg) + call_symbol, ok = resolve_type_expression( + ast_context, + arg, + ) } - if !ok { + if !ok { break next_fn } @@ -762,48 +924,66 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou if len(p.return_types) != 1 { break next_fn } - if s, ok := resolve_type_expression(ast_context, p.return_types[0].type); ok { + if s, ok := resolve_type_expression( + ast_context, + p.return_types[0].type, + ); ok { call_symbol = s } } if procedure.arg_types[i].type != nil { - arg_symbol, ok = resolve_type_expression(ast_context, procedure.arg_types[i].type) - } else { - arg_symbol, ok = resolve_type_expression(ast_context, procedure.arg_types[i].default_value) + arg_symbol, ok = resolve_type_expression( + ast_context, + procedure.arg_types[i].type, + ) + } else { + arg_symbol, ok = resolve_type_expression( + ast_context, + procedure.arg_types[i].default_value, + ) } - if !ok { + if !ok { break next_fn } - if !is_symbol_same_typed(ast_context, call_symbol, arg_symbol, procedure.arg_types[i].flags) { + if !is_symbol_same_typed( + ast_context, + call_symbol, + arg_symbol, + procedure.arg_types[i].flags, + ) { break next_fn - } + } } - + append(&candidates, f) } } } if len(candidates) > 1 { - return Symbol { + return Symbol{ type = candidates[0].type, name = candidates[0].name, pkg = candidates[0].pkg, - value = SymbolAggregateValue { - symbols = candidates[:], - }, + value = SymbolAggregateValue{symbols = candidates[:]}, }, true } else if len(candidates) == 1 { return candidates[0], true } - return Symbol {}, false + return Symbol{}, false } -resolve_basic_lit :: proc(ast_context: ^AstContext, basic_lit: ast.Basic_Lit) -> (Symbol, bool) { +resolve_basic_lit :: proc( + ast_context: ^AstContext, + basic_lit: ast.Basic_Lit, +) -> ( + Symbol, + bool, +) { symbol := Symbol { type = .Constant, } @@ -826,10 +1006,22 @@ resolve_basic_lit :: proc(ast_context: ^AstContext, basic_lit: ast.Basic_Lit) -> return symbol, true } -resolve_basic_directive :: proc(ast_context: ^AstContext, directive: ast.Basic_Directive, a := #caller_location) -> (Symbol, bool) { +resolve_basic_directive :: proc( + ast_context: ^AstContext, + directive: ast.Basic_Directive, + a := #caller_location, +) -> ( + Symbol, + bool, +) { switch directive.name { case "caller_location": - ident := new_type(ast.Ident, directive.pos, directive.end, ast_context.allocator) + ident := new_type( + ast.Ident, + directive.pos, + directive.end, + ast_context.allocator, + ) ident.name = "Source_Code_Location" ast_context.current_package = ast_context.document_package return resolve_type_identifier(ast_context, ident^) @@ -839,7 +1031,13 @@ resolve_basic_directive :: proc(ast_context: ^AstContext, directive: ast.Basic_D } -resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (Symbol, bool) { +resolve_type_expression :: proc( + ast_context: ^AstContext, + node: ^ast.Expr, +) -> ( + Symbol, + bool, +) { if node == nil { return {}, false } @@ -865,33 +1063,74 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S #partial switch v in node.derived { case ^Union_Type: - return make_symbol_union_from_ast(ast_context, v^, ast_context.field_name, true), true + return make_symbol_union_from_ast( + ast_context, + v^, + ast_context.field_name, + true, + ), true case ^Enum_Type: - return make_symbol_enum_from_ast(ast_context, v^, ast_context.field_name, true), true + return make_symbol_enum_from_ast( + ast_context, + v^, + ast_context.field_name, + true, + ), true case ^Struct_Type: - return make_symbol_struct_from_ast(ast_context, v^, ast_context.field_name, true), true + return make_symbol_struct_from_ast( + ast_context, + v^, + ast_context.field_name, + true, + ), true case ^Bit_Set_Type: - return make_symbol_bitset_from_ast(ast_context, v^, ast_context.field_name, true), true + return make_symbol_bitset_from_ast( + ast_context, + v^, + ast_context.field_name, + true, + ), true case ^Array_Type: - return make_symbol_array_from_ast(ast_context, v^, ast_context.field_name), true + return make_symbol_array_from_ast( + ast_context, + v^, + ast_context.field_name, + ), true case ^Dynamic_Array_Type: - return make_symbol_dynamic_array_from_ast(ast_context, v^, ast_context.field_name), true + return make_symbol_dynamic_array_from_ast( + ast_context, + v^, + ast_context.field_name, + ), true case ^Multi_Pointer_Type: - return make_symbol_multi_pointer_from_ast(ast_context, v^, ast_context.field_name), true + return make_symbol_multi_pointer_from_ast( + ast_context, + v^, + ast_context.field_name, + ), true case ^Map_Type: - return make_symbol_map_from_ast(ast_context, v^, ast_context.field_name), true + return make_symbol_map_from_ast( + ast_context, + v^, + ast_context.field_name, + ), true case ^Proc_Type: - return make_symbol_procedure_from_ast(ast_context, node, v^, ast_context.field_name), true + return make_symbol_procedure_from_ast( + ast_context, + node, + v^, + ast_context.field_name, + ), true case ^Basic_Directive: return resolve_basic_directive(ast_context, v^) case ^Binary_Expr: - return resolve_first_symbol_from_binary_expression(ast_context, v) + return resolve_first_symbol_from_binary_expression(ast_context, v) case ^Ident: return resolve_type_identifier(ast_context, v^) case ^Basic_Lit: return resolve_basic_lit(ast_context, v^) case ^Type_Cast: - return resolve_type_expression(ast_context, v.type) + return resolve_type_expression(ast_context, v.type) case ^Auto_Cast: return resolve_type_expression(ast_context, v.expr) case ^Comp_Lit: @@ -925,22 +1164,29 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S case ^Type_Assertion: if unary, ok := v.type.derived.(^ast.Unary_Expr); ok { if unary.op.kind == .Question { - if symbol, ok := resolve_type_expression(ast_context, v.expr); ok { + if symbol, ok := resolve_type_expression(ast_context, v.expr); + ok { if union_value, ok := symbol.value.(SymbolUnionValue); ok { if len(union_value.types) != 1 { return {}, false } - return resolve_type_expression(ast_context, union_value.types[0]) + return resolve_type_expression( + ast_context, + union_value.types[0], + ) } } } } else { return resolve_type_expression(ast_context, v.type) - } + } case ^Proc_Lit: if v.type.results != nil { if len(v.type.results.list) == 1 { - return resolve_type_expression(ast_context, v.type.results.list[0].type) + return resolve_type_expression( + ast_context, + v.type.results.list[0].type, + ) } } case ^Pointer_Type: @@ -976,7 +1222,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S ast_context.call = cast(^Call_Expr)node return resolve_type_expression(ast_context, v.expr) case ^Implicit_Selector_Expr: - return Symbol {}, false + return Symbol{}, false case ^Selector_Call_Expr: return resolve_type_expression(ast_context, v.expr) case ^Selector_Expr: @@ -987,8 +1233,14 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S case SymbolFixedArrayValue: components_count := 0 for c in v.field.name { - if c == 'x' || c == 'y' || c == 'z' || c == 'w' || - c == 'r' || c == 'g' || c == 'b' || c == 'a' { + if c == 'x' || + c == 'y' || + c == 'z' || + c == 'w' || + c == 'r' || + c == 'g' || + c == 'b' || + c == 'a' { components_count += 1 } } @@ -1001,7 +1253,8 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S if selector.pkg != "" { ast_context.current_package = selector.pkg } else { - ast_context.current_package = ast_context.document_package + ast_context.current_package = + ast_context.document_package } symbol, ok := resolve_type_expression(ast_context, s.expr) symbol.type = .Variable @@ -1009,7 +1262,10 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S } else { value := SymbolFixedArrayValue { expr = s.expr, - len = make_int_basic_value(ast_context, components_count), + len = make_int_basic_value( + ast_context, + components_count, + ), } selector.value = value selector.type = .Variable @@ -1017,7 +1273,12 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S } case SymbolProcedureValue: if len(s.return_types) == 1 { - selector_expr := new_type(ast.Selector_Expr, s.return_types[0].node.pos, s.return_types[0].node.end, ast_context.allocator) + selector_expr := new_type( + ast.Selector_Expr, + s.return_types[0].node.pos, + s.return_types[0].node.end, + ast_context.allocator, + ) selector_expr.expr = s.return_types[0].type selector_expr.field = v.field return resolve_type_expression(ast_context, selector_expr) @@ -1032,7 +1293,10 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S for name, i in s.names { if v.field != nil && name == v.field.name { ast_context.field_name = v.field^ - symbol, ok := resolve_type_expression(ast_context, s.types[i]) + symbol, ok := resolve_type_expression( + ast_context, + s.types[i], + ) symbol.type = .Variable return symbol, ok } @@ -1043,13 +1307,16 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S try_build_package(ast_context.current_package) if v.field != nil { - return resolve_symbol_return(ast_context, lookup(v.field.name, selector.pkg)) + return resolve_symbol_return( + ast_context, + lookup(v.field.name, selector.pkg), + ) } else { - return Symbol {}, false + return Symbol{}, false } } } else { - return Symbol {}, false + return Symbol{}, false } case: log.warnf("default node kind, resolve_type_expression: %T", v) @@ -1058,10 +1325,17 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S } } - return Symbol {}, false + return Symbol{}, false } -store_local :: proc(ast_context: ^AstContext, lhs: ^ast.Expr, rhs: ^ast.Expr, offset: int, name: string, id := 0) { +store_local :: proc( + ast_context: ^AstContext, + lhs: ^ast.Expr, + rhs: ^ast.Expr, + offset: int, + name: string, + id := 0, +) { local_stack := &ast_context.locals[id][name] if local_stack == nil { @@ -1070,18 +1344,32 @@ store_local :: proc(ast_context: ^AstContext, lhs: ^ast.Expr, rhs: ^ast.Expr, of local_stack = &locals[name] } - append(local_stack, DocumentLocal {lhs = lhs, rhs = rhs, offset = offset, id = id}) + append( + local_stack, + DocumentLocal{lhs = lhs, rhs = rhs, offset = offset, id = id}, + ) } add_local_group :: proc(ast_context: ^AstContext, id: int) { - ast_context.locals[id] = make(map[string][dynamic]DocumentLocal, 100, ast_context.allocator) + ast_context.locals[id] = make( + map[string][dynamic]DocumentLocal, + 100, + ast_context.allocator, + ) } clear_local_group :: proc(ast_context: ^AstContext, id: int) { ast_context.locals[id] = {} } -get_local_lhs_and_rhs :: proc(ast_context: ^AstContext, offset: int, name: string) -> (^ast.Expr, ^ast.Expr) { +get_local_lhs_and_rhs :: proc( + ast_context: ^AstContext, + offset: int, + name: string, +) -> ( + ^ast.Expr, + ^ast.Expr, +) { previous := 0 //is the local we are getting being declared? @@ -1104,31 +1392,43 @@ get_local_lhs_and_rhs :: proc(ast_context: ^AstContext, offset: int, name: strin return nil, nil } else { ret := local_stack[i - previous].rhs - if ident, ok := ret.derived.(^ast.Ident); ok && ident.name == name { + if ident, ok := ret.derived.(^ast.Ident); + ok && ident.name == name { if i - previous - 1 < 0 { return nil, nil } - if _, ok := ast_context.parameters[ident.name]; ok { - return local_stack[i - previous].lhs, local_stack[i - previous].rhs + if _, ok := ast_context.parameters[ident.name]; + ok { + return local_stack[i - + previous].lhs, local_stack[i - previous].rhs } } - return local_stack[i - previous].lhs, local_stack[i - previous].rhs; - } + return local_stack[i - + previous].lhs, local_stack[i - previous].rhs + } } } } } - + return nil, nil } -get_local :: proc(ast_context: ^AstContext, offset: int, name: string) -> ^ast.Expr { +get_local :: proc( + ast_context: ^AstContext, + offset: int, + name: string, +) -> ^ast.Expr { lhs, rhs := get_local_lhs_and_rhs(ast_context, offset, name) return rhs } -get_local_offset :: proc(ast_context: ^AstContext, offset: int, name: string) -> int { +get_local_offset :: proc( + ast_context: ^AstContext, + offset: int, + name: string, +) -> int { for _, locals in &ast_context.locals { if local_stack, ok := locals[name]; ok { for i := len(local_stack) - 1; i >= 0; i -= 1 { @@ -1137,7 +1437,7 @@ get_local_offset :: proc(ast_context: ^AstContext, offset: int, name: string) -> return -1 } else { return local_stack[i].offset - } + } } } } @@ -1146,7 +1446,13 @@ get_local_offset :: proc(ast_context: ^AstContext, offset: int, name: string) -> return -1 } -resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (Symbol, bool) { +resolve_type_identifier :: proc( + ast_context: ^AstContext, + node: ast.Ident, +) -> ( + Symbol, + bool, +) { using ast if ast_context.recursion_counter > 200 { @@ -1183,9 +1489,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S type = .Keyword, signature = node.name, pkg = ast_context.current_package, - value = SymbolUntypedValue { - type = .Bool, - }, + value = SymbolUntypedValue{type = .Bool}, } case: symbol = Symbol { @@ -1193,9 +1497,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S signature = node.name, name = ident.name, pkg = ast_context.current_package, - value = SymbolBasicValue { - ident = ident, - }, + value = SymbolBasicValue{ident = ident}, } } @@ -1206,20 +1508,21 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S symbol := Symbol { type = .Package, pkg = imp.name, - value = SymbolPackageValue {}, + value = SymbolPackageValue{}, } return symbol, true } } - } - - if local := get_local(ast_context, node.pos.offset, node.name); local != nil && ast_context.use_locals { + } + + if local := get_local(ast_context, node.pos.offset, node.name); + local != nil && ast_context.use_locals { is_distinct := false if dist, ok := local.derived.(^ast.Distinct_Type); ok { if dist.type != nil { - local = dist.type + local = dist.type is_distinct = true } } @@ -1231,37 +1534,62 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S case ^Ident: return_symbol, ok = resolve_type_identifier(ast_context, v^) case ^Union_Type: - return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_union_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Enum_Type: - return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_enum_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Struct_Type: - return_symbol, ok = make_symbol_struct_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_struct_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Bit_Set_Type: - return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_bitset_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Proc_Lit: if !v.type.generic { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, local, v.type^, node), true + return_symbol, ok = + make_symbol_procedure_from_ast( + ast_context, + local, + v.type^, + node, + ), + true } else { - if return_symbol, ok = resolve_generic_function(ast_context, v^); !ok { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, local, v.type^, node), true + if return_symbol, ok = resolve_generic_function( + ast_context, + v^, + ); !ok { + return_symbol, ok = + make_symbol_procedure_from_ast( + ast_context, + local, + v.type^, + node, + ), + true } } case ^Proc_Group: return_symbol, ok = resolve_function_overload(ast_context, v^) case ^Array_Type: - return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_array_from_ast(ast_context, v^, node), true case ^Dynamic_Array_Type: - return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_dynamic_array_from_ast(ast_context, v^, node), true case ^Map_Type: - return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_map_from_ast(ast_context, v^, node), true case ^Basic_Lit: return_symbol, ok = resolve_basic_lit(ast_context, v^) return_symbol.name = node.name - return_symbol.type = ast_context.variables[node.name] ? .Variable : .Constant + return_symbol.type = + ast_context.variables[node.name] ? .Variable : .Constant case: return_symbol, ok = resolve_type_expression(ast_context, local) } @@ -1271,7 +1599,8 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S return_symbol.flags |= {.Distinct} } - if is_variable, ok := ast_context.variables[node.name]; ok && is_variable { + if is_variable, ok := ast_context.variables[node.name]; + ok && is_variable { //return_symbol.name = node.name return_symbol.type = .Variable } @@ -1280,7 +1609,8 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S return return_symbol, ok - } else if global, ok := ast_context.globals[node.name]; ast_context.use_globals && ok { + } else if global, ok := ast_context.globals[node.name]; + ast_context.use_globals && ok { is_distinct := false if dist, ok := global.expr.derived.(^ast.Distinct_Type); ok { @@ -1297,39 +1627,66 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S case ^Ident: return_symbol, ok = resolve_type_identifier(ast_context, v^) case ^Struct_Type: - return_symbol, ok = make_symbol_struct_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_struct_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Bit_Set_Type: - return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_bitset_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Union_Type: - return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_union_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Enum_Type: - return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_enum_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Proc_Lit: if !v.type.generic { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, global.expr, v.type^, node), true + return_symbol, ok = + make_symbol_procedure_from_ast( + ast_context, + global.expr, + v.type^, + node, + ), + true } else { - if return_symbol, ok = resolve_generic_function(ast_context, v^); !ok { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, global.expr, v.type^, node), true + if return_symbol, ok = resolve_generic_function( + ast_context, + v^, + ); !ok { + return_symbol, ok = + make_symbol_procedure_from_ast( + ast_context, + global.expr, + v.type^, + node, + ), + true } } case ^Proc_Group: return_symbol, ok = resolve_function_overload(ast_context, v^) case ^Array_Type: - return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_array_from_ast(ast_context, v^, node), true case ^Dynamic_Array_Type: - return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_dynamic_array_from_ast(ast_context, v^, node), true case ^Map_Type: - return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_map_from_ast(ast_context, v^, node), true case ^Basic_Lit: return_symbol, ok = resolve_basic_lit(ast_context, v^) return_symbol.name = node.name return_symbol.type = global.mutable ? .Variable : .Constant case: - return_symbol, ok = resolve_type_expression(ast_context, global.expr) + return_symbol, ok = resolve_type_expression( + ast_context, + global.expr, + ) } if is_distinct { @@ -1337,7 +1694,8 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S return_symbol.flags |= {.Distinct} } - if is_variable, ok := ast_context.variables[node.name]; ok && is_variable { + if is_variable, ok := ast_context.variables[node.name]; + ok && is_variable { return_symbol.type = .Variable } @@ -1357,13 +1715,13 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S symbol := Symbol { type = .Package, pkg = node.name, - value = SymbolPackageValue {}, + value = SymbolPackageValue{}, } try_build_package(symbol.pkg) return symbol, true - } + } //last option is to check the index if symbol, ok := lookup(node.name, ast_context.current_package); ok { @@ -1375,7 +1733,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S symbol := Symbol { type = .Package, pkg = imp.name, - value = SymbolPackageValue {}, + value = SymbolPackageValue{}, } try_build_package(symbol.pkg) @@ -1408,10 +1766,14 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S } } - return Symbol {}, false + return Symbol{}, false } -expand_struct_usings :: proc(ast_context: ^AstContext, symbol: Symbol, value: SymbolStructValue) -> SymbolStructValue { +expand_struct_usings :: proc( + ast_context: ^AstContext, + symbol: Symbol, + value: SymbolStructValue, +) -> SymbolStructValue { names := slice.to_dynamic(value.names, ast_context.allocator) types := slice.to_dynamic(value.types, ast_context.allocator) ranges := slice.to_dynamic(value.ranges, ast_context.allocator) @@ -1444,19 +1806,22 @@ expand_struct_usings :: proc(ast_context: ^AstContext, symbol: Symbol, value: Sy for range in struct_value.ranges { append(&ranges, range) - } + } } } } - return { - names = names[:], - types = types[:], - ranges = ranges[:], - } + return {names = names[:], types = types[:], ranges = ranges[:]} } -resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: Symbol, ok := true) -> (Symbol, bool) { +resolve_symbol_return :: proc( + ast_context: ^AstContext, + symbol: Symbol, + ok := true, +) -> ( + Symbol, + bool, +) { if !ok { return symbol, ok } @@ -1468,17 +1833,24 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: Symbol, ok := tr return {}, false } } - + #partial switch v in &symbol.value { case SymbolProcedureGroupValue: - if symbol, ok := resolve_function_overload(ast_context, v.group.derived.(^ast.Proc_Group)^); ok { + if symbol, ok := resolve_function_overload( + ast_context, + v.group.derived.(^ast.Proc_Group)^, + ); ok { return symbol, true } else { return symbol, false } case SymbolProcedureValue: if v.generic { - if resolved_symbol, ok := resolve_generic_function(ast_context, v.arg_types, v.return_types); ok { + if resolved_symbol, ok := resolve_generic_function( + ast_context, + v.arg_types, + v.return_types, + ); ok { return resolved_symbol, ok } else { return symbol, true @@ -1512,7 +1884,7 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: Symbol, ok := tr expanded.value = expand_struct_usings(ast_context, symbol, v) return expanded, true } else { - return symbol, true + return symbol, true } case SymbolGenericValue: ret, ok := resolve_type_expression(ast_context, v.expr) @@ -1525,7 +1897,10 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: Symbol, ok := tr return symbol, true } -resolve_unresolved_symbol :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> bool { +resolve_unresolved_symbol :: proc( + ast_context: ^AstContext, + symbol: ^Symbol, +) -> bool { if symbol.type != .Unresolved { return true } @@ -1533,15 +1908,15 @@ resolve_unresolved_symbol :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> #partial switch v in symbol.value { case SymbolStructValue: symbol.type = .Struct - case SymbolPackageValue: + case SymbolPackageValue: symbol.type = .Package - case SymbolProcedureValue, SymbolProcedureGroupValue: + case SymbolProcedureValue, SymbolProcedureGroupValue: symbol.type = .Function - case SymbolUnionValue: + case SymbolUnionValue: symbol.type = .Enum - case SymbolEnumValue: + case SymbolEnumValue: symbol.type = .Enum - case SymbolBitSetValue: + case SymbolBitSetValue: symbol.type = .Enum case SymbolGenericValue: ast_context.current_package = symbol.pkg @@ -1556,17 +1931,30 @@ resolve_unresolved_symbol :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> return true } -resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (Symbol, bool) { +resolve_location_identifier :: proc( + ast_context: ^AstContext, + node: ast.Ident, +) -> ( + Symbol, + bool, +) { symbol: Symbol - if local, _ := get_local_lhs_and_rhs(ast_context, node.pos.offset, node.name); local != nil { + if local, _ := get_local_lhs_and_rhs( + ast_context, + node.pos.offset, + node.name, + ); local != nil { symbol.range = common.get_token_range(local, ast_context.file.src) uri := common.create_uri(local.pos.file, ast_context.allocator) symbol.pkg = ast_context.document_package symbol.uri = uri.uri return symbol, true } else if global, ok := ast_context.globals[node.name]; ok { - symbol.range = common.get_token_range(global.expr, ast_context.file.src) + symbol.range = common.get_token_range( + global.expr, + ast_context.file.src, + ) uri := common.create_uri(global.expr.pos.file, ast_context.allocator) symbol.pkg = ast_context.document_package symbol.uri = uri.uri @@ -1588,7 +1976,13 @@ resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) - return {}, false } -resolve_location_selector :: proc(ast_context: ^AstContext, selector: ^ast.Selector_Expr) -> (Symbol, bool) { +resolve_location_selector :: proc( + ast_context: ^AstContext, + selector: ^ast.Selector_Expr, +) -> ( + Symbol, + bool, +) { ast_context.use_locals = true ast_context.use_globals = true ast_context.current_package = ast_context.document_package @@ -1628,7 +2022,13 @@ resolve_location_selector :: proc(ast_context: ^AstContext, selector: ^ast.Selec } -resolve_first_symbol_from_binary_expression :: proc(ast_context: ^AstContext, binary: ^ast.Binary_Expr) -> (Symbol, bool) { +resolve_first_symbol_from_binary_expression :: proc( + ast_context: ^AstContext, + binary: ^ast.Binary_Expr, +) -> ( + Symbol, + bool, +) { //Fairly simple function to find the earliest identifier symbol in binary expression. if binary.left != nil { @@ -1638,7 +2038,10 @@ resolve_first_symbol_from_binary_expression :: proc(ast_context: ^AstContext, bi return s, ok } } else if _, ok := binary.left.derived.(^ast.Binary_Expr); ok { - if s, ok := resolve_first_symbol_from_binary_expression(ast_context, cast(^ast.Binary_Expr)binary.left); ok { + if s, ok := resolve_first_symbol_from_binary_expression( + ast_context, + cast(^ast.Binary_Expr)binary.left, + ); ok { return s, ok } } @@ -1650,7 +2053,10 @@ resolve_first_symbol_from_binary_expression :: proc(ast_context: ^AstContext, bi return s, ok } } else if _, ok := binary.right.derived.(^ast.Binary_Expr); ok { - if s, ok := resolve_first_symbol_from_binary_expression(ast_context, cast(^ast.Binary_Expr)binary.right); ok { + if s, ok := resolve_first_symbol_from_binary_expression( + ast_context, + cast(^ast.Binary_Expr)binary.right, + ); ok { return s, ok } } @@ -1659,7 +2065,13 @@ resolve_first_symbol_from_binary_expression :: proc(ast_context: ^AstContext, bi return {}, false } -find_position_in_call_param :: proc(ast_context: ^AstContext, call: ast.Call_Expr) -> (int, bool) { +find_position_in_call_param :: proc( + ast_context: ^AstContext, + call: ast.Call_Expr, +) -> ( + int, + bool, +) { if call.args == nil { return 0, false } @@ -1673,8 +2085,16 @@ find_position_in_call_param :: proc(ast_context: ^AstContext, call: ast.Call_Exp return len(call.args) - 1, true } -make_pointer_ast :: proc(ast_context: ^AstContext, elem: ^ast.Expr) -> ^ast.Pointer_Type { - pointer := new_type(ast.Pointer_Type, elem.pos, elem.end, ast_context.allocator) +make_pointer_ast :: proc( + ast_context: ^AstContext, + elem: ^ast.Expr, +) -> ^ast.Pointer_Type { + pointer := new_type( + ast.Pointer_Type, + elem.pos, + elem.end, + ast_context.allocator, + ) pointer.elem = elem return pointer } @@ -1691,10 +2111,13 @@ make_int_ast :: proc(ast_context: ^AstContext) -> ^ast.Ident { return ident } -make_int_basic_value :: proc(ast_context: ^AstContext, n: int) -> ^ast.Basic_Lit { +make_int_basic_value :: proc( + ast_context: ^AstContext, + n: int, +) -> ^ast.Basic_Lit { basic := new_type(ast.Basic_Lit, {}, {}, ast_context.allocator) basic.tok.text = fmt.tprintf("%v", n) - return basic + return basic } get_package_from_node :: proc(node: ast.Node) -> string { @@ -1722,16 +2145,21 @@ get_using_packages :: proc(ast_context: ^AstContext) -> []string { return usings } -make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v: ast.Proc_Type, name: ast.Ident) -> Symbol { +make_symbol_procedure_from_ast :: proc( + ast_context: ^AstContext, + n: ^ast.Node, + v: ast.Proc_Type, + name: ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(n^, ast_context.file.src), - type = .Function, - pkg = get_package_from_node(n^), - name = name.name, + type = .Function, + pkg = get_package_from_node(n^), + name = name.name, } return_types := make([dynamic]^ast.Field, ast_context.allocator) - arg_types := make([dynamic]^ast.Field, ast_context.allocator) + arg_types := make([dynamic]^ast.Field, ast_context.allocator) if v.results != nil { for ret in v.results.list { @@ -1753,25 +2181,29 @@ make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v symbol.value = SymbolProcedureValue { return_types = return_types[:], - arg_types = arg_types[:], - generic = v.generic, + arg_types = arg_types[:], + generic = v.generic, } return symbol } -make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type, name: ast.Ident) -> Symbol { +make_symbol_array_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Array_Type, + name: ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, - pkg = get_package_from_node(v.node), - name = name.name, + type = .Variable, + pkg = get_package_from_node(v.node), + name = name.name, } if v.len != nil { symbol.value = SymbolFixedArrayValue { expr = v.elem, - len = v.len, + len = v.len, } } else { symbol.value = SymbolSliceValue { @@ -1782,12 +2214,16 @@ make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type, return symbol } -make_symbol_dynamic_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Dynamic_Array_Type, name: ast.Ident) -> Symbol { +make_symbol_dynamic_array_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Dynamic_Array_Type, + name: ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, - pkg = get_package_from_node(v.node), - name = name.name, + type = .Variable, + pkg = get_package_from_node(v.node), + name = name.name, } symbol.value = SymbolDynamicArrayValue { @@ -1797,12 +2233,16 @@ make_symbol_dynamic_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Dyna return symbol } -make_symbol_multi_pointer_from_ast :: proc(ast_context: ^AstContext, v: ast.Multi_Pointer_Type, name: ast.Ident) -> Symbol { +make_symbol_multi_pointer_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Multi_Pointer_Type, + name: ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, - pkg = get_package_from_node(v.node), - name = name.name, + type = .Variable, + pkg = get_package_from_node(v.node), + name = name.name, } symbol.value = SymbolMultiPointer { @@ -1812,27 +2252,35 @@ make_symbol_multi_pointer_from_ast :: proc(ast_context: ^AstContext, v: ast.Mult return symbol } -make_symbol_map_from_ast :: proc(ast_context: ^AstContext, v: ast.Map_Type, name: ast.Ident) -> Symbol { +make_symbol_map_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Map_Type, + name: ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, - pkg = get_package_from_node(v.node), - name = name.name, + type = .Variable, + pkg = get_package_from_node(v.node), + name = name.name, } symbol.value = SymbolMapValue { - key = v.key, + key = v.key, value = v.value, } return symbol } -make_symbol_basic_type_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v: ^ast.Ident) -> Symbol { +make_symbol_basic_type_from_ast :: proc( + ast_context: ^AstContext, + n: ^ast.Node, + v: ^ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(n^, ast_context.file.src), - type = .Variable, - pkg = get_package_from_node(n^), + type = .Variable, + pkg = get_package_from_node(n^), } symbol.value = SymbolBasicValue { @@ -1842,12 +2290,17 @@ make_symbol_basic_type_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, return symbol } -make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, ident: ast.Ident, inlined := false) -> Symbol { +make_symbol_union_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Union_Type, + ident: ast.Ident, + inlined := false, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), - type = .Union, - pkg = get_package_from_node(v.node), - name = ident.name, + type = .Union, + pkg = get_package_from_node(v.node), + name = ident.name, } if inlined { @@ -1855,7 +2308,7 @@ make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, symbol.name = "union" } - types := make([dynamic]^ast.Expr, ast_context.allocator) + types := make([dynamic]^ast.Expr, ast_context.allocator) for variant in v.variants { if v.poly_params != nil { @@ -1876,12 +2329,17 @@ make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, return symbol } -make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, ident: ast.Ident, inlined := false) -> Symbol { +make_symbol_enum_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Enum_Type, + ident: ast.Ident, + inlined := false, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), - type = .Enum, - name = ident.name, - pkg = get_package_from_node(v.node), + type = .Enum, + name = ident.name, + pkg = get_package_from_node(v.node), } if inlined { @@ -1898,9 +2356,10 @@ make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, id } else if field, ok := n.derived.(^ast.Field_Value); ok { if ident, ok := field.field.derived.(^ast.Ident); ok { append(&names, ident.name) - } else if binary, ok := field.field.derived.(^ast.Binary_Expr); ok { + } else if binary, ok := field.field.derived.(^ast.Binary_Expr); + ok { append(&names, binary.left.derived.(^ast.Ident).name) - } + } } } @@ -1911,12 +2370,17 @@ make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, id return symbol } -make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Type, ident: ast.Ident, inlined := false) -> Symbol { +make_symbol_bitset_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Bit_Set_Type, + ident: ast.Ident, + inlined := false, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), - type = .Enum, - name = ident.name, - pkg = get_package_from_node(v.node), + type = .Enum, + name = ident.name, + pkg = get_package_from_node(v.node), } if inlined { @@ -1931,12 +2395,17 @@ make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Typ return symbol } -make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type, ident: ast.Ident, inlined := false) -> Symbol { +make_symbol_struct_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Struct_Type, + ident: ast.Ident, + inlined := false, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), - type = .Struct, - pkg = get_package_from_node(v.node), - name = ident.name, + type = .Struct, + pkg = get_package_from_node(v.node), + name = ident.name, } if inlined { @@ -1951,13 +2420,17 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type for field in v.fields.list { for n in field.names { - if identifier, ok := n.derived.(^ast.Ident); ok && field.type != nil { + if identifier, ok := n.derived.(^ast.Ident); + ok && field.type != nil { if identifier.name == "_" { continue } append(&names, identifier.name) if v.poly_params != nil { - append(&types, clone_type(field.type, ast_context.allocator, nil)) + append( + &types, + clone_type(field.type, ast_context.allocator, nil), + ) } else { append(&types, field.type) } @@ -1965,14 +2438,17 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type usings[identifier.name] = true } - append(&ranges, common.get_token_range(n, ast_context.file.src)) + append( + &ranges, + common.get_token_range(n, ast_context.file.src), + ) } } } symbol.value = SymbolStructValue { - names = names[:], - types = types[:], + names = names[:], + types = types[:], ranges = ranges[:], usings = usings, } @@ -1983,13 +2459,21 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type //TODO change the expand to not double copy the array, but just pass the dynamic arrays if len(usings) > 0 { - symbol.value = expand_struct_usings(ast_context, symbol, symbol.value.(SymbolStructValue)) + symbol.value = expand_struct_usings( + ast_context, + symbol, + symbol.value.(SymbolStructValue), + ) } return symbol } -resolve_poly_union :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_List, symbol: ^Symbol) { +resolve_poly_union :: proc( + ast_context: ^AstContext, + poly_params: ^ast.Field_List, + symbol: ^Symbol, +) { if ast_context.call == nil { return } @@ -2013,11 +2497,11 @@ resolve_poly_union :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_Lis if param.type == nil { continue } - + if poly, ok := param.type.derived.(^ast.Typeid_Type); ok { if ident, ok := name.derived.(^ast.Ident); ok { poly_map[ident.name] = ast_context.call.args[i] - } else if poly, ok := name.derived.(^ast.Poly_Type); ok { + } else if poly, ok := name.derived.(^ast.Poly_Type); ok { if poly.type != nil { poly_map[poly.type.name] = ast_context.call.args[i] } @@ -2027,7 +2511,7 @@ resolve_poly_union :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_Lis i += 1 } } - + for type, i in symbol_value.types { if ident, ok := type.derived.(^ast.Ident); ok { if expr, ok := poly_map[ident.name]; ok { @@ -2049,7 +2533,11 @@ resolve_poly_union :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_Lis } } -resolve_poly_struct :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_List, symbol: ^Symbol) { +resolve_poly_struct :: proc( + ast_context: ^AstContext, + poly_params: ^ast.Field_List, + symbol: ^Symbol, +) { if ast_context.call == nil { return } @@ -2073,11 +2561,11 @@ resolve_poly_struct :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_Li if param.type == nil { continue } - + if poly, ok := param.type.derived.(^ast.Typeid_Type); ok { if ident, ok := name.derived.(^ast.Ident); ok { poly_map[ident.name] = ast_context.call.args[i] - } else if poly, ok := name.derived.(^ast.Poly_Type); ok { + } else if poly, ok := name.derived.(^ast.Poly_Type); ok { if poly.type != nil { poly_map[poly.type.name] = ast_context.call.args[i] } @@ -2087,7 +2575,7 @@ resolve_poly_struct :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_Li i += 1 } } - + for type, i in symbol_value.types { if ident, ok := type.derived.(^ast.Ident); ok { if expr, ok := poly_map[ident.name]; ok { @@ -2120,7 +2608,12 @@ get_globals :: proc(file: ast.File, ast_context: ^AstContext) { } } -get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^AstContext, results: ^[dynamic]^ast.Expr) { +get_generic_assignment :: proc( + file: ast.File, + value: ^ast.Expr, + ast_context: ^AstContext, + results: ^[dynamic]^ast.Expr, +) { using ast ast_context.use_locals = true @@ -2131,7 +2624,7 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A get_generic_assignment(file, v.expr, ast_context, results) case ^Call_Expr: ast_context.call = cast(^ast.Call_Expr)value - + if symbol, ok := resolve_type_expression(ast_context, v.expr); ok { if procedure, ok := symbol.value.(SymbolProcedureValue); ok { for ret in procedure.return_types { @@ -2157,7 +2650,8 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A } case ^Type_Assertion: if v.type != nil { - if unary, ok := v.type.derived.(^ast.Unary_Expr); ok && unary.op.kind == .Question { + if unary, ok := v.type.derived.(^ast.Unary_Expr); + ok && unary.op.kind == .Question { append(results, cast(^ast.Expr)&v.node) } else { append(results, v.type) @@ -2173,7 +2667,11 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A } } -get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_context: ^AstContext) { +get_locals_value_decl :: proc( + file: ast.File, + value_decl: ast.Value_Decl, + ast_context: ^AstContext, +) { using ast if len(value_decl.names) <= 0 { @@ -2184,7 +2682,14 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co for name, i in value_decl.names { str := common.get_ast_node_string(value_decl.names[i], file.src) ast_context.variables[str] = value_decl.is_mutable - store_local(ast_context, name, value_decl.type, value_decl.end.offset, str, ast_context.local_id) + store_local( + ast_context, + name, + value_decl.type, + value_decl.end.offset, + str, + ast_context.local_id, + ) } return } @@ -2200,15 +2705,28 @@ 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) + result_i := min(len(results) - 1, i) str := common.get_ast_node_string(name, file.src) ast_context.in_package[str] = get_package_from_node(results[result_i]^) - store_local(ast_context, name, results[result_i], value_decl.end.offset, str, ast_context.local_id) + store_local( + ast_context, + name, + results[result_i], + value_decl.end.offset, + str, + ast_context.local_id, + ) ast_context.variables[str] = value_decl.is_mutable } } -get_locals_stmt :: proc(file: ast.File, stmt: ^ast.Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext, save_assign := false) { +get_locals_stmt :: proc( + file: ast.File, + stmt: ^ast.Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, + save_assign := false, +) { ast_context.use_locals = true ast_context.use_globals = true ast_context.current_package = ast_context.document_package @@ -2256,12 +2774,18 @@ get_locals_stmt :: proc(file: ast.File, stmt: ^ast.Stmt, ast_context: ^AstContex get_locals_stmt(file, stmt, ast_context, document_position) } case: - //log.debugf("default node local stmt %v", v); + //log.debugf("default node local stmt %v", v); } } -get_locals_block_stmt :: proc(file: ast.File, block: ast.Block_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { - if !(block.pos.offset <= document_position.position && document_position.position <= block.end.offset) { +get_locals_block_stmt :: proc( + file: ast.File, + block: ast.Block_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { + if !(block.pos.offset <= document_position.position && + document_position.position <= block.end.offset) { return } @@ -2280,11 +2804,28 @@ get_locals_using_stmt :: proc(stmt: ast.Using_Stmt, ast_context: ^AstContext) { } case SymbolStructValue: for name, i in v.names { - selector := new_type(ast.Selector_Expr, v.types[i].pos, v.types[i].end, ast_context.allocator) + selector := new_type( + ast.Selector_Expr, + v.types[i].pos, + v.types[i].end, + ast_context.allocator, + ) selector.expr = u - selector.field = new_type(ast.Ident, v.types[i].pos, v.types[i].end, ast_context.allocator) + selector.field = new_type( + ast.Ident, + v.types[i].pos, + v.types[i].end, + ast_context.allocator, + ) selector.field.name = name - store_local(ast_context, u, selector, 0, name, ast_context.local_id) + store_local( + ast_context, + u, + selector, + 0, + name, + ast_context.local_id, + ) ast_context.variables[name] = true } } @@ -2292,7 +2833,11 @@ get_locals_using_stmt :: proc(stmt: ast.Using_Stmt, ast_context: ^AstContext) { } } -get_locals_assign_stmt :: proc(file: ast.File, stmt: ast.Assign_Stmt, ast_context: ^AstContext) { +get_locals_assign_stmt :: proc( + file: ast.File, + stmt: ast.Assign_Stmt, + ast_context: ^AstContext, +) { using ast if stmt.lhs == nil || stmt.rhs == nil { @@ -2311,14 +2856,27 @@ get_locals_assign_stmt :: proc(file: ast.File, stmt: ast.Assign_Stmt, ast_contex for lhs, i in stmt.lhs { if ident, ok := lhs.derived.(^ast.Ident); ok { - store_local(ast_context, lhs, results[i], ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + lhs, + results[i], + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true } } } -get_locals_if_stmt :: proc(file: ast.File, stmt: ast.If_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { - if !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) { +get_locals_if_stmt :: proc( + file: ast.File, + stmt: ast.If_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { + if !(stmt.pos.offset <= document_position.position && + document_position.position <= stmt.end.offset) { return } @@ -2327,10 +2885,16 @@ get_locals_if_stmt :: proc(file: ast.File, stmt: ast.If_Stmt, ast_context: ^AstC get_locals_stmt(file, stmt.else_stmt, ast_context, document_position) } -get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { +get_locals_for_range_stmt :: proc( + file: ast.File, + stmt: ast.Range_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { using ast - if !(stmt.body.pos.offset <= document_position.position && document_position.position <= stmt.body.end.offset) { + if !(stmt.body.pos.offset <= document_position.position && + document_position.position <= stmt.body.end.offset) { return } @@ -2344,7 +2908,14 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont if binary.op.kind == .Range_Half { if len(stmt.vals) >= 1 { if ident, ok := stmt.vals[0].derived.(^Ident); ok { - store_local(ast_context, ident, make_int_ast(ast_context), ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + make_int_ast(ast_context), + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true } } @@ -2356,14 +2927,28 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont case SymbolMapValue: if len(stmt.vals) >= 1 { if ident, ok := stmt.vals[0].derived.(^Ident); ok { - store_local(ast_context, ident, v.key, ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + v.key, + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } } if len(stmt.vals) >= 2 { if ident, ok := stmt.vals[1].derived.(^Ident); ok { - store_local(ast_context, ident, v.value, ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + v.value, + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } @@ -2371,14 +2956,28 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont case SymbolDynamicArrayValue: if len(stmt.vals) >= 1 { if ident, ok := stmt.vals[0].derived.(^Ident); ok { - store_local(ast_context, ident, v.expr, ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + v.expr, + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } } if len(stmt.vals) >= 2 { if ident, ok := stmt.vals[1].derived.(^Ident); ok { - store_local(ast_context, ident, make_int_ast(ast_context), ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + make_int_ast(ast_context), + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } @@ -2386,7 +2985,14 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont case SymbolFixedArrayValue: if len(stmt.vals) >= 1 { if ident, ok := stmt.vals[0].derived.(^Ident); ok { - store_local(ast_context, ident, v.expr, ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + v.expr, + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } @@ -2394,7 +3000,14 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont if len(stmt.vals) >= 2 { if ident, ok := stmt.vals[1].derived.(^Ident); ok { - store_local(ast_context, ident, make_int_ast(ast_context), ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + make_int_ast(ast_context), + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } @@ -2402,26 +3015,46 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont case SymbolSliceValue: if len(stmt.vals) >= 1 { if ident, ok := stmt.vals[0].derived.(^Ident); ok { - store_local(ast_context, ident, v.expr, ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + v.expr, + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } } if len(stmt.vals) >= 2 { if ident, ok := stmt.vals[1].derived.(^Ident); ok { - store_local(ast_context, ident, make_int_ast(ast_context), ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + make_int_ast(ast_context), + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } } } } - + get_locals_stmt(file, stmt.body, ast_context, document_position) } -get_locals_for_stmt :: proc(file: ast.File, stmt: ast.For_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { - if !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) { +get_locals_for_stmt :: proc( + file: ast.File, + stmt: ast.For_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { + if !(stmt.pos.offset <= document_position.position && + document_position.position <= stmt.end.offset) { return } @@ -2429,18 +3062,30 @@ get_locals_for_stmt :: proc(file: ast.File, stmt: ast.For_Stmt, ast_context: ^As get_locals_stmt(file, stmt.body, ast_context, document_position) } -get_locals_switch_stmt :: proc(file: ast.File, stmt: ast.Switch_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { - if !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) { +get_locals_switch_stmt :: proc( + file: ast.File, + stmt: ast.Switch_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { + if !(stmt.pos.offset <= document_position.position && + document_position.position <= stmt.end.offset) { return } get_locals_stmt(file, stmt.body, ast_context, document_position) } -get_locals_type_switch_stmt :: proc(file: ast.File, stmt: ast.Type_Switch_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { +get_locals_type_switch_stmt :: proc( + file: ast.File, + stmt: ast.Type_Switch_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { using ast - if !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) { + if !(stmt.pos.offset <= document_position.position && + document_position.position <= stmt.end.offset) { return } @@ -2450,12 +3095,22 @@ get_locals_type_switch_stmt :: proc(file: ast.File, stmt: ast.Type_Switch_Stmt, if block, ok := stmt.body.derived.(^Block_Stmt); ok { for block_stmt in block.stmts { - if cause, ok := block_stmt.derived.(^Case_Clause); ok && cause.pos.offset <= document_position.position && document_position.position <= cause.end.offset { + if cause, ok := block_stmt.derived.(^Case_Clause); + ok && + cause.pos.offset <= document_position.position && + document_position.position <= cause.end.offset { tag := stmt.tag.derived.(^Assign_Stmt) if len(tag.lhs) == 1 && len(cause.list) == 1 { ident := tag.lhs[0].derived.(^Ident) - store_local(ast_context, ident, cause.list[0], ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + cause.list[0], + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true } @@ -2467,7 +3122,12 @@ get_locals_type_switch_stmt :: proc(file: ast.File, stmt: ast.Type_Switch_Stmt, } } -get_locals_proc_param_and_results :: proc(file: ast.File, function: ast.Proc_Lit, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { +get_locals_proc_param_and_results :: proc( + file: ast.File, + function: ast.Proc_Lit, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { proc_lit, ok := function.derived.(^ast.Proc_Lit) if !ok || proc_lit.body == nil { @@ -2479,19 +3139,37 @@ get_locals_proc_param_and_results :: proc(file: ast.File, function: ast.Proc_Lit for name in arg.names { if arg.type != nil { str := common.get_ast_node_string(name, file.src) - store_local(ast_context, name, arg.type, name.pos.offset, str, ast_context.local_id) + store_local( + ast_context, + name, + arg.type, + name.pos.offset, + str, + ast_context.local_id, + ) ast_context.variables[str] = true ast_context.parameters[str] = true if .Using in arg.flags { using_stmt: ast.Using_Stmt - using_stmt.list = make([]^ast.Expr, 1, context.temp_allocator) + using_stmt.list = make( + []^ast.Expr, + 1, + context.temp_allocator, + ) using_stmt.list[0] = arg.type get_locals_using_stmt(using_stmt, ast_context) } } else { str := common.get_ast_node_string(name, file.src) - store_local(ast_context, name, arg.default_value, name.pos.offset, str, ast_context.local_id) + store_local( + ast_context, + name, + arg.default_value, + name.pos.offset, + str, + ast_context.local_id, + ) ast_context.variables[str] = true ast_context.parameters[str] = true } @@ -2504,7 +3182,14 @@ get_locals_proc_param_and_results :: proc(file: ast.File, function: ast.Proc_Lit for name in result.names { if result.type != nil { str := common.get_ast_node_string(name, file.src) - store_local(ast_context, name, result.type, name.pos.offset, str, ast_context.local_id) + store_local( + ast_context, + name, + result.type, + name.pos.offset, + str, + ast_context.local_id, + ) ast_context.variables[str] = true ast_context.parameters[str] = true } @@ -2513,14 +3198,24 @@ get_locals_proc_param_and_results :: proc(file: ast.File, function: ast.Proc_Lit } } -get_locals :: proc(file: ast.File, function: ^ast.Node, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { +get_locals :: proc( + file: ast.File, + function: ^ast.Node, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { proc_lit, ok := function.derived.(^ast.Proc_Lit) if !ok || proc_lit.body == nil { return } - get_locals_proc_param_and_results(file, proc_lit^, ast_context, document_position) + get_locals_proc_param_and_results( + file, + proc_lit^, + ast_context, + document_position, + ) block: ^ast.Block_Stmt block, ok = proc_lit.body.derived.(^ast.Block_Stmt) @@ -2549,8 +3244,20 @@ ResolveReferenceFlag :: enum { StructElement, } -resolve_entire_file :: proc(document: ^Document, reference := "", flag := ResolveReferenceFlag.None, allocator := context.allocator) -> map[uintptr]SymbolAndNode { - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath, allocator) +resolve_entire_file :: proc( + document: ^Document, + reference := "", + flag := ResolveReferenceFlag.None, + allocator := context.allocator, +) -> map[uintptr]SymbolAndNode { + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + allocator, + ) get_globals(document.ast, &ast_context) @@ -2559,37 +3266,53 @@ resolve_entire_file :: proc(document: ^Document, reference := "", flag := Resolv symbols := make(map[uintptr]SymbolAndNode, 10000, allocator) for decl in document.ast.decls { - resolve_entire_decl(&ast_context, document, decl, &symbols, reference, flag, allocator) + resolve_entire_decl( + &ast_context, + document, + decl, + &symbols, + reference, + flag, + allocator, + ) clear(&ast_context.locals) } return symbols } -resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: ^ast.Node, symbols: ^map[uintptr]SymbolAndNode, reference := "", flag := ResolveReferenceFlag.None, allocator := context.allocator) { +resolve_entire_decl :: proc( + ast_context: ^AstContext, + document: ^Document, + decl: ^ast.Node, + symbols: ^map[uintptr]SymbolAndNode, + reference := "", + flag := ResolveReferenceFlag.None, + allocator := context.allocator, +) { Scope :: struct { offset: int, id: int, } - + Visit_Data :: struct { - ast_context: ^AstContext, - symbols: ^map[uintptr]SymbolAndNode, - scopes: [dynamic]Scope, - id_counter: int, - last_visit: ^ast.Node, + ast_context: ^AstContext, + symbols: ^map[uintptr]SymbolAndNode, + scopes: [dynamic]Scope, + id_counter: int, + last_visit: ^ast.Node, resolve_flag: ResolveReferenceFlag, - reference: string, - document: ^Document, + reference: string, + document: ^Document, } data := Visit_Data { - ast_context = ast_context, - symbols = symbols, - scopes = make([dynamic]Scope, allocator), + ast_context = ast_context, + symbols = symbols, + scopes = make([dynamic]Scope, allocator), resolve_flag = flag, - reference = reference, - document = document, + reference = reference, + document = document, } visit :: proc(visitor: ^ast.Visitor, node: ^ast.Node) -> ^ast.Visitor { @@ -2601,11 +3324,11 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: ast_context.use_locals = true ast_context.use_globals = true - data.last_visit = node; + data.last_visit = node //It's somewhat silly to check the scope everytime, but the alternative is to implement my own walker function. if len(data.scopes) > 0 { - current_scope := data.scopes[len(data.scopes)-1] + current_scope := data.scopes[len(data.scopes) - 1] if current_scope.offset < node.end.offset { clear_local_group(ast_context, current_scope.id) @@ -2613,12 +3336,12 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: pop(&data.scopes) if len(data.scopes) > 0 { - current_scope = data.scopes[len(data.scopes)-1] + current_scope = data.scopes[len(data.scopes) - 1] ast_context.local_id = current_scope.id } else { ast_context.local_id = 0 } - } + } } #partial switch v in node.derived { @@ -2639,8 +3362,18 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: position_context: DocumentPositionContext position_context.position = node.end.offset - get_locals_proc_param_and_results(ast_context.file, v^, ast_context, &position_context) - get_locals_stmt(ast_context.file, cast(^ast.Stmt)node, ast_context, &position_context) + get_locals_proc_param_and_results( + ast_context.file, + v^, + ast_context, + &position_context, + ) + get_locals_stmt( + ast_context.file, + cast(^ast.Stmt)node, + ast_context, + &position_context, + ) case ^ast.If_Stmt, ^ast.For_Stmt, ^ast.Range_Stmt, ^ast.Inline_Range_Stmt: scope: Scope scope.id = data.id_counter @@ -2653,73 +3386,92 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: position_context: DocumentPositionContext position_context.position = node.end.offset - get_locals_stmt(ast_context.file, cast(^ast.Stmt)node, ast_context, &position_context) + get_locals_stmt( + ast_context.file, + cast(^ast.Stmt)node, + ast_context, + &position_context, + ) } if data.resolve_flag == .None { - #partial switch v in node.derived { - case ^ast.Ident: + #partial switch v in node.derived { + case ^ast.Ident: if symbol, ok := resolve_type_identifier(ast_context, v^); ok { data.symbols[cast(uintptr)node] = SymbolAndNode { - node = v, + node = v, symbol = symbol, } - } + } case ^ast.Selector_Expr: - if symbol, ok := resolve_type_expression(ast_context, &v.node); ok { + if symbol, ok := resolve_type_expression(ast_context, &v.node); + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { - node = v, + node = v, symbol = symbol, } } case ^ast.Call_Expr: - if symbol, ok := resolve_type_expression(ast_context, &v.node); ok { + if symbol, ok := resolve_type_expression(ast_context, &v.node); + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { - node = v, + node = v, symbol = symbol, } - } + } } } else { - #partial done: switch v in node.derived { + #partial done: switch v in node.derived { case ^ast.Selector_Expr: - document : ^Document = data.document + document: ^Document = data.document position_context := DocumentPositionContext { position = v.pos.offset, } - get_document_position_decls(document.ast.decls[:], &position_context) + get_document_position_decls( + document.ast.decls[:], + &position_context, + ) - if symbol, ok := resolve_location_selector(ast_context, v); ok { + if symbol, ok := resolve_location_selector(ast_context, v); + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { - node = v, + node = v, symbol = symbol, } - } - case ^ast.Ident: + } + case ^ast.Ident: if data.resolve_flag == .Variable && v.name != data.reference { break done } - document : ^Document = data.document + document: ^Document = data.document position_context := DocumentPositionContext { position = v.pos.offset, } - get_document_position_decls(document.ast.decls[:], &position_context) + get_document_position_decls( + document.ast.decls[:], + &position_context, + ) - if position_context.field_value != nil && position_in_node(position_context.field_value.field, v.pos.offset) { + if position_context.field_value != nil && + position_in_node( + position_context.field_value.field, + v.pos.offset, + ) { break done } - if symbol, ok := resolve_location_identifier(ast_context, v^); ok { + if symbol, ok := resolve_location_identifier(ast_context, v^); + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { - node = v, + node = v, symbol = symbol, } - } + } } } @@ -2727,7 +3479,7 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: } visitor := ast.Visitor { - data = &data, + data = &data, visit = visit, } @@ -2739,11 +3491,29 @@ concatenate_symbol_information :: proc { concatenate_raw_string_information, } -concatenate_raw_symbol_information :: proc(ast_context: ^AstContext, symbol: Symbol, is_completion: bool) -> string { - return concatenate_raw_string_information(ast_context, symbol.pkg, symbol.name, symbol.signature, symbol.type, is_completion) +concatenate_raw_symbol_information :: proc( + ast_context: ^AstContext, + symbol: Symbol, + is_completion: bool, +) -> string { + return concatenate_raw_string_information( + ast_context, + symbol.pkg, + symbol.name, + symbol.signature, + symbol.type, + is_completion, + ) } -concatenate_raw_string_information :: proc(ast_context: ^AstContext, pkg: string, name: string, signature: string, type: SymbolType, is_completion: bool) -> string { +concatenate_raw_string_information :: proc( + ast_context: ^AstContext, + pkg: string, + name: string, + signature: string, + type: SymbolType, + is_completion: bool, +) -> string { pkg := path.base(pkg, false, context.temp_allocator) if type == .Package { @@ -2759,7 +3529,13 @@ concatenate_raw_string_information :: proc(ast_context: ^AstContext, pkg: string } } -unwrap_enum :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (SymbolEnumValue, bool) { +unwrap_enum :: proc( + ast_context: ^AstContext, + node: ^ast.Expr, +) -> ( + SymbolEnumValue, + bool, +) { if node == nil { return {}, false } @@ -2773,7 +3549,13 @@ unwrap_enum :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (SymbolEnumVal return {}, false } -unwrap_union :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (SymbolUnionValue, bool) { +unwrap_union :: proc( + ast_context: ^AstContext, + node: ^ast.Expr, +) -> ( + SymbolUnionValue, + bool, +) { if union_symbol, ok := resolve_type_expression(ast_context, node); ok { if union_value, ok := union_symbol.value.(SymbolUnionValue); ok { return union_value, true @@ -2783,9 +3565,18 @@ unwrap_union :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (SymbolUnionV return {}, false } -unwrap_bitset :: proc(ast_context: ^AstContext, bitset_symbol: Symbol) -> (SymbolEnumValue, bool) { +unwrap_bitset :: proc( + ast_context: ^AstContext, + bitset_symbol: Symbol, +) -> ( + SymbolEnumValue, + bool, +) { if bitset_value, ok := bitset_symbol.value.(SymbolBitSetValue); ok { - if enum_symbol, ok := resolve_type_expression(ast_context, bitset_value.expr); ok { + if enum_symbol, ok := resolve_type_expression( + ast_context, + bitset_value.expr, + ); ok { if enum_value, ok := enum_symbol.value.(SymbolEnumValue); ok { return enum_value, true } @@ -2795,7 +3586,12 @@ unwrap_bitset :: proc(ast_context: ^AstContext, bitset_symbol: Symbol) -> (Symbo return {}, false } -get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: Symbol, was_variable := false) -> string { +get_signature :: proc( + ast_context: ^AstContext, + ident: ast.Ident, + symbol: Symbol, + was_variable := false, +) -> string { if symbol.type == .Function { return symbol.signature } @@ -2814,51 +3610,79 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: Symbol case SymbolEnumValue: if is_variable { return symbol.name - } - else { + } else { return "enum" } case SymbolMapValue: - return strings.concatenate(a = {"map[", common.node_to_string(v.key), "]", common.node_to_string(v.value)}, allocator = ast_context.allocator) + return strings.concatenate( + a = { + "map[", + common.node_to_string(v.key), + "]", + common.node_to_string(v.value), + }, + allocator = ast_context.allocator, + ) case SymbolProcedureValue: return "proc" case SymbolStructValue: if is_variable { return symbol.name - } - else { + } else { return "struct" } case SymbolUnionValue: if is_variable { return symbol.name - } - else { + } else { return "union" } case SymbolMultiPointer: - return strings.concatenate(a = {"[^]", common.node_to_string(v.expr)}, allocator = ast_context.allocator) + return strings.concatenate( + a = {"[^]", common.node_to_string(v.expr)}, + allocator = ast_context.allocator, + ) case SymbolDynamicArrayValue: - return strings.concatenate(a = {"[dynamic]", common.node_to_string(v.expr)}, allocator = ast_context.allocator) + return strings.concatenate( + a = {"[dynamic]", common.node_to_string(v.expr)}, + allocator = ast_context.allocator, + ) case SymbolSliceValue: - return strings.concatenate(a = {"[]", common.node_to_string(v.expr)}, allocator = ast_context.allocator) + return strings.concatenate( + a = {"[]", common.node_to_string(v.expr)}, + allocator = ast_context.allocator, + ) case SymbolFixedArrayValue: - return strings.concatenate(a = {"[", common.node_to_string(v.len), "]", common.node_to_string(v.expr)}, allocator = ast_context.allocator) + return strings.concatenate( + a = { + "[", + common.node_to_string(v.len), + "]", + common.node_to_string(v.expr), + }, + allocator = ast_context.allocator, + ) case SymbolPackageValue: return "package" case SymbolUntypedValue: switch v.type { - case .Float: return "float" - case .String: return "string" - case .Bool: return "bool" - case .Integer: return "int" + case .Float: + return "float" + case .String: + return "string" + case .Bool: + return "bool" + case .Integer: + return "int" } } - + return "" } -position_in_proc_decl :: proc(position_context: ^DocumentPositionContext) -> bool { +position_in_proc_decl :: proc( + position_context: ^DocumentPositionContext, +) -> bool { if position_context.value_decl == nil { return false } @@ -2867,12 +3691,16 @@ position_in_proc_decl :: proc(position_context: ^DocumentPositionContext) -> boo return false } - if _, ok := position_context.value_decl.values[0].derived.(^ast.Proc_Type); ok { + if _, ok := position_context.value_decl.values[0].derived.(^ast.Proc_Type); + ok { return true } - if proc_lit, ok := position_context.value_decl.values[0].derived.(^ast.Proc_Lit); ok { - if proc_lit.type != nil && position_in_node(proc_lit.type, position_context.position) { + if proc_lit, ok := position_context.value_decl.values[ + 0 \ + ].derived.(^ast.Proc_Lit); ok { + if proc_lit.type != nil && + position_in_node(proc_lit.type, position_context.position) { return true } } @@ -2906,7 +3734,10 @@ is_lhs_comp_lit :: proc(position_context: ^DocumentPositionContext) -> bool { return true } -field_exists_in_comp_lit :: proc(comp_lit: ^ast.Comp_Lit, name: string) -> bool { +field_exists_in_comp_lit :: proc( + comp_lit: ^ast.Comp_Lit, + name: string, +) -> bool { for elem in comp_lit.elems { if field, ok := elem.derived.(^ast.Field_Value); ok { if field.field != nil { @@ -2925,7 +3756,10 @@ field_exists_in_comp_lit :: proc(comp_lit: ^ast.Comp_Lit, name: string) -> bool /* Parser gives ranges of expression, but not actually where the commas are placed. */ -get_call_commas :: proc(position_context: ^DocumentPositionContext, document: ^Document) { +get_call_commas :: proc( + position_context: ^DocumentPositionContext, + document: ^Document, +) { if position_context.call == nil { return } @@ -2942,12 +3776,18 @@ get_call_commas :: proc(position_context: ^DocumentPositionContext, document: ^D } for i := call.open.offset; i < call.close.offset; i += 1 { switch document.text[i] { - case '[': paren_count += 1 - case ']': paren_count -= 1 - case '{': brace_count += 1 - case '}': brace_count -= 1 - case '(': paren_count += 1 - case ')': paren_count -= 1 + case '[': + paren_count += 1 + case ']': + paren_count -= 1 + case '{': + brace_count += 1 + case '}': + brace_count -= 1 + case '(': + paren_count += 1 + case ')': + paren_count -= 1 case ',': if paren_count == 0 && brace_count == 0 && bracket_count == 0 { append(&commas, i) @@ -2966,10 +3806,13 @@ type_to_string :: proc(ast_context: ^AstContext, expr: ^ast.Expr) -> string { } } - return common.node_to_string(expr) + return common.node_to_string(expr) } -get_document_position_decls :: proc(decls: []^ast.Stmt, position_context: ^DocumentPositionContext) -> bool { +get_document_position_decls :: proc( + decls: []^ast.Stmt, + position_context: ^DocumentPositionContext, +) -> bool { exists_in_decl := false for decl in decls { if position_in_node(decl, position_context.position) { @@ -2988,14 +3831,24 @@ get_document_position_decls :: proc(decls: []^ast.Stmt, position_context: ^Docum /* Figure out what exactly is at the given position and whether it is in a function, struct, etc. */ -get_document_position_context :: proc(document: ^Document, position: common.Position, hint: DocumentPositionContextHint) -> (DocumentPositionContext, bool) { +get_document_position_context :: proc( + document: ^Document, + position: common.Position, + hint: DocumentPositionContextHint, +) -> ( + DocumentPositionContext, + bool, +) { position_context: DocumentPositionContext position_context.hint = hint position_context.file = document.ast position_context.line = position.line - absolute_position, ok := common.get_absolute_position(position, document.text) + absolute_position, ok := common.get_absolute_position( + position, + document.text, + ) if !ok { log.error("failed to get absolute position") @@ -3004,7 +3857,10 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi position_context.position = absolute_position - exists_in_decl := get_document_position_decls(document.ast.decls[:], &position_context) + exists_in_decl := get_document_position_decls( + document.ast.decls[:], + &position_context, + ) for import_stmt in document.ast.imports { if position_in_node(import_stmt, position_context.position) { @@ -3017,11 +3873,17 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi position_context.abort_completion = true } - if !position_in_node(position_context.comp_lit, position_context.position) { + if !position_in_node( + position_context.comp_lit, + position_context.position, + ) { position_context.comp_lit = nil } - if !position_in_node(position_context.parent_comp_lit, position_context.position) { + if !position_in_node( + position_context.parent_comp_lit, + position_context.position, + ) { position_context.parent_comp_lit = nil } @@ -3033,16 +3895,30 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi position_context.binary = nil } - if !position_in_node(position_context.parent_binary, position_context.position) { + if !position_in_node( + position_context.parent_binary, + position_context.position, + ) { position_context.parent_binary = nil } - if hint == .Completion && position_context.selector == nil && position_context.field == nil { - fallback_position_context_completion(document, position, &position_context) + if hint == .Completion && + position_context.selector == nil && + position_context.field == nil { + fallback_position_context_completion( + document, + position, + &position_context, + ) } - if (hint == .SignatureHelp || hint == .Completion) && position_context.call == nil { - fallback_position_context_signature(document, position, &position_context) + if (hint == .SignatureHelp || hint == .Completion) && + position_context.call == nil { + fallback_position_context_signature( + document, + position, + &position_context, + ) } if hint == .SignatureHelp { @@ -3053,16 +3929,20 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi } //terrible fallback code -fallback_position_context_completion :: proc(document: ^Document, position: common.Position, position_context: ^DocumentPositionContext) { - paren_count: int +fallback_position_context_completion :: proc( + document: ^Document, + position: common.Position, + position_context: ^DocumentPositionContext, +) { + paren_count: int bracket_count: int - end: int - start: int - empty_dot: bool - empty_arrow: bool - last_dot: bool - last_arrow: bool - dots_seen: int + end: int + start: int + empty_dot: bool + empty_arrow: bool + last_dot: bool + last_arrow: bool + dots_seen: int partial_arrow: bool i := position_context.position - 1 @@ -3110,11 +3990,21 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm } //yeah.. - if c == ' ' || c == '{' || c == ',' || - c == '}' || c == '^' || c == ':' || - c == '\n' || c == '\r' || c == '=' || - c == '<' || c == '-' || c == '!' || - c == '+' || c == '&'|| c == '|' { + if c == ' ' || + c == '{' || + c == ',' || + c == '}' || + c == '^' || + c == ':' || + c == '\n' || + c == '\r' || + c == '=' || + c == '<' || + c == '-' || + c == '!' || + c == '+' || + c == '&' || + c == '|' { start = i + 1 break } else if c == '>' { @@ -3130,14 +4020,16 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm if i >= 0 && position_context.file.src[end] == '.' { empty_dot = true end -= 1 - } else if i >= 0 && position_context.file.src[max(0, end - 1)] == '-' && position_context.file.src[end] == '>' { + } else if i >= 0 && + position_context.file.src[max(0, end - 1)] == '-' && + position_context.file.src[end] == '>' { empty_arrow = true end -= 2 position_context.arrow = true } begin_offset := max(0, start) - end_offset := max(start, end + 1) + end_offset := max(start, end + 1) line_offset := begin_offset if line_offset < len(position_context.file.src) { @@ -3176,17 +4068,22 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm } p := parser.Parser { - err = common.parser_warning_handler, //empty + err = common.parser_warning_handler, //empty warn = common.parser_warning_handler, //empty flags = {.Optional_Semicolons}, file = &position_context.file, } - tokenizer.init(&p.tok, str, position_context.file.fullpath, common.parser_warning_handler) + tokenizer.init( + &p.tok, + str, + position_context.file.fullpath, + common.parser_warning_handler, + ) p.tok.ch = ' ' p.tok.line_count = position.line + 1 - p.tok.line_offset = line_offset + p.tok.line_offset = line_offset p.tok.offset = begin_offset p.tok.read_offset = begin_offset @@ -3215,18 +4112,28 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm //this is most likely because of use of 'in', 'context', etc. //try to go back one dot. - src_with_dot := string(position_context.file.src[0:min(len(position_context.file.src), end_offset + 1)]) - last_dot := strings.last_index(src_with_dot, ".") + src_with_dot := string( + position_context.file.src[0:min( + len(position_context.file.src), + end_offset + 1, + )], + ) + last_dot := strings.last_index(src_with_dot, ".") if last_dot == -1 { return } - tokenizer.init(&p.tok, position_context.file.src[0:last_dot], position_context.file.fullpath, common.parser_warning_handler) + tokenizer.init( + &p.tok, + position_context.file.src[0:last_dot], + position_context.file.fullpath, + common.parser_warning_handler, + ) p.tok.ch = ' ' p.tok.line_count = position.line + 1 - p.tok.line_offset = line_offset + p.tok.line_offset = line_offset p.tok.offset = begin_offset p.tok.read_offset = begin_offset @@ -3261,8 +4168,12 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm } } -fallback_position_context_signature :: proc(document: ^Document, position: common.Position, position_context: ^DocumentPositionContext) { - end: int +fallback_position_context_signature :: proc( + document: ^Document, + position: common.Position, + position_context: ^DocumentPositionContext, +) { + end: int start: int i := position_context.position - 1 end = i @@ -3290,7 +4201,7 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo end -= 1 begin_offset := max(0, start) - end_offset := max(start, end + 1) + end_offset := max(start, end + 1) if end_offset - begin_offset <= 1 { return @@ -3299,12 +4210,17 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo str := position_context.file.src[0:end_offset] p := parser.Parser { - err = common.parser_warning_handler, //empty + err = common.parser_warning_handler, //empty warn = common.parser_warning_handler, //empty file = &position_context.file, } - tokenizer.init(&p.tok, str, position_context.file.fullpath, common.parser_warning_handler) + tokenizer.init( + &p.tok, + str, + position_context.file.fullpath, + common.parser_warning_handler, + ) p.tok.ch = ' ' p.tok.line_count = position.line @@ -3326,7 +4242,7 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo if _, ok := position_context.call.derived.(^ast.Proc_Type); ok { position_context.call = nil } - + //log.error(string(position_context.file.src[begin_offset:end_offset])); } @@ -3334,29 +4250,45 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo All these fallback functions are not perfect and should be fixed. A lot of weird use of the odin tokenizer and parser. */ -get_document_position ::proc { +get_document_position :: proc { get_document_position_array, get_document_position_dynamic_array, get_document_position_node, } -get_document_position_array :: proc(array: $A/[]^$T, position_context: ^DocumentPositionContext) { +get_document_position_array :: proc( + array: $A/[]^$T, + position_context: ^DocumentPositionContext, +) { for elem, i in array { get_document_position(elem, position_context) } } -get_document_position_dynamic_array :: proc(array: $A/[dynamic]^$T, position_context: ^DocumentPositionContext) { +get_document_position_dynamic_array :: proc( + array: $A/[dynamic]^$T, + position_context: ^DocumentPositionContext, +) { for elem, i in array { get_document_position(elem, position_context) } } -position_in_node :: proc(node: ^ast.Node, position: common.AbsolutePosition) -> bool { - return node != nil && node.pos.offset <= position && position <= node.end.offset +position_in_node :: proc( + node: ^ast.Node, + position: common.AbsolutePosition, +) -> bool { + return( + node != nil && + node.pos.offset <= position && + position <= node.end.offset \ + ) } -get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentPositionContext) { +get_document_position_node :: proc( + node: ^ast.Node, + position_context: ^DocumentPositionContext, +) { using ast if node == nil { @@ -3385,7 +4317,7 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP if position_in_node(n.body, position_context.position) { position_context.function = cast(^Proc_Lit)node get_document_position(n.body, position_context) - } + } case ^Comp_Lit: //only set this for the parent comp literal, since we will need to walk through it to infer types. if position_context.parent_comp_lit == nil { @@ -3410,19 +4342,23 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP case ^Paren_Expr: get_document_position(n.expr, position_context) case ^Call_Expr: - if position_context.hint == .SignatureHelp || position_context.hint == .Completion { + if position_context.hint == .SignatureHelp || + position_context.hint == .Completion { position_context.call = cast(^Expr)node } get_document_position(n.expr, position_context) get_document_position(n.args, position_context) case ^Selector_Expr: if position_context.hint == .Completion { - if n.field != nil && n.field.pos.line - 1 == position_context.line { + if n.field != nil && + n.field.pos.line - 1 == position_context.line { //The parser is not fault tolerant enough, relying on the fallback as the main completion parsing for now //position_context.selector = n.expr; //position_context.field = n.field; } - } else if (position_context.hint == .Definition || position_context.hint == .Hover) && n.field != nil { + } else if (position_context.hint == .Definition || + position_context.hint == .Hover) && + n.field != nil { position_context.selector = n.expr position_context.field = n.field position_context.selector_expr = cast(^Selector_Expr)node @@ -3533,7 +4469,8 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP get_document_position(n.attributes, position_context) for name in n.names { - if position_in_node(name, position_context.position) && n.end.line - 1 == position_context.line { + if position_in_node(name, position_context.position) && + n.end.line - 1 == position_context.line { position_context.abort_completion = true break } diff --git a/src/server/build.odin b/src/server/build.odin index 7abe95c..4f97dfd 100644 --- a/src/server/build.odin +++ b/src/server/build.odin @@ -17,22 +17,22 @@ import "shared:common" platform_os: map[string]bool = { "windows" = true, - "linux" = true, + "linux" = true, "essence" = true, - "js" = true, + "js" = true, "freebsd" = true, - "darwin" = true, - "wasm32" = true, + "darwin" = true, + "wasm32" = true, } os_enum_to_string: map[runtime.Odin_OS_Type]string = { - .Windows = "windows", - .Darwin = "darwin", - .Linux = "linux", - .Essence = "essence", - .FreeBSD = "freebsd", - .WASI = "wasi", - .JS = "js", + .Windows = "windows", + .Darwin = "darwin", + .Linux = "linux", + .Essence = "essence", + .FreeBSD = "freebsd", + .WASI = "wasi", + .JS = "js", .Freestanding = "freestanding", } @@ -41,7 +41,10 @@ try_build_package :: proc(pkg_name: string) { return } - matches, err := filepath.glob(fmt.tprintf("%v/*.odin", pkg_name), context.temp_allocator) + matches, err := filepath.glob( + fmt.tprintf("%v/*.odin", pkg_name), + context.temp_allocator, + ) if err != .None { log.errorf("Failed to glob %v for indexing package", pkg_name) @@ -49,9 +52,12 @@ try_build_package :: proc(pkg_name: string) { temp_arena: mem.Arena - mem.arena_init(&temp_arena, make([]byte, mem.Megabyte*25, runtime.default_allocator())) + mem.arena_init( + &temp_arena, + make([]byte, mem.Megabyte * 25, runtime.default_allocator()), + ) defer delete(temp_arena.data) - + { context.allocator = mem.arena_allocator(&temp_arena) @@ -59,7 +65,10 @@ try_build_package :: proc(pkg_name: string) { data, ok := os.read_entire_file(fullpath, context.allocator) if !ok { - log.errorf("failed to read entire file for indexing %v", fullpath) + log.errorf( + "failed to read entire file for indexing %v", + fullpath, + ) continue } @@ -82,8 +91,8 @@ try_build_package :: proc(pkg_name: string) { file := ast.File { fullpath = fullpath, - src = string(data), - pkg = pkg, + src = string(data), + pkg = pkg, } ok = parser.parse_file(&p, &file) @@ -101,18 +110,27 @@ try_build_package :: proc(pkg_name: string) { } } - build_cache.loaded_pkgs[strings.clone(pkg_name, indexer.index.collection.allocator)] = PackageCacheInfo { + build_cache.loaded_pkgs[ + strings.clone(pkg_name, indexer.index.collection.allocator) \ + ] = PackageCacheInfo { timestamp = time.now(), - } + } } setup_index :: proc() { - build_cache.loaded_pkgs = make(map[string]PackageCacheInfo, 50, context.allocator) - symbol_collection := make_symbol_collection(context.allocator, &common.config) + build_cache.loaded_pkgs = make( + map[string]PackageCacheInfo, + 50, + context.allocator, + ) + symbol_collection := make_symbol_collection( + context.allocator, + &common.config, + ) indexer.index = make_memory_index(symbol_collection) dir_exe := path.dir(os.args[0]) - + try_build_package(path.join({dir_exe, "builtin"})) } diff --git a/src/server/caches.odin b/src/server/caches.odin index 80128f4..55091fd 100644 --- a/src/server/caches.odin +++ b/src/server/caches.odin @@ -17,7 +17,9 @@ FileResolveCache :: struct { file_resolve_cache: FileResolveCache -resolve_entire_file_cached :: proc(document: ^Document) -> map[uintptr]SymbolAndNode{ +resolve_entire_file_cached :: proc( + document: ^Document, +) -> map[uintptr]SymbolAndNode { if document.uri.uri not_in file_resolve_cache.files { file_resolve_cache.files[document.uri.uri] = FileResolve { symbols = resolve_entire_file( @@ -27,9 +29,9 @@ resolve_entire_file_cached :: proc(document: ^Document) -> map[uintptr]SymbolAnd common.scratch_allocator(document.allocator), ), } - } + } - return file_resolve_cache.files[document.uri.uri].symbols; + return file_resolve_cache.files[document.uri.uri].symbols } BuildCache :: struct { @@ -40,4 +42,4 @@ PackageCacheInfo :: struct { timestamp: time.Time, } -build_cache: BuildCache
\ No newline at end of file +build_cache: BuildCache diff --git a/src/server/check.odin b/src/server/check.odin index 6d57b95..056783a 100644 --- a/src/server/check.odin +++ b/src/server/check.odin @@ -19,11 +19,11 @@ import "core:text/scanner" import "shared:common" is_package :: proc(file: string, pkg: string) { - + } check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { - data := make([]byte, mem.Kilobyte*10, context.temp_allocator) + data := make([]byte, mem.Kilobyte * 10, context.temp_allocator) buffer: []byte code: u32 @@ -35,7 +35,10 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { if k == "" || k == "core" || k == "vendor" { continue } - strings.write_string(&collection_builder, fmt.aprintf("-collection:%v=%v ", k, v)) + strings.write_string( + &collection_builder, + fmt.aprintf("-collection:%v=%v ", k, v), + ) } command: string @@ -47,32 +50,37 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { } if code, ok, buffer = common.run_executable( - fmt.tprintf("%v check %s %s -no-entry-point %s %s", - command, - path.dir(uri.path, context.temp_allocator), - strings.to_string(collection_builder), - config.checker_args, - ODIN_OS == .Linux || ODIN_OS == .Darwin ? "2>&1" : "", - ), - &data - ); !ok { - log.errorf("Odin check failed with code %v for file %v", code, uri.path) + fmt.tprintf( + "%v check %s %s -no-entry-point %s %s", + command, + path.dir(uri.path, context.temp_allocator), + strings.to_string(collection_builder), + config.checker_args, + ODIN_OS == .Linux || ODIN_OS == .Darwin ? "2>&1" : "", + ), + &data, + ); !ok { + log.errorf( + "Odin check failed with code %v for file %v", + code, + uri.path, + ) return - } + } s: scanner.Scanner scanner.init(&s, string(buffer)) - s.whitespace = {'\t', ' '} + s.whitespace = {'\t', ' '} current: rune ErrorSeperator :: struct { message: string, - line: int, - column: int, - uri: string, + line: int, + column: int, + uri: string, } error_seperators := make([dynamic]ErrorSeperator, context.temp_allocator) @@ -93,10 +101,10 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { if n == scanner.EOF { break loop - } + } } - error.uri = string(buffer[source_pos:s.src_pos-1]) + error.uri = string(buffer[source_pos:s.src_pos - 1]) left_paren := scanner.scan(&s) @@ -123,7 +131,7 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { if seperator != ':' { break loop - } + } rhs_digit := scanner.scan(&s) @@ -157,7 +165,7 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { continue } - error.message = string(buffer[source_pos:s.src_pos-1]) + error.message = string(buffer[source_pos:s.src_pos - 1]) error.column = column error.line = line @@ -169,32 +177,34 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { for error in error_seperators { if error.uri not_in errors { - errors[error.uri] = make([dynamic]Diagnostic, context.temp_allocator) - } - - append(&errors[error.uri], Diagnostic { - code = "checker", - severity = .Error, - range = { - start = { - character = 0, - line = error.line - 1, - }, - end = { - character = 0, - line = error.line, + errors[error.uri] = make( + [dynamic]Diagnostic, + context.temp_allocator, + ) + } + + append( + &errors[error.uri], + Diagnostic{ + code = "checker", + severity = .Error, + range = { + start = {character = 0, line = error.line - 1}, + end = {character = 0, line = error.line}, }, + message = error.message, }, - message = error.message, - }) + ) } - matches, err := filepath.glob(fmt.tprintf("%v/*.odin", path.dir(uri.path, context.temp_allocator))) + matches, err := filepath.glob( + fmt.tprintf("%v/*.odin", path.dir(uri.path, context.temp_allocator)), + ) if err == .None { for match in matches { uri := common.create_uri(match, context.temp_allocator) - + params := NotificationPublishDiagnosticsParams { uri = uri.uri, diagnostics = {}, @@ -202,8 +212,8 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { notifaction := Notification { jsonrpc = "2.0", - method = "textDocument/publishDiagnostics", - params = params, + method = "textDocument/publishDiagnostics", + params = params, } if writer != nil { @@ -216,14 +226,14 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { uri := common.create_uri(k, context.temp_allocator) params := NotificationPublishDiagnosticsParams { - uri = uri.uri, + uri = uri.uri, diagnostics = v[:], } notifaction := Notification { jsonrpc = "2.0", - method = "textDocument/publishDiagnostics", - params = params, + method = "textDocument/publishDiagnostics", + params = params, } if writer != nil { diff --git a/src/server/clone.odin b/src/server/clone.odin index 9a4af46..9db9ecb 100644 --- a/src/server/clone.odin +++ b/src/server/clone.odin @@ -10,7 +10,12 @@ import "core:intrinsics" import "core:reflect" _ :: intrinsics -new_type :: proc($T: typeid, pos, end: tokenizer.Pos, allocator: mem.Allocator) -> ^T { +new_type :: proc( + $T: typeid, + pos, + end: tokenizer.Pos, + allocator: mem.Allocator, +) -> ^T { n, _ := mem.new(T, allocator) n.pos = pos n.end = end @@ -33,7 +38,11 @@ clone_type :: proc { clone_dynamic_array, } -clone_array :: proc(array: $A/[]^$T, allocator: mem.Allocator, unique_strings: ^map[string]string) -> A { +clone_array :: proc( + array: $A/[]^$T, + allocator: mem.Allocator, + unique_strings: ^map[string]string, +) -> A { if len(array) == 0 { return nil } @@ -44,7 +53,11 @@ clone_array :: proc(array: $A/[]^$T, allocator: mem.Allocator, unique_strings: ^ return res } -clone_dynamic_array :: proc(array: $A/[dynamic]^$T, allocator: mem.Allocator, unique_strings: ^map[string]string) -> A { +clone_dynamic_array :: proc( + array: $A/[dynamic]^$T, + allocator: mem.Allocator, + unique_strings: ^map[string]string, +) -> A { if len(array) == 0 { return nil } @@ -52,25 +65,33 @@ clone_dynamic_array :: proc(array: $A/[dynamic]^$T, allocator: mem.Allocator, un for elem, i in array { res[i] = auto_cast clone_type(elem, allocator, unique_strings) } - return res + return res } -clone_expr :: proc(node: ^ast.Expr, allocator: mem.Allocator, unique_strings: ^map[string]string) -> ^ast.Expr { +clone_expr :: proc( + node: ^ast.Expr, + allocator: mem.Allocator, + unique_strings: ^map[string]string, +) -> ^ast.Expr { return cast(^ast.Expr)clone_node(node, allocator, unique_strings) } -clone_node :: proc(node: ^ast.Node, allocator: mem.Allocator, unique_strings: ^map[string]string) -> ^ast.Node { +clone_node :: proc( + node: ^ast.Node, + allocator: mem.Allocator, + unique_strings: ^map[string]string, +) -> ^ast.Node { using ast if node == nil { return nil } - size := size_of(Node) + size := size_of(Node) align := align_of(Node) ti := reflect.union_variant_type_info(node.derived) if ti != nil { elem := ti.variant.(reflect.Type_Info_Pointer).elem - size = elem.size + size = elem.size align = elem.align } @@ -90,13 +111,21 @@ clone_node :: proc(node: ^ast.Node, allocator: mem.Allocator, unique_strings: ^m res_ptr_any.id = ti.id if unique_strings != nil && node.pos.file != "" { - res.pos.file = get_index_unique_string(unique_strings, allocator, node.pos.file) + res.pos.file = get_index_unique_string( + unique_strings, + allocator, + node.pos.file, + ) } else { res.pos.file = node.pos.file } if unique_strings != nil && node.end.file != "" { - res.end.file = get_index_unique_string(unique_strings, allocator, node.end.file) + res.end.file = get_index_unique_string( + unique_strings, + allocator, + node.end.file, + ) } else { res.end.file = node.end.file } @@ -105,149 +134,197 @@ clone_node :: proc(node: ^ast.Node, allocator: mem.Allocator, unique_strings: ^m res_ptr := reflect.deref(res_ptr_any) - if de := reflect.struct_field_value_by_name(res_ptr, "derived_expr", true); de != nil { + if de := reflect.struct_field_value_by_name(res_ptr, "derived_expr", true); + de != nil { reflect.set_union_value(de, res_ptr_any) } - if ds := reflect.struct_field_value_by_name(res_ptr, "derived_stmt", true); ds != nil { + if ds := reflect.struct_field_value_by_name(res_ptr, "derived_stmt", true); + ds != nil { reflect.set_union_value(ds, res_ptr_any) } if res.derived != nil do #partial switch r in res.derived { - case ^Ident: - n := node.derived.(^Ident) + case ^Ident: + n := node.derived.(^Ident) - if unique_strings == nil { - r.name = strings.clone(n.name, allocator) - } else { - r.name = get_index_unique_string(unique_strings, allocator, n.name) - } - case ^Implicit: - n := node.derived.(^Implicit) - if unique_strings == nil { - r.tok.text = strings.clone(n.tok.text, allocator) - } else { - r.tok.text = get_index_unique_string(unique_strings, allocator, n.tok.text) - } - case ^Undef: - case ^Basic_Lit: - n := node.derived.(^Basic_Lit) - if unique_strings == nil { - r.tok.text = strings.clone(n.tok.text, allocator) - } else { - r.tok.text = get_index_unique_string(unique_strings, allocator, n.tok.text) - } - case ^Basic_Directive: - n := node.derived.(^Basic_Directive) - if unique_strings == nil { - r.name = strings.clone(n.name, allocator) - } else { - r.name = get_index_unique_string(unique_strings, allocator, n.name) - } - case ^Ellipsis: - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Tag_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Unary_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Binary_Expr: - r.left = clone_type(r.left, allocator, unique_strings) - r.right = clone_type(r.right, allocator, unique_strings) - case ^Paren_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Selector_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - r.field = auto_cast clone_type(r.field, allocator, unique_strings) - case ^Implicit_Selector_Expr: - r.field = auto_cast clone_type(r.field, allocator, unique_strings) - case ^Slice_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - r.low = clone_type(r.low, allocator, unique_strings) - r.high = clone_type(r.high, allocator, unique_strings) - case ^Attribute: - r.elems = clone_type(r.elems, allocator, unique_strings) - case ^Distinct_Type: - r.type = clone_type(r.type, allocator, unique_strings) - case ^Proc_Type: - r.params = auto_cast clone_type(r.params, allocator, unique_strings) - r.results = auto_cast clone_type(r.results, allocator, unique_strings) - case ^Pointer_Type: - r.elem = clone_type(r.elem, allocator, unique_strings) - case ^Array_Type: - r.len = clone_type(r.len, allocator, unique_strings) - r.elem = clone_type(r.elem, allocator, unique_strings) - r.tag = clone_type(r.tag, allocator, unique_strings) - case ^Dynamic_Array_Type: - r.elem = clone_type(r.elem, allocator, unique_strings) - r.tag = clone_type(r.tag, allocator, unique_strings) - case ^Struct_Type: - r.poly_params = auto_cast clone_type(r.poly_params, allocator, unique_strings) - r.align = clone_type(r.align, allocator, unique_strings) - r.fields = auto_cast clone_type(r.fields, allocator, unique_strings) - r.where_clauses = clone_type(r.where_clauses, allocator, unique_strings) - case ^Field: - r.names = clone_type(r.names, allocator, unique_strings) - r.type = clone_type(r.type, allocator, unique_strings) - r.default_value = clone_type(r.default_value, allocator, unique_strings) - case ^Field_List: - r.list = clone_type(r.list, allocator, unique_strings) - case ^Field_Value: - r.field = clone_type(r.field, allocator, unique_strings) - r.value = clone_type(r.value, allocator, unique_strings) - case ^Union_Type: - r.poly_params = auto_cast clone_type(r.poly_params, allocator, unique_strings) - r.align = clone_type(r.align, allocator, unique_strings) - r.variants = clone_type(r.variants, allocator, unique_strings) - r.where_clauses = clone_type(r.where_clauses, allocator, unique_strings) - case ^Enum_Type: - r.base_type = clone_type(r.base_type, allocator, unique_strings) - r.fields = clone_type(r.fields, allocator, unique_strings) - case ^Bit_Set_Type: - r.elem = clone_type(r.elem, allocator, unique_strings) - r.underlying = clone_type(r.underlying, allocator, unique_strings) - case ^Map_Type: - r.key = clone_type(r.key, allocator, unique_strings) - r.value = clone_type(r.value, allocator, unique_strings) - case ^Call_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - r.args = clone_type(r.args, allocator, unique_strings) - case ^Typeid_Type: - r.specialization = clone_type(r.specialization, allocator, unique_strings) - case ^Ternary_When_Expr: - r.x = clone_type(r.x, allocator, unique_strings) - r.cond = clone_type(r.cond, allocator, unique_strings) - r.y = clone_type(r.y, allocator, unique_strings) - case ^Poly_Type: - r.type = auto_cast clone_type(r.type, allocator, unique_strings) - r.specialization = clone_type(r.specialization, allocator, unique_strings) - case ^Proc_Group: - r.args = clone_type(r.args, allocator, unique_strings) - case ^Comp_Lit: - r.type = clone_type(r.type, allocator, unique_strings) - r.elems = clone_type(r.elems, allocator, unique_strings) - case ^Proc_Lit: - r.type = cast(^Proc_Type)clone_type(cast(^Node)r.type, allocator, unique_strings) - r.body = nil - r.where_clauses = nil - case ^Helper_Type: - r.type = clone_type(r.type, allocator, unique_strings) - case ^Type_Cast: - r.type = clone_type(r.type, allocator, unique_strings) - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Deref_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Index_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - r.index = clone_type(r.index, allocator, unique_strings) - case ^Multi_Pointer_Type: - r.elem = clone_type(r.elem, allocator, unique_strings) - case ^Matrix_Type: - r.elem = clone_type(r.elem, allocator, unique_strings) - case ^Type_Assertion: - r.expr = clone_type(r.expr, allocator, unique_strings) - r.type = clone_type(r.type, allocator, unique_strings) - case: + if unique_strings == nil { + r.name = strings.clone(n.name, allocator) + } else { + r.name = get_index_unique_string( + unique_strings, + allocator, + n.name, + ) + } + case ^Implicit: + n := node.derived.(^Implicit) + if unique_strings == nil { + r.tok.text = strings.clone(n.tok.text, allocator) + } else { + r.tok.text = get_index_unique_string( + unique_strings, + allocator, + n.tok.text, + ) + } + case ^Undef: + case ^Basic_Lit: + n := node.derived.(^Basic_Lit) + if unique_strings == nil { + r.tok.text = strings.clone(n.tok.text, allocator) + } else { + r.tok.text = get_index_unique_string( + unique_strings, + allocator, + n.tok.text, + ) + } + case ^Basic_Directive: + n := node.derived.(^Basic_Directive) + if unique_strings == nil { + r.name = strings.clone(n.name, allocator) + } else { + r.name = get_index_unique_string( + unique_strings, + allocator, + n.name, + ) + } + case ^Ellipsis: + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Tag_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Unary_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Binary_Expr: + r.left = clone_type(r.left, allocator, unique_strings) + r.right = clone_type(r.right, allocator, unique_strings) + case ^Paren_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Selector_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + r.field = auto_cast clone_type(r.field, allocator, unique_strings) + case ^Implicit_Selector_Expr: + r.field = auto_cast clone_type(r.field, allocator, unique_strings) + case ^Slice_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + r.low = clone_type(r.low, allocator, unique_strings) + r.high = clone_type(r.high, allocator, unique_strings) + case ^Attribute: + r.elems = clone_type(r.elems, allocator, unique_strings) + case ^Distinct_Type: + r.type = clone_type(r.type, allocator, unique_strings) + case ^Proc_Type: + r.params = + auto_cast clone_type(r.params, allocator, unique_strings) + r.results = + auto_cast clone_type(r.results, allocator, unique_strings) + case ^Pointer_Type: + r.elem = clone_type(r.elem, allocator, unique_strings) + case ^Array_Type: + r.len = clone_type(r.len, allocator, unique_strings) + r.elem = clone_type(r.elem, allocator, unique_strings) + r.tag = clone_type(r.tag, allocator, unique_strings) + case ^Dynamic_Array_Type: + r.elem = clone_type(r.elem, allocator, unique_strings) + r.tag = clone_type(r.tag, allocator, unique_strings) + case ^Struct_Type: + r.poly_params = + auto_cast clone_type(r.poly_params, allocator, unique_strings) + r.align = clone_type(r.align, allocator, unique_strings) + r.fields = + auto_cast clone_type(r.fields, allocator, unique_strings) + r.where_clauses = clone_type( + r.where_clauses, + allocator, + unique_strings, + ) + case ^Field: + r.names = clone_type(r.names, allocator, unique_strings) + r.type = clone_type(r.type, allocator, unique_strings) + r.default_value = clone_type( + r.default_value, + allocator, + unique_strings, + ) + case ^Field_List: + r.list = clone_type(r.list, allocator, unique_strings) + case ^Field_Value: + r.field = clone_type(r.field, allocator, unique_strings) + r.value = clone_type(r.value, allocator, unique_strings) + case ^Union_Type: + r.poly_params = + auto_cast clone_type(r.poly_params, allocator, unique_strings) + r.align = clone_type(r.align, allocator, unique_strings) + r.variants = clone_type(r.variants, allocator, unique_strings) + r.where_clauses = clone_type( + r.where_clauses, + allocator, + unique_strings, + ) + case ^Enum_Type: + r.base_type = clone_type(r.base_type, allocator, unique_strings) + r.fields = clone_type(r.fields, allocator, unique_strings) + case ^Bit_Set_Type: + r.elem = clone_type(r.elem, allocator, unique_strings) + r.underlying = clone_type(r.underlying, allocator, unique_strings) + case ^Map_Type: + r.key = clone_type(r.key, allocator, unique_strings) + r.value = clone_type(r.value, allocator, unique_strings) + case ^Call_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + r.args = clone_type(r.args, allocator, unique_strings) + case ^Typeid_Type: + r.specialization = clone_type( + r.specialization, + allocator, + unique_strings, + ) + case ^Ternary_When_Expr: + r.x = clone_type(r.x, allocator, unique_strings) + r.cond = clone_type(r.cond, allocator, unique_strings) + r.y = clone_type(r.y, allocator, unique_strings) + case ^Poly_Type: + r.type = auto_cast clone_type(r.type, allocator, unique_strings) + r.specialization = clone_type( + r.specialization, + allocator, + unique_strings, + ) + case ^Proc_Group: + r.args = clone_type(r.args, allocator, unique_strings) + case ^Comp_Lit: + r.type = clone_type(r.type, allocator, unique_strings) + r.elems = clone_type(r.elems, allocator, unique_strings) + case ^Proc_Lit: + r.type = + cast(^Proc_Type)clone_type( + cast(^Node)r.type, + allocator, + unique_strings, + ) + r.body = nil + r.where_clauses = nil + case ^Helper_Type: + r.type = clone_type(r.type, allocator, unique_strings) + case ^Type_Cast: + r.type = clone_type(r.type, allocator, unique_strings) + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Deref_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Index_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + r.index = clone_type(r.index, allocator, unique_strings) + case ^Multi_Pointer_Type: + r.elem = clone_type(r.elem, allocator, unique_strings) + case ^Matrix_Type: + r.elem = clone_type(r.elem, allocator, unique_strings) + case ^Type_Assertion: + r.expr = clone_type(r.expr, allocator, unique_strings) + r.type = clone_type(r.type, allocator, unique_strings) + case: //fmt.logf("Unhandled node kind: %T", r) - } + } return res } diff --git a/src/server/collector.odin b/src/server/collector.odin index 464b22f..5cea81f 100644 --- a/src/server/collector.odin +++ b/src/server/collector.odin @@ -24,33 +24,49 @@ get_index_unique_string :: proc { get_index_unique_string_collection_raw, } -get_index_unique_string_collection :: proc(collection: ^SymbolCollection, s: string) -> string { - return get_index_unique_string_collection_raw(&collection.unique_strings, collection.allocator, s) +get_index_unique_string_collection :: proc( + collection: ^SymbolCollection, + s: string, +) -> string { + return get_index_unique_string_collection_raw( + &collection.unique_strings, + collection.allocator, + s, + ) } -get_index_unique_string_collection_raw :: proc(unique_strings: ^map[string]string, allocator: mem.Allocator, s: string) -> string { +get_index_unique_string_collection_raw :: proc( + unique_strings: ^map[string]string, + allocator: mem.Allocator, + s: string, +) -> string { if _, ok := unique_strings[s]; !ok { str := strings.clone(s, allocator) - unique_strings[str] = str + unique_strings[str] = str } return unique_strings[s] } -make_symbol_collection :: proc(allocator := context.allocator, config: ^common.Config) -> SymbolCollection { - return SymbolCollection { - allocator = allocator, - config = config, - packages = make(map[string]map[string]Symbol, 16, allocator), - unique_strings = make(map[string]string, 16, allocator), - } +make_symbol_collection :: proc( + allocator := context.allocator, + config: ^common.Config, +) -> SymbolCollection { + return( + SymbolCollection{ + allocator = allocator, + config = config, + packages = make(map[string]map[string]Symbol, 16, allocator), + unique_strings = make(map[string]string, 16, allocator), + } \ + ) } delete_symbol_collection :: proc(collection: SymbolCollection) { for k, v in collection.packages { for k2, v2 in v { free_symbol(v2, collection.allocator) - } + } } for k, v in collection.unique_strings { @@ -65,13 +81,23 @@ delete_symbol_collection :: proc(collection: SymbolCollection) { delete(collection.unique_strings) } -collect_procedure_fields :: proc(collection: ^SymbolCollection, proc_type: ^ast.Proc_Type, arg_list: ^ast.Field_List, return_list: ^ast.Field_List, package_map: map[string]string) -> SymbolProcedureValue { +collect_procedure_fields :: proc( + collection: ^SymbolCollection, + proc_type: ^ast.Proc_Type, + arg_list: ^ast.Field_List, + return_list: ^ast.Field_List, + package_map: map[string]string, +) -> SymbolProcedureValue { returns := make([dynamic]^ast.Field, 0, collection.allocator) args := make([dynamic]^ast.Field, 0, collection.allocator) if return_list != nil { for ret in return_list.list { - cloned := cast(^ast.Field)clone_type(ret, collection.allocator, &collection.unique_strings) + cloned := cast(^ast.Field)clone_type( + ret, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) append(&returns, cloned) } @@ -79,7 +105,11 @@ collect_procedure_fields :: proc(collection: ^SymbolCollection, proc_type: ^ast. if arg_list != nil { for arg in arg_list.list { - cloned := cast(^ast.Field)clone_type(arg, collection.allocator, &collection.unique_strings) + cloned := cast(^ast.Field)clone_type( + arg, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) append(&args, cloned) } @@ -87,13 +117,18 @@ collect_procedure_fields :: proc(collection: ^SymbolCollection, proc_type: ^ast. value := SymbolProcedureValue { return_types = returns[:], - arg_types = args[:], - generic = proc_type.generic, + arg_types = args[:], + generic = proc_type.generic, } return value } -collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.Struct_Type, package_map: map[string]string, file: ast.File) -> SymbolStructValue { +collect_struct_fields :: proc( + collection: ^SymbolCollection, + struct_type: ast.Struct_Type, + package_map: map[string]string, + file: ast.File, +) -> SymbolStructValue { names := make([dynamic]string, 0, collection.allocator) types := make([dynamic]^ast.Expr, 0, collection.allocator) usings := make(map[string]bool, 0, collection.allocator) @@ -104,7 +139,11 @@ collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.St ident := n.derived.(^ast.Ident) append(&names, get_index_unique_string(collection, ident.name)) - cloned := clone_type(field.type, collection.allocator, &collection.unique_strings) + cloned := clone_type( + field.type, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) append(&types, cloned) @@ -117,17 +156,25 @@ collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.St } value := SymbolStructValue { - names = names[:], - types = types[:], + names = names[:], + types = types[:], ranges = ranges[:], usings = usings, - poly = cast(^ast.Field_List)clone_type(struct_type.poly_params, collection.allocator, &collection.unique_strings), + poly = cast(^ast.Field_List)clone_type( + struct_type.poly_params, + collection.allocator, + &collection.unique_strings, + ), } return value } -collect_enum_fields :: proc(collection: ^SymbolCollection, fields: []^ast.Expr, package_map: map[string]string) -> SymbolEnumValue { +collect_enum_fields :: proc( + collection: ^SymbolCollection, + fields: []^ast.Expr, + package_map: map[string]string, +) -> SymbolEnumValue { names := make([dynamic]string, 0, collection.allocator) //ERROR no hover on n in the for, but elsewhere is fine @@ -137,9 +184,16 @@ collect_enum_fields :: proc(collection: ^SymbolCollection, fields: []^ast.Expr, } else if field, ok := n.derived.(^ast.Field_Value); ok { if ident, ok := field.field.derived.(^ast.Ident); ok { append(&names, get_index_unique_string(collection, ident.name)) - } else if binary, ok := field.field.derived.(^ast.Binary_Expr); ok { - append(&names, get_index_unique_string(collection, binary.left.derived.(^ast.Ident).name)) - } + } else if binary, ok := field.field.derived.(^ast.Binary_Expr); + ok { + append( + &names, + get_index_unique_string( + collection, + binary.left.derived.(^ast.Ident).name, + ), + ) + } } } @@ -150,95 +204,155 @@ collect_enum_fields :: proc(collection: ^SymbolCollection, fields: []^ast.Expr, return value } -collect_union_fields :: proc(collection: ^SymbolCollection, union_type: ast.Union_Type, package_map: map[string]string) -> SymbolUnionValue { +collect_union_fields :: proc( + collection: ^SymbolCollection, + union_type: ast.Union_Type, + package_map: map[string]string, +) -> SymbolUnionValue { types := make([dynamic]^ast.Expr, 0, collection.allocator) for variant in union_type.variants { - cloned := clone_type(variant, collection.allocator, &collection.unique_strings) + cloned := clone_type( + variant, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) append(&types, cloned) } value := SymbolUnionValue { types = types[:], - poly = cast(^ast.Field_List)clone_type(union_type.poly_params, collection.allocator, &collection.unique_strings), + poly = cast(^ast.Field_List)clone_type( + union_type.poly_params, + collection.allocator, + &collection.unique_strings, + ), } return value } -collect_bitset_field :: proc(collection: ^SymbolCollection, bitset_type: ast.Bit_Set_Type, package_map: map[string]string) -> SymbolBitSetValue { - cloned := clone_type(bitset_type.elem, collection.allocator, &collection.unique_strings) +collect_bitset_field :: proc( + collection: ^SymbolCollection, + bitset_type: ast.Bit_Set_Type, + package_map: map[string]string, +) -> SymbolBitSetValue { + cloned := clone_type( + bitset_type.elem, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) - return SymbolBitSetValue { - expr = cloned, - } + return SymbolBitSetValue{expr = cloned} } -collect_slice :: proc(collection: ^SymbolCollection, array: ast.Array_Type, package_map: map[string]string) -> SymbolFixedArrayValue { - elem := clone_type(array.elem, collection.allocator, &collection.unique_strings) - len := clone_type(array.len, collection.allocator, &collection.unique_strings) +collect_slice :: proc( + collection: ^SymbolCollection, + array: ast.Array_Type, + package_map: map[string]string, +) -> SymbolFixedArrayValue { + elem := clone_type( + array.elem, + collection.allocator, + &collection.unique_strings, + ) + len := clone_type( + array.len, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(elem, package_map, collection) replace_package_alias(len, package_map, collection) - return SymbolFixedArrayValue { - expr = elem, - len = len, - } + return SymbolFixedArrayValue{expr = elem, len = len} } -collect_array :: proc(collection: ^SymbolCollection, array: ast.Array_Type, package_map: map[string]string) -> SymbolSliceValue { - elem := clone_type(array.elem, collection.allocator, &collection.unique_strings) +collect_array :: proc( + collection: ^SymbolCollection, + array: ast.Array_Type, + package_map: map[string]string, +) -> SymbolSliceValue { + elem := clone_type( + array.elem, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(elem, package_map, collection) - return SymbolSliceValue { - expr = elem, - } + return SymbolSliceValue{expr = elem} } -collect_map :: proc(collection: ^SymbolCollection, m: ast.Map_Type, package_map: map[string]string) -> SymbolMapValue { - key := clone_type(m.key, collection.allocator, &collection.unique_strings) - value := clone_type(m.value, collection.allocator, &collection.unique_strings) +collect_map :: proc( + collection: ^SymbolCollection, + m: ast.Map_Type, + package_map: map[string]string, +) -> SymbolMapValue { + key := clone_type(m.key, collection.allocator, &collection.unique_strings) + value := clone_type( + m.value, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(key, package_map, collection) replace_package_alias(value, package_map, collection) - return SymbolMapValue { - key = key, - value = value, - } + return SymbolMapValue{key = key, value = value} } -collect_dynamic_array :: proc(collection: ^SymbolCollection, array: ast.Dynamic_Array_Type, package_map: map[string]string) -> SymbolDynamicArrayValue { - elem := clone_type(array.elem, collection.allocator, &collection.unique_strings) +collect_dynamic_array :: proc( + collection: ^SymbolCollection, + array: ast.Dynamic_Array_Type, + package_map: map[string]string, +) -> SymbolDynamicArrayValue { + elem := clone_type( + array.elem, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(elem, package_map, collection) - return SymbolDynamicArrayValue { - expr = elem, - } + return SymbolDynamicArrayValue{expr = elem} } -collect_multi_pointer :: proc(collection: ^SymbolCollection, array: ast.Multi_Pointer_Type, package_map: map[string]string) -> SymbolMultiPointer { - elem := clone_type(array.elem, collection.allocator, &collection.unique_strings) +collect_multi_pointer :: proc( + collection: ^SymbolCollection, + array: ast.Multi_Pointer_Type, + package_map: map[string]string, +) -> SymbolMultiPointer { + elem := clone_type( + array.elem, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(elem, package_map, collection) - return SymbolMultiPointer { - expr = elem, - } + return SymbolMultiPointer{expr = elem} } -collect_generic :: proc(collection: ^SymbolCollection, expr: ^ast.Expr, package_map: map[string]string, uri: string) -> SymbolGenericValue { +collect_generic :: proc( + collection: ^SymbolCollection, + expr: ^ast.Expr, + package_map: map[string]string, + uri: string, +) -> SymbolGenericValue { //Bit hacky right now, but it's hopefully a temporary solution. //In the c package code it uses a documentation package(builtin). if selector, ok := expr.derived.(^ast.Selector_Expr); ok { if ident, ok := selector.expr.derived.(^ast.Ident); ok { - if ident.name == "builtin" && strings.contains(uri, "Odin/core/c/c.odin") { - cloned := clone_type(selector.field, collection.allocator, &collection.unique_strings) + if ident.name == "builtin" && + strings.contains(uri, "Odin/core/c/c.odin") { + cloned := clone_type( + selector.field, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) value := SymbolGenericValue { expr = cloned, @@ -248,7 +362,11 @@ collect_generic :: proc(collection: ^SymbolCollection, expr: ^ast.Expr, package_ } } - cloned := clone_type(expr, collection.allocator, &collection.unique_strings) + cloned := clone_type( + expr, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) value := SymbolGenericValue { @@ -258,7 +376,11 @@ collect_generic :: proc(collection: ^SymbolCollection, expr: ^ast.Expr, package_ return value } -collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: string) -> common.Error { +collect_symbols :: proc( + collection: ^SymbolCollection, + file: ast.File, + uri: string, +) -> common.Error { forward, _ := filepath.to_slash(file.fullpath, context.temp_allocator) directory := path.dir(forward, context.temp_allocator) package_map := get_package_mapping(file, collection.config, directory) @@ -293,27 +415,52 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri token_type = .Function if v.type != nil { - symbol.value = collect_procedure_fields(collection, v.type, v.type.params, v.type.results, package_map) + symbol.value = collect_procedure_fields( + collection, + v.type, + v.type.params, + v.type.results, + package_map, + ) } case ^ast.Proc_Type: token = v^ token_type = .Function - symbol.value = collect_procedure_fields(collection, cast(^ast.Proc_Type)col_expr, v.params, v.results, package_map) + symbol.value = collect_procedure_fields( + collection, + cast(^ast.Proc_Type)col_expr, + v.params, + v.results, + package_map, + ) case ^ast.Proc_Group: token = v^ token_type = .Function symbol.value = SymbolProcedureGroupValue { - group = clone_type(col_expr, collection.allocator, &collection.unique_strings), + group = clone_type( + col_expr, + collection.allocator, + &collection.unique_strings, + ), } case ^ast.Struct_Type: token = v^ token_type = .Struct - symbol.value = collect_struct_fields(collection, v^, package_map, file) + symbol.value = collect_struct_fields( + collection, + v^, + package_map, + file, + ) symbol.signature = "struct" case ^ast.Enum_Type: token = v^ token_type = .Enum - symbol.value = collect_enum_fields(collection, v.fields, package_map) + symbol.value = collect_enum_fields( + collection, + v.fields, + package_map, + ) symbol.signature = "enum" case ^ast.Union_Type: token = v^ @@ -347,7 +494,12 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri symbol.value = collect_multi_pointer(collection, v^, package_map) case ^ast.Basic_Lit: token = v^ - symbol.value = collect_generic(collection, col_expr, package_map, uri) + symbol.value = collect_generic( + collection, + col_expr, + package_map, + uri, + ) if expr.mutable { token_type = .Variable } else { @@ -355,14 +507,25 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri } case ^ast.Ident: token = v^ - symbol.value = collect_generic(collection, col_expr, package_map, uri) + symbol.value = collect_generic( + collection, + col_expr, + package_map, + uri, + ) if expr.mutable { token_type = .Variable } else { token_type = .Unresolved } - case: // default - symbol.value = collect_generic(collection, col_expr, package_map, uri) + case: + // default + symbol.value = collect_generic( + collection, + col_expr, + package_map, + uri, + ) if expr.mutable { token_type = .Variable } else { @@ -375,7 +538,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri symbol.name = get_index_unique_string(collection, name) symbol.type = token_type symbol.doc = common.get_doc(expr.docs, collection.allocator) - + if expr.builtin || strings.contains(uri, "builtin.odin") { symbol.pkg = "$builtin" } else if strings.contains(uri, "intrinsics.odin") { @@ -397,34 +560,42 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri } symbol.uri = get_index_unique_string(collection, uri) - + pkg: ^map[string]Symbol ok: bool if pkg, ok = &collection.packages[symbol.pkg]; !ok { - collection.packages[symbol.pkg] = make(map[string]Symbol, 100, collection.allocator) + collection.packages[symbol.pkg] = make( + map[string]Symbol, + 100, + collection.allocator, + ) pkg = &collection.packages[symbol.pkg] - } + } if v, ok := pkg[symbol.name]; !ok || v.name == "" { pkg[symbol.name] = symbol } else { free_symbol(symbol, collection.allocator) - } + } } return .None } Reference :: struct { - identifiers: [dynamic]common.Location, - selectors: map[string][dynamic]common.Range, + identifiers: [dynamic]common.Location, + selectors: map[string][dynamic]common.Range, } /* Gets the map from import alias to absolute package directory */ -get_package_mapping :: proc(file: ast.File, config: ^common.Config, directory: string) -> map[string]string { +get_package_mapping :: proc( + file: ast.File, + config: ^common.Config, + directory: string, +) -> map[string]string { package_map := make(map[string]string, 0, context.temp_allocator) for imp, index in file.imports { @@ -441,7 +612,10 @@ get_package_mapping :: proc(file: ast.File, config: ^common.Config, directory: s name: string - full := path.join(elems = {dir, p}, allocator = context.temp_allocator) + full := path.join( + elems = {dir, p}, + allocator = context.temp_allocator, + ) if imp.name.text != "" { name = imp.name.text @@ -453,7 +627,10 @@ get_package_mapping :: proc(file: ast.File, config: ^common.Config, directory: s } else { name: string - full := path.join(elems = {directory, imp.fullpath[1:len(imp.fullpath) - 1]}, allocator = context.temp_allocator) + full := path.join( + elems = {directory, imp.fullpath[1:len(imp.fullpath) - 1]}, + allocator = context.temp_allocator, + ) full = path.clean(full, context.temp_allocator) if imp.name.text != "" { @@ -481,23 +658,39 @@ replace_package_alias :: proc { replace_package_alias_dynamic_array, } -replace_package_alias_array :: proc(array: $A/[]^$T, package_map: map[string]string, collection: ^SymbolCollection) { +replace_package_alias_array :: proc( + array: $A/[]^$T, + package_map: map[string]string, + collection: ^SymbolCollection, +) { for elem, i in array { replace_package_alias(elem, package_map, collection) } } -replace_package_alias_dynamic_array :: proc(array: $A/[dynamic]^$T, package_map: map[string]string, collection: ^SymbolCollection) { +replace_package_alias_dynamic_array :: proc( + array: $A/[dynamic]^$T, + package_map: map[string]string, + collection: ^SymbolCollection, +) { for elem, i in array { replace_package_alias(elem, package_map, collection) } } -replace_package_alias_expr :: proc(node: ^ast.Expr, package_map: map[string]string, collection: ^SymbolCollection) { +replace_package_alias_expr :: proc( + node: ^ast.Expr, + package_map: map[string]string, + collection: ^SymbolCollection, +) { replace_package_alias_node(node, package_map, collection) } -replace_package_alias_node :: proc(node: ^ast.Node, package_map: map[string]string, collection: ^SymbolCollection) { +replace_package_alias_node :: proc( + node: ^ast.Node, + package_map: map[string]string, + collection: ^SymbolCollection, +) { using ast if node == nil { diff --git a/src/server/completion.odin b/src/server/completion.odin index a3b80c1..2f695af 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -32,20 +32,38 @@ Completion_Type :: enum { Package, } -get_completion_list :: proc(document: ^Document, position: common.Position, completion_context: CompletionContext) -> (CompletionList, bool) { +get_completion_list :: proc( + document: ^Document, + position: common.Position, + completion_context: CompletionContext, +) -> ( + CompletionList, + bool, +) { list: CompletionList - position_context, ok := get_document_position_context(document, position, .Completion) + position_context, ok := get_document_position_context( + document, + position, + .Completion, + ) if !ok || position_context.abort_completion { return list, true } - if position_context.import_stmt == nil && strings.contains_any(completion_context.triggerCharacter, "/:\"") { + if position_context.import_stmt == nil && + strings.contains_any(completion_context.triggerCharacter, "/:\"") { return list, true } - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) get_globals(document.ast, &ast_context) @@ -53,7 +71,12 @@ get_completion_list :: proc(document: ^Document, position: common.Position, comp ast_context.value_decl = position_context.value_decl if position_context.function != nil { - get_locals(document.ast, position_context.function, &ast_context, &position_context) + get_locals( + document.ast, + position_context.function, + &ast_context, + &position_context, + ) } completion_type: Completion_Type = .Identifier @@ -78,12 +101,17 @@ get_completion_list :: proc(document: ^Document, position: common.Position, comp completion_type = .Package } - if position_context.switch_type_stmt != nil && position_context.case_clause != nil { - if assign, ok := position_context.switch_type_stmt.tag.derived.(^ast.Assign_Stmt); ok && assign.rhs != nil && len(assign.rhs) == 1 { + if position_context.switch_type_stmt != nil && + position_context.case_clause != nil { + if assign, ok := position_context.switch_type_stmt.tag.derived.(^ast.Assign_Stmt); + ok && assign.rhs != nil && len(assign.rhs) == 1 { ast_context.use_globals = true ast_context.use_locals = true - if symbol, ok := resolve_type_expression(&ast_context, assign.rhs[0]); ok { + if symbol, ok := resolve_type_expression( + &ast_context, + assign.rhs[0], + ); ok { if union_value, ok := symbol.value.(SymbolUnionValue); ok { completion_type = .Switch_Type } @@ -111,21 +139,29 @@ get_completion_list :: proc(document: ^Document, position: common.Position, comp return list, true } -get_attribute_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { - +get_attribute_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { + } -get_directive_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_directive_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { list.isIncomplete = false - + items := make([dynamic]CompletionItem, context.temp_allocator) /* Right now just return all the possible completions, but later on I should give the context specific ones */ - directive_list := []string { + directive_list := []string{ "file", "line", "packed", @@ -150,8 +186,8 @@ get_directive_completion :: proc(ast_context: ^AstContext, position_context: ^Do for elem in directive_list { item := CompletionItem { detail = elem, - label = elem, - kind = .Constant, + label = elem, + kind = .Constant, } append(&items, item) @@ -160,30 +196,53 @@ get_directive_completion :: proc(ast_context: ^AstContext, position_context: ^Do list.items = items[:] } -get_comp_lit_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_comp_lit_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { items := make([dynamic]CompletionItem, context.temp_allocator) if position_context.parent_comp_lit.type == nil { return } - if symbol, ok := resolve_type_expression(ast_context, position_context.parent_comp_lit.type); ok { - if comp_symbol, _, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok { - ast_context.current_package = comp_symbol.pkg; + if symbol, ok := resolve_type_expression( + ast_context, + position_context.parent_comp_lit.type, + ); ok { + if comp_symbol, _, ok := resolve_type_comp_literal( + ast_context, + position_context, + symbol, + position_context.parent_comp_lit, + ); ok { + ast_context.current_package = comp_symbol.pkg #partial switch v in comp_symbol.value { case SymbolStructValue: for name, i in v.names { ast_context.current_package = comp_symbol.pkg - if resolved, ok := resolve_type_expression(ast_context, v.types[i]); ok { - if field_exists_in_comp_lit(position_context.comp_lit, name) { + if resolved, ok := resolve_type_expression( + ast_context, + v.types[i], + ); ok { + if field_exists_in_comp_lit( + position_context.comp_lit, + name, + ) { continue } item := CompletionItem { - label = name, - kind = .Field, - detail = fmt.tprintf("%v.%v: %v", comp_symbol.name, name, common.node_to_string(v.types[i])), + label = name, + kind = .Field, + detail = fmt.tprintf( + "%v.%v: %v", + comp_symbol.name, + name, + common.node_to_string(v.types[i]), + ), documentation = resolved.doc, } @@ -197,7 +256,11 @@ get_comp_lit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc list.items = items[:] } -get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_selector_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { items := make([dynamic]CompletionItem, context.temp_allocator) ast_context.current_package = ast_context.document_package @@ -208,13 +271,18 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc ast_context.use_locals = true ast_context.use_globals = true - selector, ok = resolve_type_expression(ast_context, position_context.selector) + selector, ok = resolve_type_expression( + ast_context, + position_context.selector, + ) if !ok { return } - if selector.type != .Variable && selector.type != .Package && selector.type != .Enum { + if selector.type != .Variable && + selector.type != .Package && + selector.type != .Enum { return } @@ -235,7 +303,10 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc if s, ok := selector.value.(SymbolProcedureValue); ok { if len(s.return_types) == 1 { - if selector, ok = resolve_type_expression(ast_context, s.return_types[0].type); !ok { + if selector, ok = resolve_type_expression( + ast_context, + s.return_types[0].type, + ); !ok { return } } @@ -265,7 +336,7 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc containsCoord += 1 } } - } + } if containsColor == 1 && containsCoord == 1 { save := expr_len @@ -277,13 +348,18 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc expr_len -= 1 item := CompletionItem { - label = fmt.tprintf("%v%c", field, k), - kind = .Property, - detail = fmt.tprintf("%v%c: %v", field, k, common.node_to_string(v.expr)), + label = fmt.tprintf("%v%c", field, k), + kind = .Property, + detail = fmt.tprintf( + "%v%c: %v", + field, + k, + common.node_to_string(v.expr), + ), } append(&items, item) } - + expr_len = save for k in swizzle_coord_components { @@ -294,13 +370,18 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc expr_len -= 1 item := CompletionItem { - label = fmt.tprintf("%v%c", field, k), - kind = .Property, - detail = fmt.tprintf("%v%c: %v", field, k, common.node_to_string(v.expr)), + label = fmt.tprintf("%v%c", field, k), + kind = .Property, + detail = fmt.tprintf( + "%v%c: %v", + field, + k, + common.node_to_string(v.expr), + ), } append(&items, item) } - } + } if containsColor > 1 { for k in swizzle_color_components { @@ -311,9 +392,15 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc expr_len -= 1 item := CompletionItem { - label = fmt.tprintf("%v%c", field, k), - kind = .Property, - detail = fmt.tprintf("%v%c: [%v]%v", field, k, containsColor, common.node_to_string(v.expr)), + label = fmt.tprintf("%v%c", field, k), + kind = .Property, + detail = fmt.tprintf( + "%v%c: [%v]%v", + field, + k, + containsColor, + common.node_to_string(v.expr), + ), } append(&items, item) } @@ -326,13 +413,19 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc expr_len -= 1 item := CompletionItem { - label = fmt.tprintf("%v%c", field, k), - kind = .Property, - detail = fmt.tprintf("%v%c: [%v]%v", field, k, containsCoord, common.node_to_string(v.expr)), + label = fmt.tprintf("%v%c", field, k), + kind = .Property, + detail = fmt.tprintf( + "%v%c: [%v]%v", + field, + k, + containsCoord, + common.node_to_string(v.expr), + ), } append(&items, item) } - } + } case SymbolUnionValue: list.isIncomplete = false @@ -343,16 +436,35 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc base := path.base(symbol.pkg, false, context.temp_allocator) item := CompletionItem { - kind = .EnumMember, - detail = fmt.tprintf("%v", selector.name), + kind = .EnumMember, + detail = fmt.tprintf("%v", selector.name), documentation = symbol.doc, } - if symbol.pkg == ast_context.document_package || base == "runtime" || base == "$builtin" { - item.label = fmt.aprintf("(%v%v)", common.repeat("^", symbol.pointers, context.temp_allocator), common.node_to_string(type, true)) + if symbol.pkg == ast_context.document_package || + base == "runtime" || + base == "$builtin" { + item.label = fmt.aprintf( + "(%v%v)", + common.repeat( + "^", + symbol.pointers, + context.temp_allocator, + ), + common.node_to_string(type, true), + ) } else { - item.label = fmt.aprintf("(%v%v.%v)", common.repeat("^", symbol.pointers, context.temp_allocator), path.base(symbol.pkg, false, context.temp_allocator), common.node_to_string(type, true)) - } + item.label = fmt.aprintf( + "(%v%v.%v)", + common.repeat( + "^", + symbol.pointers, + context.temp_allocator, + ), + path.base(symbol.pkg, false, context.temp_allocator), + common.node_to_string(type, true), + ) + } append(&items, item) } @@ -363,8 +475,8 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc for name in v.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = fmt.tprintf("%v.%v", selector.name, name), } append(&items, item) @@ -380,8 +492,10 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc ast_context.current_package = ast_context.document_package } - if symbol, ok := resolve_type_expression(ast_context, v.types[i]); ok { - if expr, ok := position_context.selector.derived.(^ast.Selector_Expr); ok { + if symbol, ok := resolve_type_expression(ast_context, v.types[i]); + ok { + if expr, ok := position_context.selector.derived.(^ast.Selector_Expr); + ok { if expr.op.text == "->" && symbol.type != .Function { continue } @@ -392,9 +506,14 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } item := CompletionItem { - label = name, - kind = .Field, - detail = fmt.tprintf("%v.%v: %v", selector.name, name, type_to_string(ast_context, v.types[i])), + label = name, + kind = .Field, + detail = fmt.tprintf( + "%v.%v: %v", + selector.name, + name, + type_to_string(ast_context, v.types[i]), + ), documentation = symbol.doc, } @@ -402,9 +521,13 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } else { //just give some generic symbol with name. item := CompletionItem { - label = symbol.name, - kind = .Field, - detail = fmt.tprintf("%v: %v", name, common.node_to_string(v.types[i])), + label = symbol.name, + kind = .Field, + detail = fmt.tprintf( + "%v: %v", + name, + common.node_to_string(v.types[i]), + ), documentation = symbol.doc, } @@ -423,45 +546,62 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc resolve_unresolved_symbol(ast_context, &symbol) build_procedure_symbol_signature(&symbol) - + item := CompletionItem { - label = symbol.name, - kind = cast(CompletionItemKind)symbol.type, - detail = concatenate_symbol_information(ast_context, symbol, true), + label = symbol.name, + kind = cast(CompletionItemKind)symbol.type, + detail = concatenate_symbol_information( + ast_context, + symbol, + true, + ), documentation = symbol.doc, } if symbol.type == .Function && common.config.enable_snippets { item.insertText = fmt.tprintf("%v($0)", item.label) item.insertTextFormat = .Snippet - item.command.command = "editor.action.triggerParameterHints" - item.deprecated = .Deprecated in symbol.flags + item.command.command = + "editor.action.triggerParameterHints" + item.deprecated = .Deprecated in symbol.flags } append(&items, item) } } else { - log.errorf("Failed to fuzzy search, field: %v, package: %v", field, selector.pkg) + log.errorf( + "Failed to fuzzy search, field: %v, package: %v", + field, + selector.pkg, + ) return } case SymbolDynamicArrayValue: list.isIncomplete = false - append_magic_dynamic_array_completion(position_context, selector, &items) + append_magic_dynamic_array_completion( + position_context, + selector, + &items, + ) case SymbolMapValue: - list.isIncomplete = false + list.isIncomplete = false append_magic_map_completion(position_context, selector, &items) } list.items = items[:] } -get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_implicit_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { items := make([dynamic]CompletionItem, context.temp_allocator) list.isIncomplete = false selector: Symbol - + ast_context.use_locals = true ast_context.use_globals = true @@ -472,12 +612,16 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } //value decl infer a : My_Enum = .* - if position_context.value_decl != nil && position_context.value_decl.type != nil { - if enum_value, ok := unwrap_enum(ast_context, position_context.value_decl.type); ok { + if position_context.value_decl != nil && + position_context.value_decl.type != nil { + if enum_value, ok := unwrap_enum( + ast_context, + position_context.value_decl.type, + ); ok { for name in enum_value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } append(&items, item) @@ -489,14 +633,18 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } //enum switch infer - if position_context.switch_stmt != nil && position_context.case_clause != nil && position_context.switch_stmt.cond != nil { + if position_context.switch_stmt != nil && + position_context.case_clause != nil && + position_context.switch_stmt.cond != nil { used_enums := make(map[string]bool, 5, context.temp_allocator) - if block, ok := position_context.switch_stmt.body.derived.(^ast.Block_Stmt); ok { + if block, ok := position_context.switch_stmt.body.derived.(^ast.Block_Stmt); + ok { for stmt in block.stmts { if case_clause, ok := stmt.derived.(^ast.Case_Clause); ok { for name in case_clause.list { - if implicit, ok := name.derived.(^ast.Implicit_Selector_Expr); ok { + if implicit, ok := name.derived.(^ast.Implicit_Selector_Expr); + ok { used_enums[implicit.field.name] = true } } @@ -504,15 +652,18 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } - if enum_value, ok := unwrap_enum(ast_context, position_context.switch_stmt.cond); ok { + if enum_value, ok := unwrap_enum( + ast_context, + position_context.switch_stmt.cond, + ); ok { for name in enum_value.names { if name in used_enums { continue } item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -524,15 +675,21 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } - if position_context.assign != nil && position_context.assign.lhs != nil && len(position_context.assign.lhs) == 1 && is_bitset_assignment_operator(position_context.assign.op.text) { + if position_context.assign != nil && + position_context.assign.lhs != nil && + len(position_context.assign.lhs) == 1 && + is_bitset_assignment_operator(position_context.assign.op.text) { //bitsets - if symbol, ok := resolve_type_expression(ast_context, position_context.assign.lhs[0]); ok { + if symbol, ok := resolve_type_expression( + ast_context, + position_context.assign.lhs[0], + ); ok { if value, ok := unwrap_bitset(ast_context, symbol); ok { for name in value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -545,14 +702,19 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } - if position_context.comp_lit != nil && position_context.parent_binary != nil && is_bitset_binary_operator(position_context.binary.op.text) { + if position_context.comp_lit != nil && + position_context.parent_binary != nil && + is_bitset_binary_operator(position_context.binary.op.text) { //bitsets - if symbol, ok := resolve_first_symbol_from_binary_expression(ast_context, position_context.parent_binary); ok { + if symbol, ok := resolve_first_symbol_from_binary_expression( + ast_context, + position_context.parent_binary, + ); ok { if value, ok := unwrap_bitset(ast_context, symbol); ok { for name in value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -574,17 +736,26 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc field_name: string if position_context.field_value != nil { - if field, ok := position_context.field_value.field.derived.(^ast.Ident); ok { + if field, ok := position_context.field_value.field.derived.(^ast.Ident); + ok { field_name = field.name } else { return - } + } } - if symbol, ok := resolve_type_expression(ast_context, position_context.parent_comp_lit.type); ok { - if comp_symbol, comp_lit, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok { + if symbol, ok := resolve_type_expression( + ast_context, + position_context.parent_comp_lit.type, + ); ok { + if comp_symbol, comp_lit, ok := resolve_type_comp_literal( + ast_context, + position_context, + symbol, + position_context.parent_comp_lit, + ); ok { if s, ok := comp_symbol.value.(SymbolStructValue); ok { - ast_context.current_package = comp_symbol.pkg; + ast_context.current_package = comp_symbol.pkg //We can either have the final elem_index := -1 @@ -600,21 +771,21 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc for name, i in s.names { if name != field_name { continue - } + } type = s.types[i] break } - if type == nil && len(s.types) > elem_index { + if type == nil && len(s.types) > elem_index { type = s.types[elem_index] } if enum_value, ok := unwrap_enum(ast_context, type); ok { for enum_name in enum_value.names { item := CompletionItem { - label = enum_name, - kind = .EnumMember, + label = enum_name, + kind = .EnumMember, detail = enum_name, } @@ -623,27 +794,34 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc list.items = items[:] return - } else if bitset_symbol, ok := resolve_type_expression(ast_context, type); ok { - if value, ok := unwrap_bitset(ast_context, bitset_symbol); ok { + } else if bitset_symbol, ok := resolve_type_expression( + ast_context, + type, + ); ok { + if value, ok := unwrap_bitset( + ast_context, + bitset_symbol, + ); ok { for name in value.names { - + item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } - + append(&items, item) - } + } list.items = items[:] return } } - } else if s, ok := unwrap_bitset(ast_context, comp_symbol); ok { + } else if s, ok := unwrap_bitset(ast_context, comp_symbol); + ok { for enum_name in s.names { item := CompletionItem { - label = enum_name, - kind = .EnumMember, + label = enum_name, + kind = .EnumMember, detail = enum_name, } @@ -655,16 +833,24 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } } - } - - if position_context.binary != nil && (position_context.binary.op.text == "==" || position_context.binary.op.text == "!=") { + } + + if position_context.binary != nil && + (position_context.binary.op.text == "==" || + position_context.binary.op.text == "!=") { context_node: ^ast.Expr enum_node: ^ast.Expr - if position_in_node(position_context.binary.right, position_context.position) { + if position_in_node( + position_context.binary.right, + position_context.position, + ) { context_node = position_context.binary.right enum_node = position_context.binary.left - } else if position_in_node(position_context.binary.left, position_context.position) { + } else if position_in_node( + position_context.binary.left, + position_context.position, + ) { context_node = position_context.binary.left enum_node = position_context.binary.right } @@ -673,8 +859,8 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc if enum_value, ok := unwrap_enum(ast_context, enum_node); ok { for name in enum_value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -687,7 +873,9 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } - if position_context.assign != nil && position_context.assign.rhs != nil && position_context.assign.lhs != nil { + if position_context.assign != nil && + position_context.assign.rhs != nil && + position_context.assign.lhs != nil { rhs_index: int for elem in position_context.assign.rhs { @@ -695,8 +883,10 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc break } else { //procedures are the only types that can return more than one value - if symbol, ok := resolve_type_expression(ast_context, elem); ok { - if procedure, ok := symbol.value.(SymbolProcedureValue); ok { + if symbol, ok := resolve_type_expression(ast_context, elem); + ok { + if procedure, ok := symbol.value.(SymbolProcedureValue); + ok { if procedure.return_types == nil { return } @@ -710,7 +900,10 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } if len(position_context.assign.lhs) > rhs_index { - if enum_value, ok := unwrap_enum(ast_context, position_context.assign.lhs[rhs_index]); ok { + if enum_value, ok := unwrap_enum( + ast_context, + position_context.assign.lhs[rhs_index], + ); ok { for name in enum_value.names { item := CompletionItem { label = name, @@ -750,11 +943,16 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } if len(position_context.function.type.results.list) > return_index { - if enum_value, ok := unwrap_enum(ast_context, position_context.function.type.results.list[return_index].type); ok { + if enum_value, ok := unwrap_enum( + ast_context, + position_context.function.type.results.list[ + return_index \ + ].type, + ); ok { for name in enum_value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -769,18 +967,25 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc if position_context.call != nil { if call, ok := position_context.call.derived.(^ast.Call_Expr); ok { - parameter_index, parameter_ok := find_position_in_call_param(ast_context, call^) - if symbol, ok := resolve_type_expression(ast_context, call.expr); ok && parameter_ok { + parameter_index, parameter_ok := find_position_in_call_param( + ast_context, + call^, + ) + if symbol, ok := resolve_type_expression(ast_context, call.expr); + ok && parameter_ok { if proc_value, ok := symbol.value.(SymbolProcedureValue); ok { if len(proc_value.arg_types) <= parameter_index { return } - if enum_value, ok := unwrap_enum(ast_context, proc_value.arg_types[parameter_index].type); ok { + if enum_value, ok := unwrap_enum( + ast_context, + proc_value.arg_types[parameter_index].type, + ); ok { for name in enum_value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -796,10 +1001,14 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } -get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_identifier_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { CombinedResult :: struct { score: f32, - snippet: Snippet_Info, + snippet: Snippet_Info, name: string, type: SymbolType, doc: string, @@ -832,7 +1041,7 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D append(&pkgs, ast_context.document_package) append(&pkgs, "$builtin") - + if results, ok := fuzzy_search(lookup_name, pkgs[:]); ok { for r in results { r := r @@ -841,15 +1050,18 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D uri, _ := common.parse_uri(r.symbol.uri, context.temp_allocator) if uri.path != ast_context.fullpath { - append(&combined, CombinedResult { - score = r.score, - type = r.symbol.type, - name = r.symbol.name, - doc = r.symbol.doc, - flags = r.symbol.flags, - signature = r.symbol.signature, - pkg = r.symbol.pkg, - }) + append( + &combined, + CombinedResult{ + score = r.score, + type = r.symbol.type, + name = r.symbol.name, + doc = r.symbol.doc, + flags = r.symbol.flags, + signature = r.symbol.signature, + pkg = r.symbol.pkg, + }, + ) } } } @@ -872,24 +1084,32 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D ast_context.use_globals = true ast_context.current_package = ast_context.document_package - ident := new_type(ast.Ident, v.expr.pos, v.expr.end, context.temp_allocator) + ident := new_type( + ast.Ident, + v.expr.pos, + v.expr.end, + context.temp_allocator, + ) ident.name = k - if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { + if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { symbol.signature = get_signature(ast_context, ident^, symbol) build_procedure_symbol_signature(&symbol) if score, ok := common.fuzzy_match(matcher, ident.name); ok == 1 { - append(&combined, CombinedResult { - score = score * 1.1, - type = symbol.type, - name = ident.name, - doc = symbol.doc, - flags = symbol.flags, - pkg = symbol.pkg, - signature = symbol.signature, - }) + append( + &combined, + CombinedResult{ + score = score * 1.1, + type = symbol.type, + name = ident.name, + doc = symbol.doc, + flags = symbol.flags, + pkg = symbol.pkg, + signature = symbol.signature, + }, + ) } } } @@ -900,30 +1120,43 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D break } - local_offset := get_local_offset(ast_context, position_context.position, k) + local_offset := get_local_offset( + ast_context, + position_context.position, + k, + ) ast_context.use_locals = true ast_context.use_globals = true ast_context.current_package = ast_context.document_package - ident := new_type(ast.Ident, {offset = local_offset}, {offset = local_offset}, context.temp_allocator) + ident := new_type( + ast.Ident, + {offset = local_offset}, + {offset = local_offset}, + context.temp_allocator, + ) ident.name = k - if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { + if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { symbol.signature = get_signature(ast_context, ident^, symbol) build_procedure_symbol_signature(&symbol) - if score, ok := common.fuzzy_match(matcher, ident.name); ok == 1 { - append(&combined, CombinedResult { - score = score * 1.7, - type = symbol.type, - name = ident.name, - doc = symbol.doc, - flags = symbol.flags, - pkg = symbol.pkg, - signature = symbol.signature, - }) + if score, ok := common.fuzzy_match(matcher, ident.name); + ok == 1 { + append( + &combined, + CombinedResult{ + score = score * 1.7, + type = symbol.type, + name = ident.name, + doc = symbol.doc, + flags = symbol.flags, + pkg = symbol.pkg, + signature = symbol.signature, + }, + ) } } } @@ -940,15 +1173,18 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D } if score, ok := common.fuzzy_match(matcher, symbol.name); ok == 1 { - append(&combined, CombinedResult { - score = score * 1.1, - type = symbol.type, - name = symbol.name, - doc = symbol.doc, - flags = symbol.flags, - signature = symbol.signature, - pkg = symbol.pkg, - }) + append( + &combined, + CombinedResult{ + score = score * 1.1, + type = symbol.type, + name = symbol.name, + doc = symbol.doc, + flags = symbol.flags, + signature = symbol.signature, + pkg = symbol.pkg, + }, + ) } } @@ -959,18 +1195,21 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D } if score, ok := common.fuzzy_match(matcher, keyword); ok == 1 { - append(&combined, CombinedResult { - score = score, - type = symbol.type, - name = symbol.name, - doc = symbol.doc, - flags = symbol.flags, - signature = symbol.signature, - pkg = symbol.pkg, - }) + append( + &combined, + CombinedResult{ + score = score, + type = symbol.type, + name = symbol.name, + doc = symbol.doc, + flags = symbol.flags, + signature = symbol.signature, + pkg = symbol.pkg, + }, + ) } } - + for keyword, _ in language_keywords { symbol := Symbol { name = keyword, @@ -978,22 +1217,28 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D } if score, ok := common.fuzzy_match(matcher, keyword); ok == 1 { - append(&combined, CombinedResult { - score = score * 1.1, - type = symbol.type, - name = symbol.name, - doc = symbol.doc, - flags = symbol.flags, - signature = symbol.signature, - pkg = symbol.pkg, - }) + append( + &combined, + CombinedResult{ + score = score * 1.1, + type = symbol.type, + name = symbol.name, + doc = symbol.doc, + flags = symbol.flags, + signature = symbol.signature, + pkg = symbol.pkg, + }, + ) } } if common.config.enable_snippets { for k, v in snippets { if score, ok := common.fuzzy_match(matcher, k); ok == 1 { - append(&combined, CombinedResult {score = score * 1.1, snippet = v, name = k}) + append( + &combined, + CombinedResult{score = score * 1.1, snippet = v, name = k}, + ) } } } @@ -1009,23 +1254,28 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D result := result //Skip procedures when the position is in proc decl - if position_in_proc_decl(position_context) && result.type == .Function && common.config.enable_procedure_context { + if position_in_proc_decl(position_context) && + result.type == .Function && + common.config.enable_procedure_context { continue } if result.snippet.insert != "" { item := CompletionItem { - label = result.name, - insertText = result.snippet.insert, - kind = .Snippet, - detail = result.snippet.detail, + label = result.name, + insertText = result.snippet.insert, + kind = .Snippet, + detail = result.snippet.detail, insertTextFormat = .Snippet, } edits := make([dynamic]TextEdit, context.temp_allocator) for pkg in result.snippet.packages { - edit, ok := get_core_insert_package_if_non_existent(ast_context, pkg) + edit, ok := get_core_insert_package_if_non_existent( + ast_context, + pkg, + ) if ok { append(&edits, edit) } @@ -1036,7 +1286,7 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D append(&items, item) } else { item := CompletionItem { - label = result.name, + label = result.name, documentation = result.doc, } @@ -1045,11 +1295,18 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D if result.type == .Function && common.config.enable_snippets { item.insertText = fmt.tprintf("%v($0)", item.label) item.insertTextFormat = .Snippet - item.deprecated = .Deprecated in result.flags + item.deprecated = .Deprecated in result.flags item.command.command = "editor.action.triggerParameterHints" } - - item.detail = concatenate_symbol_information(ast_context, result.pkg, result.name, result.signature, result.type, true) + + item.detail = concatenate_symbol_information( + ast_context, + result.pkg, + result.name, + result.signature, + result.type, + true, + ) append(&items, item) } @@ -1058,7 +1315,11 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D list.items = items[:] } -get_package_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_package_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { items := make([dynamic]CompletionItem, context.temp_allocator) list.isIncomplete = false @@ -1069,30 +1330,47 @@ get_package_completion :: proc(ast_context: ^AstContext, position_context: ^Docu return } - without_quotes := position_context.import_stmt.fullpath[1:fullpath_length-1] + without_quotes := position_context.import_stmt.fullpath[1:fullpath_length - + 1] absolute_path := without_quotes colon_index := strings.index(without_quotes, ":") if colon_index >= 0 { c := without_quotes[0:colon_index] - if colon_index+1 < len(without_quotes) { - absolute_path = filepath.join(elems = {common.config.collections[c], filepath.dir(without_quotes[colon_index+1:], context.temp_allocator)}, allocator = context.temp_allocator) + if colon_index + 1 < len(without_quotes) { + absolute_path = filepath.join( + elems = { + common.config.collections[c], + filepath.dir( + without_quotes[colon_index + 1:], + context.temp_allocator, + ), + }, + allocator = context.temp_allocator, + ) } else { absolute_path = common.config.collections[c] } } else { - import_file_dir := filepath.dir(position_context.import_stmt.pos.file, context.temp_allocator) + import_file_dir := filepath.dir( + position_context.import_stmt.pos.file, + context.temp_allocator, + ) import_dir := filepath.dir(without_quotes, context.temp_allocator) - absolute_path = filepath.join(elems = {import_file_dir, import_dir}, allocator = context.temp_allocator) + absolute_path = filepath.join( + elems = {import_file_dir, import_dir}, + allocator = context.temp_allocator, + ) } - if !strings.contains(position_context.import_stmt.fullpath, "/") && !strings.contains(position_context.import_stmt.fullpath, ":") { + if !strings.contains(position_context.import_stmt.fullpath, "/") && + !strings.contains(position_context.import_stmt.fullpath, ":") { for key, _ in common.config.collections { item := CompletionItem { detail = "collection", - label = key, - kind = .Module, + label = key, + kind = .Module, } append(&items, item) @@ -1102,8 +1380,8 @@ get_package_completion :: proc(ast_context: ^AstContext, position_context: ^Docu for pkg in search_for_packages(absolute_path) { item := CompletionItem { detail = pkg, - label = filepath.base(pkg), - kind = .Folder, + label = filepath.base(pkg), + kind = .Folder, } if item.label[0] == '.' { @@ -1116,7 +1394,7 @@ get_package_completion :: proc(ast_context: ^AstContext, position_context: ^Docu list.items = items[:] } -search_for_packages :: proc(fullpath: string) -> [] string { +search_for_packages :: proc(fullpath: string) -> []string { packages := make([dynamic]string, context.temp_allocator) fh, err := os.open(fullpath) @@ -1137,13 +1415,18 @@ search_for_packages :: proc(fullpath: string) -> [] string { return packages[:] } -get_type_switch_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_type_switch_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { items := make([dynamic]CompletionItem, context.temp_allocator) list.isIncomplete = false used_unions := make(map[string]bool, 5, context.temp_allocator) - if block, ok := position_context.switch_type_stmt.body.derived.(^ast.Block_Stmt); ok { + if block, ok := position_context.switch_type_stmt.body.derived.(^ast.Block_Stmt); + ok { for stmt in block.stmts { if case_clause, ok := stmt.derived.(^ast.Case_Clause); ok { for name in case_clause.list { @@ -1155,26 +1438,51 @@ get_type_switch_completion :: proc(ast_context: ^AstContext, position_context: ^ } } - ast_context.use_locals = true + ast_context.use_locals = true ast_context.use_globals = true - if assign, ok := position_context.switch_type_stmt.tag.derived.(^ast.Assign_Stmt); ok && assign.rhs != nil && len(assign.rhs) == 1 { + if assign, ok := position_context.switch_type_stmt.tag.derived.(^ast.Assign_Stmt); + ok && assign.rhs != nil && len(assign.rhs) == 1 { if union_value, ok := unwrap_union(ast_context, assign.rhs[0]); ok { for type, i in union_value.types { - if symbol, ok := resolve_type_expression(ast_context, union_value.types[i]); ok { + if symbol, ok := resolve_type_expression( + ast_context, + union_value.types[i], + ); ok { name := symbol.name if name in used_unions { continue } - + item := CompletionItem { kind = .EnumMember, } - + 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", + common.repeat( + "^", + symbol.pointers, + context.temp_allocator, + ), + name, + ) } else { - item.label = fmt.aprintf("%v%v.%v", common.repeat("^", symbol.pointers, context.temp_allocator), path.base(symbol.pkg, false, context.temp_allocator), name) + item.label = fmt.aprintf( + "%v%v.%v", + common.repeat( + "^", + symbol.pointers, + context.temp_allocator, + ), + path.base( + symbol.pkg, + false, + context.temp_allocator, + ), + name, + ) } append(&items, item) @@ -1186,7 +1494,13 @@ get_type_switch_completion :: proc(ast_context: ^AstContext, position_context: ^ list.items = items[:] } -get_core_insert_package_if_non_existent :: proc(ast_context: ^AstContext, pkg: string) -> (TextEdit, bool) { +get_core_insert_package_if_non_existent :: proc( + ast_context: ^AstContext, + pkg: string, +) -> ( + TextEdit, + bool, +) { builder := strings.builder_make(context.temp_allocator) for imp in ast_context.imports { @@ -1212,9 +1526,17 @@ get_core_insert_package_if_non_existent :: proc(ast_context: ^AstContext, pkg: s }, true } -get_range_from_selection_start_to_dot :: proc(position_context: ^DocumentPositionContext) -> (common.Range, bool) { +get_range_from_selection_start_to_dot :: proc( + position_context: ^DocumentPositionContext, +) -> ( + common.Range, + bool, +) { if position_context.selector != nil { - range := common.get_token_range(position_context.selector, position_context.file.src) + range := common.get_token_range( + position_context.selector, + position_context.file.src, + ) range.end.character += 1 return range, true } @@ -1222,20 +1544,24 @@ get_range_from_selection_start_to_dot :: proc(position_context: ^DocumentPositio return {}, false } -append_magic_map_completion :: proc(position_context: ^DocumentPositionContext, symbol: Symbol, items: ^[dynamic]CompletionItem) { +append_magic_map_completion :: proc( + position_context: ^DocumentPositionContext, + symbol: Symbol, + items: ^[dynamic]CompletionItem, +) { range, ok := get_range_from_selection_start_to_dot(position_context) if !ok { - return + return } remove_range := common.Range { start = range.start, - end = range.end, + end = range.end, } remove_edit := TextEdit { - range = remove_range, + range = remove_range, newText = "", } @@ -1249,37 +1575,41 @@ append_magic_map_completion :: proc(position_context: ^DocumentPositionContext, kind = .Snippet, detail = "for", additionalTextEdits = additionalTextEdits, - textEdit = TextEdit { - newText = fmt.tprintf("for ${{1:k}}, ${{2:v}} in %v {{\n\t$0 \n}}", symbol.name), - range = { - start = range.end, - end = range.end, - }, + textEdit = TextEdit{ + newText = fmt.tprintf( + "for ${{1:k}}, ${{2:v}} in %v {{\n\t$0 \n}}", + symbol.name, + ), + range = {start = range.end, end = range.end}, }, insertTextFormat = .Snippet, InsertTextMode = .adjustIndentation, } - + append(items, item) } } -append_magic_dynamic_array_completion :: proc(position_context: ^DocumentPositionContext, symbol: Symbol, items: ^[dynamic]CompletionItem) { +append_magic_dynamic_array_completion :: proc( + position_context: ^DocumentPositionContext, + symbol: Symbol, + items: ^[dynamic]CompletionItem, +) { range, ok := get_range_from_selection_start_to_dot(position_context) if !ok { - return + return } remove_range := common.Range { start = range.start, - end = range.end, + end = range.end, } remove_edit := TextEdit { - range = remove_range, + range = remove_range, newText = "", } @@ -1294,12 +1624,9 @@ append_magic_dynamic_array_completion :: proc(position_context: ^DocumentPositio label = "len", kind = .Function, detail = "len", - textEdit = TextEdit { + textEdit = TextEdit{ newText = text, - range = { - start = range.end, - end = range.end, - }, + range = {start = range.end, end = range.end}, }, additionalTextEdits = additionalTextEdits, } @@ -1314,42 +1641,46 @@ append_magic_dynamic_array_completion :: proc(position_context: ^DocumentPositio kind = .Snippet, detail = "for", additionalTextEdits = additionalTextEdits, - textEdit = TextEdit { - newText = fmt.tprintf("for i in %v {{\n\t$0 \n}}", symbol.name), - range = { - start = range.end, - end = range.end, - }, + textEdit = TextEdit{ + newText = fmt.tprintf( + "for i in %v {{\n\t$0 \n}}", + symbol.name, + ), + range = {start = range.end, end = range.end}, }, insertTextFormat = .Snippet, InsertTextMode = .adjustIndentation, } - + append(items, item) } - + } -append_magic_union_completion :: proc(position_context: ^DocumentPositionContext, symbol: Symbol, items: ^[dynamic]CompletionItem) { +append_magic_union_completion :: proc( + position_context: ^DocumentPositionContext, + symbol: Symbol, + items: ^[dynamic]CompletionItem, +) { range, ok := get_range_from_selection_start_to_dot(position_context) if !ok { - return + return } remove_range := common.Range { start = range.start, - end = range.end, + end = range.end, } remove_edit := TextEdit { - range = remove_range, + range = remove_range, newText = "", } additionalTextEdits := make([]TextEdit, 1, context.temp_allocator) additionalTextEdits[0] = remove_edit - + //switch { item := CompletionItem { @@ -1357,28 +1688,28 @@ append_magic_union_completion :: proc(position_context: ^DocumentPositionContext kind = .Snippet, detail = "switch", additionalTextEdits = additionalTextEdits, - textEdit = TextEdit { - newText = fmt.tprintf("switch v in %v {{\n\t$0 \n}}", symbol.name), - range = { - start = range.end, - end = range.end, - }, + textEdit = TextEdit{ + newText = fmt.tprintf( + "switch v in %v {{\n\t$0 \n}}", + symbol.name, + ), + range = {start = range.end, end = range.end}, }, insertTextFormat = .Snippet, InsertTextMode = .adjustIndentation, } - + append(items, item) } } bitset_operators: map[string]bool = { - "|" = true, - "&" = true, - "~" = true, - "<" = true, - ">" = true, + "|" = true, + "&" = true, + "~" = true, + "<" = true, + ">" = true, "==" = true, } @@ -1388,7 +1719,7 @@ bitset_assignment_operators: map[string]bool = { "~=" = true, "<=" = true, ">=" = true, - "=" = true, + "=" = true, "+=" = true, } @@ -1445,9 +1776,9 @@ language_keywords: []string = { } swizzle_color_components: map[u8]bool = { - 'r' = true, - 'g' = true, - 'b' = true, + 'r' = true, + 'g' = true, + 'b' = true, 'a' = true, } @@ -1456,4 +1787,4 @@ swizzle_coord_components: map[u8]bool = { 'y' = true, 'z' = true, 'w' = true, -}; +} diff --git a/src/server/definition.odin b/src/server/definition.odin index ad9e7a8..309cde1 100644 --- a/src/server/definition.odin +++ b/src/server/definition.odin @@ -16,16 +16,32 @@ import "core:os" import "shared:common" -get_definition_location :: proc(document: ^Document, position: common.Position) -> ([]common.Location, bool) { +get_definition_location :: proc( + document: ^Document, + position: common.Position, +) -> ( + []common.Location, + bool, +) { locations := make([dynamic]common.Location, context.temp_allocator) location: common.Location - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) uri: string - position_context, ok := get_document_position_context(document, position, .Definition) + position_context, ok := get_document_position_context( + document, + position, + .Definition, + ) if !ok { log.warn("Failed to get position context") @@ -35,16 +51,25 @@ get_definition_location :: proc(document: ^Document, position: common.Position) get_globals(document.ast, &ast_context) if position_context.function != nil { - get_locals(document.ast, position_context.function, &ast_context, &position_context) + get_locals( + document.ast, + position_context.function, + &ast_context, + &position_context, + ) } if position_context.selector_expr != nil { //if the base selector is the client wants to go to. - if base, ok := position_context.selector.derived.(^ast.Ident); ok && position_context.identifier != nil { + if base, ok := position_context.selector.derived.(^ast.Ident); + ok && position_context.identifier != nil { ident := position_context.identifier.derived.(^ast.Ident) if position_in_node(base, position_context.position) { - if resolved, ok := resolve_location_identifier(&ast_context, ident^); ok { + if resolved, ok := resolve_location_identifier( + &ast_context, + ident^, + ); ok { location.range = resolved.range if resolved.uri == "" { @@ -62,12 +87,18 @@ get_definition_location :: proc(document: ^Document, position: common.Position) } } - if resolved, ok := resolve_location_selector(&ast_context, position_context.selector_expr); ok { + if resolved, ok := resolve_location_selector( + &ast_context, + position_context.selector_expr, + ); ok { location.range = resolved.range uri = resolved.uri } } else if position_context.identifier != nil { - if resolved, ok := resolve_location_identifier(&ast_context, position_context.identifier.derived.(^ast.Ident)^); ok { + if resolved, ok := resolve_location_identifier( + &ast_context, + position_context.identifier.derived.(^ast.Ident)^, + ); ok { location.range = resolved.range uri = resolved.uri } else { @@ -87,4 +118,4 @@ get_definition_location :: proc(document: ^Document, position: common.Position) append(&locations, location) return locations[:], true -}
\ No newline at end of file +} diff --git a/src/server/document_links.odin b/src/server/document_links.odin index 0049509..17113ff 100644 --- a/src/server/document_links.odin +++ b/src/server/document_links.odin @@ -25,7 +25,11 @@ get_document_links :: proc(document: ^Document) -> ([]DocumentLink, bool) { continue } - e := strings.split(imp.relpath.text[1:len(imp.relpath.text)-1], ":", context.temp_allocator) + e := strings.split( + imp.relpath.text[1:len(imp.relpath.text) - 1], + ":", + context.temp_allocator, + ) if len(e) != 2 { continue @@ -43,7 +47,7 @@ get_document_links :: proc(document: ^Document) -> ([]DocumentLink, bool) { line = imp.relpath.pos.line, }, end = { - offset = imp.relpath.pos.offset + len(imp.relpath.text) - 1, + offset = imp.relpath.pos.offset + len(imp.relpath.text) - 1, column = imp.relpath.pos.column + len(imp.relpath.text) - 1, line = imp.relpath.pos.line, }, @@ -52,8 +56,12 @@ get_document_links :: proc(document: ^Document) -> ([]DocumentLink, bool) { range := common.get_token_range(node, string(document.text)) link := DocumentLink { - range = range, - target = fmt.tprintf("https://pkg.odin-lang.org/%v/%v", e[0], e[1]), + range = range, + target = fmt.tprintf( + "https://pkg.odin-lang.org/%v/%v", + e[0], + e[1], + ), tooltip = "Documentation", } diff --git a/src/server/document_symbols.odin b/src/server/document_symbols.odin index 274c37f..bed5734 100644 --- a/src/server/document_symbols.odin +++ b/src/server/document_symbols.odin @@ -18,7 +18,13 @@ import "core:os" import "shared:common" get_document_symbols :: proc(document: ^Document) -> []DocumentSymbol { - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) get_globals(document.ast, &ast_context) @@ -31,11 +37,13 @@ get_document_symbols :: proc(document: ^Document) -> []DocumentSymbol { } package_symbol.kind = .Package - package_symbol.name = path.base(document.package_name, false, context.temp_allocator) + package_symbol.name = path.base( + document.package_name, + false, + context.temp_allocator, + ) package_symbol.range = { - start = { - line = document.ast.decls[0].pos.line, - }, + start = {line = document.ast.decls[0].pos.line}, end = { line = document.ast.decls[len(document.ast.decls) - 1].end.line, }, @@ -47,7 +55,10 @@ get_document_symbols :: proc(document: ^Document) -> []DocumentSymbol { for k, global in ast_context.globals { symbol: DocumentSymbol - symbol.range = common.get_token_range(global.expr, ast_context.file.src) + symbol.range = common.get_token_range( + global.expr, + ast_context.file.src, + ) symbol.selectionRange = symbol.range symbol.name = k diff --git a/src/server/documents.odin b/src/server/documents.odin index 52309ed..5adfdfb 100644 --- a/src/server/documents.odin +++ b/src/server/documents.odin @@ -72,7 +72,7 @@ document_get_allocator :: proc() -> ^common.Scratch_Allocator { return pop(&document_storage.free_allocators) } else { allocator := new(common.Scratch_Allocator) - common.scratch_allocator_init(allocator, mem.Megabyte*3) + common.scratch_allocator_init(allocator, mem.Megabyte * 3) return allocator } } @@ -111,7 +111,12 @@ document_release :: proc(document: ^Document) { Client opens a document with transferred text */ -document_open :: proc(uri_string: string, text: string, config: ^common.Config, writer: ^Writer) -> common.Error { +document_open :: proc( + uri_string: string, + text: string, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { uri, parsed_ok := common.parse_uri(uri_string, context.allocator) if !parsed_ok { @@ -121,7 +126,10 @@ document_open :: proc(uri_string: string, text: string, config: ^common.Config, if document := &document_storage.documents[uri.path]; document != nil { if document.client_owned { - log.errorf("Client called open on an already open document: %v ", document.uri.path) + log.errorf( + "Client called open on an already open document: %v ", + document.uri.path, + ) return .InvalidRequest } @@ -138,11 +146,11 @@ document_open :: proc(uri_string: string, text: string, config: ^common.Config, } } else { document := Document { - uri = uri, - text = transmute([]u8)text, + uri = uri, + text = transmute([]u8)text, client_owned = true, - used_text = len(text), - allocator = document_get_allocator(), + used_text = len(text), + allocator = document_get_allocator(), } document_setup(&document) @@ -160,37 +168,46 @@ document_open :: proc(uri_string: string, text: string, config: ^common.Config, } document_setup :: proc(document: ^Document) { - //Right now not all clients return the case correct windows path, and that causes issues with indexing, so we ensure that it's case correct. - when ODIN_OS == .Windows { - package_name := path.dir(document.uri.path, context.temp_allocator) - forward, _ := filepath.to_slash(common.get_case_sensitive_path(package_name), context.temp_allocator) - if forward == "" { - document.package_name = package_name - } else { - document.package_name = strings.clone(forward) - } + //Right now not all clients return the case correct windows path, and that causes issues with indexing, so we ensure that it's case correct. + when ODIN_OS == .Windows { + package_name := path.dir(document.uri.path, context.temp_allocator) + forward, _ := filepath.to_slash( + common.get_case_sensitive_path(package_name), + context.temp_allocator, + ) + if forward == "" { + document.package_name = package_name } else { - document.package_name = path.dir(document.uri.path) + document.package_name = strings.clone(forward) } + } else { + document.package_name = path.dir(document.uri.path) + } - when ODIN_OS == .Windows { - correct := common.get_case_sensitive_path(document.uri.path) - fullpath: string - if correct == "" { - //This is basically here to handle the tests where the physical file doesn't actual exist. - document.fullpath, _ = filepath.to_slash(document.uri.path) - } else { - document.fullpath, _ = filepath.to_slash(correct) - } + when ODIN_OS == .Windows { + correct := common.get_case_sensitive_path(document.uri.path) + fullpath: string + if correct == "" { + //This is basically here to handle the tests where the physical file doesn't actual exist. + document.fullpath, _ = filepath.to_slash(document.uri.path) } else { - document.fullpath = document.uri.path + document.fullpath, _ = filepath.to_slash(correct) } + } else { + document.fullpath = document.uri.path + } } /* Function that applies changes to the given document through incremental syncronization */ -document_apply_changes :: proc(uri_string: string, changes: [dynamic]TextDocumentContentChangeEvent, version: Maybe(int), config: ^common.Config, writer: ^Writer) -> common.Error { +document_apply_changes :: proc( + uri_string: string, + changes: [dynamic]TextDocumentContentChangeEvent, + version: Maybe(int), + config: ^common.Config, + writer: ^Writer, +) -> common.Error { uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator) if !parsed_ok { @@ -202,14 +219,20 @@ document_apply_changes :: proc(uri_string: string, changes: [dynamic]TextDocumen document.version = version if !document.client_owned { - log.errorf("Client called change on an document not opened: %v ", document.uri.path) + log.errorf( + "Client called change on an document not opened: %v ", + document.uri.path, + ) return .InvalidRequest } for change in changes { //for some reason sublime doesn't seem to care even if i tell it to do incremental sync if range, ok := change.range.(common.Range); ok { - absolute_range, ok := common.get_absolute_range(range, document.text[:document.used_text]) + absolute_range, ok := common.get_absolute_range( + range, + document.text[:document.used_text], + ) if !ok { return .ParseError @@ -276,7 +299,10 @@ document_close :: proc(uri_string: string) -> common.Error { document := &document_storage.documents[uri.path] if document == nil || !document.client_owned { - log.errorf("Client called close on a document that was never opened: %v ", document.uri.path) + log.errorf( + "Client called close on a document that was never opened: %v ", + document.uri.path, + ) return .InvalidRequest } @@ -294,7 +320,11 @@ document_close :: proc(uri_string: string) -> common.Error { return .None } -document_refresh :: proc(document: ^Document, config: ^common.Config, writer: ^Writer) -> common.Error { +document_refresh :: proc( + document: ^Document, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { errors, ok := parse_document(document, config) if !ok { @@ -305,32 +335,33 @@ document_refresh :: proc(document: ^Document, config: ^common.Config, writer: ^W document.diagnosed_errors = true params := NotificationPublishDiagnosticsParams { - uri = document.uri.uri, - diagnostics = make([]Diagnostic, len(errors), context.temp_allocator), + uri = document.uri.uri, + diagnostics = make( + []Diagnostic, + len(errors), + context.temp_allocator, + ), } for error, i in errors { params.diagnostics[i] = Diagnostic { - range = common.Range { - start = common.Position { + range = common.Range{ + start = common.Position{ line = error.line - 1, character = 0, }, - end = common.Position { - line = error.line, - character = 0, - }, + end = common.Position{line = error.line, character = 0}, }, severity = DiagnosticSeverity.Error, code = "Syntax", message = error.message, } } - + notifaction := Notification { jsonrpc = "2.0", - method = "textDocument/publishDiagnostics", - params = params, + method = "textDocument/publishDiagnostics", + params = params, } send_notification(notifaction, writer) @@ -343,9 +374,13 @@ document_refresh :: proc(document: ^Document, config: ^common.Config, writer: ^W notifaction := Notification { jsonrpc = "2.0", method = "textDocument/publishDiagnostics", - params = NotificationPublishDiagnosticsParams { + params = NotificationPublishDiagnosticsParams{ uri = document.uri.uri, - diagnostics = make([]Diagnostic, len(errors), context.temp_allocator), + diagnostics = make( + []Diagnostic, + len(errors), + context.temp_allocator, + ), }, } @@ -362,13 +397,22 @@ current_errors: [dynamic]ParserError parser_error_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { error := ParserError { - line = pos.line,column = pos.column,file = pos.file, - offset = pos.offset,message = fmt.tprintf(msg, ..args), + line = pos.line, + column = pos.column, + file = pos.file, + offset = pos.offset, + message = fmt.tprintf(msg, ..args), } append(¤t_errors, error) } -parse_document :: proc(document: ^Document, config: ^common.Config) -> ([]ParserError, bool) { +parse_document :: proc( + document: ^Document, + config: ^common.Config, +) -> ( + []ParserError, + bool, +) { p := parser.Parser { err = parser_error_handler, warn = common.parser_warning_handler, @@ -391,8 +435,8 @@ parse_document :: proc(document: ^Document, config: ^common.Config) -> ([]Parser document.ast = ast.File { fullpath = document.fullpath, - src = string(document.text[:document.used_text]), - pkg = pkg, + src = string(document.text[:document.used_text]), + pkg = pkg, } parser.parse_file(&p, &document.ast) @@ -404,14 +448,15 @@ parse_document :: proc(document: ^Document, config: ^common.Config) -> ([]Parser parse_imports :: proc(document: ^Document, config: ^common.Config) { imports := make([dynamic]Package) - + for imp, index in document.ast.imports { if i := strings.index(imp.fullpath, "\""); i == -1 { continue } //collection specified - if i := strings.index(imp.fullpath, ":"); i != -1 && i > 1 && i < len(imp.fullpath) - 1 { + if i := strings.index(imp.fullpath, ":"); + i != -1 && i > 1 && i < len(imp.fullpath) - 1 { if len(imp.fullpath) < 2 { continue } @@ -426,14 +471,19 @@ parse_imports :: proc(document: ^Document, config: ^common.Config) { } import_: Package - import_.name = strings.clone(path.join(elems = {dir, p}, allocator = context.temp_allocator)) + import_.name = strings.clone( + path.join( + elems = {dir, p}, + allocator = context.temp_allocator, + ), + ) if imp.name.text != "" { import_.base = imp.name.text } else { import_.base = path.base(import_.name, false) } - + append(&imports, import_) } else { //relative @@ -442,7 +492,13 @@ parse_imports :: proc(document: ^Document, config: ^common.Config) { } import_: Package - import_.name = path.join(elems = {document.package_name, imp.fullpath[1:len(imp.fullpath) - 1]}, allocator = context.temp_allocator) + import_.name = path.join( + elems = { + document.package_name, + imp.fullpath[1:len(imp.fullpath) - 1], + }, + allocator = context.temp_allocator, + ) import_.name = path.clean(import_.name) if imp.name.text != "" { diff --git a/src/server/format.odin b/src/server/format.odin index 236bee2..cbb4082 100644 --- a/src/server/format.odin +++ b/src/server/format.odin @@ -20,7 +20,13 @@ DocumentFormattingParams :: struct { options: FormattingOptions, } -get_complete_format :: proc(document: ^Document, config: ^common.Config) -> ([]TextEdit, bool) { +get_complete_format :: proc( + document: ^Document, + config: ^common.Config, +) -> ( + []TextEdit, + bool, +) { if document.ast.syntax_error_count > 0 { return {}, true } @@ -29,7 +35,9 @@ get_complete_format :: proc(document: ^Document, config: ^common.Config) -> ([]T return {}, true } - style := format.find_config_file_or_default(filepath.dir(document.fullpath, context.temp_allocator)) + style := format.find_config_file_or_default( + filepath.dir(document.fullpath, context.temp_allocator), + ) prnt := printer.make_printer(style, context.temp_allocator) src := printer.print(&prnt, &document.ast) @@ -42,7 +50,9 @@ get_complete_format :: proc(document: ^Document, config: ^common.Config) -> ([]T last := document.text[0] line := 0 - for current_index := 0; current_index < len(document.text); current_index += 1 { + for current_index := 0; + current_index < len(document.text); + current_index += 1 { current := document.text[current_index] if last == '\r' && current == '\n' { @@ -58,14 +68,8 @@ get_complete_format :: proc(document: ^Document, config: ^common.Config) -> ([]T edit := TextEdit { newText = src, range = { - start = { - character = 0, - line = 0, - }, - end = { - character = 1, - line = line+1, - }, + start = {character = 0, line = 0}, + end = {character = 1, line = line + 1}, }, } diff --git a/src/server/hover.odin b/src/server/hover.odin index 0e00fa0..580038f 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -15,17 +15,24 @@ import "core:slice" import "shared:common" -write_hover_content :: proc(ast_context: ^AstContext, symbol: Symbol) -> MarkupContent { +write_hover_content :: proc( + ast_context: ^AstContext, + symbol: Symbol, +) -> MarkupContent { content: MarkupContent symbol := symbol if untyped, ok := symbol.value.(SymbolUntypedValue); ok { switch untyped.type { - case .String: symbol.signature = "string" - case .Bool: symbol.signature = "bool" - case .Float: symbol.signature = "float" - case .Integer: symbol.signature = "int" + case .String: + symbol.signature = "string" + case .Bool: + symbol.signature = "bool" + case .Float: + symbol.signature = "float" + case .Integer: + symbol.signature = "int" } } @@ -44,80 +51,133 @@ write_hover_content :: proc(ast_context: ^AstContext, symbol: Symbol) -> MarkupC } builtin_identifier_hover: map[string]string = { - "context" = fmt.aprintf("```odin\n%v\n```\n%v", "runtime.context: Context", "This context variable is local to each scope and is implicitly passed by pointer to any procedure call in that scope (if the procedure has the Odin calling convention)."), + "context" = fmt.aprintf( + "```odin\n%v\n```\n%v", + "runtime.context: Context", + "This context variable is local to each scope and is implicitly passed by pointer to any procedure call in that scope (if the procedure has the Odin calling convention).", + ), } -get_hover_information :: proc(document: ^Document, position: common.Position) -> (Hover, bool, bool) { +get_hover_information :: proc( + document: ^Document, + position: common.Position, +) -> ( + Hover, + bool, + bool, +) { hover := Hover { - contents = { - kind = "plaintext", - }, + contents = {kind = "plaintext"}, } - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) - position_context, ok := get_document_position_context(document, position, .Hover) + position_context, ok := get_document_position_context( + document, + position, + .Hover, + ) get_globals(document.ast, &ast_context) if position_context.function != nil { - get_locals(document.ast, position_context.function, &ast_context, &position_context) + get_locals( + document.ast, + position_context.function, + &ast_context, + &position_context, + ) } if position_context.identifier != nil { if ident, ok := position_context.identifier.derived.(^ast.Ident); ok { if _, ok := common.keyword_map[ident.name]; ok { hover.contents.kind = "plaintext" - hover.range = common.get_token_range(position_context.identifier^, ast_context.file.src) + hover.range = common.get_token_range( + position_context.identifier^, + ast_context.file.src, + ) return hover, true, true } if str, ok := builtin_identifier_hover[ident.name]; ok { hover.contents.kind = "markdown" hover.contents.value = str - hover.range = common.get_token_range(position_context.identifier^, ast_context.file.src) + hover.range = common.get_token_range( + position_context.identifier^, + ast_context.file.src, + ) return hover, true, true } - } + } } if position_context.implicit_context != nil { - if str, ok := builtin_identifier_hover[position_context.implicit_context.tok.text]; ok { + if str, ok := + builtin_identifier_hover[ + position_context.implicit_context.tok.text \ + ]; ok { hover.contents.kind = "markdown" hover.contents.value = str - hover.range = common.get_token_range(position_context.implicit_context^, ast_context.file.src) + hover.range = common.get_token_range( + position_context.implicit_context^, + ast_context.file.src, + ) return hover, true, true } } if position_context.selector != nil && position_context.identifier != nil { - hover.range = common.get_token_range(position_context.identifier^, ast_context.file.src) + hover.range = common.get_token_range( + position_context.identifier^, + ast_context.file.src, + ) ast_context.use_locals = true ast_context.use_globals = true ast_context.current_package = ast_context.document_package //if the base selector is the client wants to go to. - if base, ok := position_context.selector.derived.(^ast.Ident); ok && position_context.identifier != nil { + if base, ok := position_context.selector.derived.(^ast.Ident); + ok && position_context.identifier != nil { ident := position_context.identifier.derived.(^ast.Ident)^ if position_in_node(base, position_context.position) { - if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { - resolved.signature = get_signature(&ast_context, ident, resolved) + if resolved, ok := resolve_type_identifier( + &ast_context, + ident, + ); ok { + resolved.signature = get_signature( + &ast_context, + ident, + resolved, + ) resolved.name = ident.name if resolved.type == .Variable { resolved.pkg = ast_context.document_package } - hover.contents = write_hover_content(&ast_context, resolved) + hover.contents = write_hover_content( + &ast_context, + resolved, + ) return hover, true, true } } } selector: Symbol - selector, ok = resolve_type_expression(&ast_context, position_context.selector) + selector, ok = resolve_type_expression( + &ast_context, + position_context.selector, + ) if !ok { return hover, false, true @@ -138,20 +198,33 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> case SymbolStructValue: for name, i in v.names { if name == field { - if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok { + if symbol, ok := resolve_type_expression( + &ast_context, + v.types[i], + ); ok { symbol.name = name //TODO refractor - never set symbol name after creation - change writer_hover_content symbol.pkg = selector.name symbol.signature = common.node_to_string(v.types[i]) - hover.contents = write_hover_content(&ast_context, symbol) + hover.contents = write_hover_content( + &ast_context, + symbol, + ) return hover, true, true } } } case SymbolPackageValue: if position_context.field != nil { - if ident, ok := position_context.field.derived.(^ast.Ident); ok { - if symbol, ok := resolve_type_identifier(&ast_context, ident^); ok { - hover.contents = write_hover_content(&ast_context, symbol) + if ident, ok := position_context.field.derived.(^ast.Ident); + ok { + if symbol, ok := resolve_type_identifier( + &ast_context, + ident^, + ); ok { + hover.contents = write_hover_content( + &ast_context, + symbol, + ) return hover, true, true } } @@ -164,9 +237,12 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> ident := position_context.identifier.derived.(^ast.Ident)^ - hover.range = common.get_token_range(position_context.identifier^, document.ast.src) + hover.range = common.get_token_range( + position_context.identifier^, + document.ast.src, + ) - if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { + if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { resolved.signature = get_signature(&ast_context, ident, resolved) resolved.name = ident.name diff --git a/src/server/indexer.odin b/src/server/indexer.odin index 581bd37..7b7d071 100644 --- a/src/server/indexer.odin +++ b/src/server/indexer.odin @@ -9,7 +9,7 @@ import "core:slice" Indexer :: struct { builtin_packages: [dynamic]string, - index: MemoryIndex, + index: MemoryIndex, } indexer: Indexer @@ -19,7 +19,14 @@ FuzzyResult :: struct { score: f32, } -lookup :: proc(name: string, pkg: string, loc := #caller_location) -> (Symbol, bool) { +lookup :: proc( + name: string, + pkg: string, + loc := #caller_location, +) -> ( + Symbol, + bool, +) { if symbol, ok := memory_index_lookup(&indexer.index, name, pkg); ok { return symbol, true } diff --git a/src/server/inlay_hints.odin b/src/server/inlay_hints.odin index fb989db..59f3c86 100644 --- a/src/server/inlay_hints.odin +++ b/src/server/inlay_hints.odin @@ -1,14 +1,26 @@ -package server +package server import "core:odin/ast" import "core:fmt" import "shared:common" -get_inlay_hints :: proc(document: ^Document, symbols: map[uintptr]SymbolAndNode) -> ([]InlayHint, bool) { +get_inlay_hints :: proc( + document: ^Document, + symbols: map[uintptr]SymbolAndNode, +) -> ( + []InlayHint, + bool, +) { hints := make([dynamic]InlayHint, context.temp_allocator) - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) Visit_Data :: struct { calls: [dynamic]^ast.Node, @@ -33,7 +45,7 @@ get_inlay_hints :: proc(document: ^Document, symbols: map[uintptr]SymbolAndNode) } visitor := ast.Visitor { - data = &data, + data = &data, visit = visit, } @@ -53,7 +65,8 @@ get_inlay_hints :: proc(document: ^Document, symbols: map[uintptr]SymbolAndNode) } if symbol_and_node, ok := symbols[cast(uintptr)node_call]; ok { - if symbol_call, ok := symbol_and_node.symbol.value.(SymbolProcedureValue); ok { + if symbol_call, ok := symbol_and_node.symbol.value.(SymbolProcedureValue); + ok { for arg in symbol_call.arg_types { for name in arg.names { if symbol_arg_count >= len(call.args) { @@ -62,12 +75,15 @@ get_inlay_hints :: proc(document: ^Document, symbols: map[uintptr]SymbolAndNode) if ident, ok := name.derived.(^ast.Ident); ok { hint := InlayHint { - kind = "parameter", + kind = "parameter", label = fmt.tprintf("%v = ", ident.name), - range = common.get_token_range(call.args[symbol_arg_count], string(document.text)), + range = common.get_token_range( + call.args[symbol_arg_count], + string(document.text), + ), } append(&hints, hint) - } + } symbol_arg_count += 1 } } @@ -76,4 +92,4 @@ get_inlay_hints :: proc(document: ^Document, symbols: map[uintptr]SymbolAndNode) } return hints[:], true -}
\ No newline at end of file +} diff --git a/src/server/lens.odin b/src/server/lens.odin index 5525554..99eaea3 100644 --- a/src/server/lens.odin +++ b/src/server/lens.odin @@ -15,13 +15,25 @@ CodeLensOptions :: struct { } CodeLens :: struct { - range: common.Range, + range: common.Range, command: Command, - data: string, + data: string, } -get_code_lenses :: proc(document: ^Document, position: common.Position) -> ([]CodeLens, bool) { - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) +get_code_lenses :: proc( + document: ^Document, + position: common.Position, +) -> ( + []CodeLens, + bool, +) { + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) get_globals(document.ast, &ast_context) @@ -33,18 +45,16 @@ get_code_lenses :: proc(document: ^Document, position: common.Position) -> ([]Co for name, global in ast_context.globals { - + if proc_lit, ok := global.expr.derived.(^ast.Proc_Lit); ok { - } } - + return {}, false } - diff --git a/src/server/log.odin b/src/server/log.odin index c23270d..8660e88 100644 --- a/src/server/log.odin +++ b/src/server/log.odin @@ -6,29 +6,35 @@ import "core:os" import "core:time" import "core:log" -Default_Console_Logger_Opts :: log.Options { - .Level, - .Terminal_Color, - .Short_File_Path, - .Line, - .Procedure, -} | log.Full_Timestamp_Opts +Default_Console_Logger_Opts :: + log.Options{.Level, .Terminal_Color, .Short_File_Path, .Line, .Procedure} | + log.Full_Timestamp_Opts Lsp_Logger_Data :: struct { writer: ^Writer, } -create_lsp_logger :: proc(writer: ^Writer, lowest := log.Level.Debug, opt := Default_Console_Logger_Opts) -> log.Logger { +create_lsp_logger :: proc( + writer: ^Writer, + lowest := log.Level.Debug, + opt := Default_Console_Logger_Opts, +) -> log.Logger { data := new(Lsp_Logger_Data) data.writer = writer - return log.Logger {lsp_logger_proc, data, lowest, opt} + return log.Logger{lsp_logger_proc, data, lowest, opt} } destroy_lsp_logger :: proc(log: ^log.Logger) { free(log.data) } -lsp_logger_proc :: proc(logger_data: rawptr, level: log.Level, text: string, options: log.Options, location := #caller_location) { +lsp_logger_proc :: proc( + logger_data: rawptr, + level: log.Level, + text: string, + options: log.Options, + location := #caller_location, +) { data := cast(^Lsp_Logger_Data)logger_data @@ -36,16 +42,20 @@ lsp_logger_proc :: proc(logger_data: rawptr, level: log.Level, text: string, opt message_type: DiagnosticSeverity switch level { - case .Debug: message_type = DiagnosticSeverity.Hint - case .Info: message_type = DiagnosticSeverity.Information - case .Warning: message_type = DiagnosticSeverity.Warning - case .Error, .Fatal: message_type = DiagnosticSeverity.Error + case .Debug: + message_type = DiagnosticSeverity.Hint + case .Info: + message_type = DiagnosticSeverity.Information + case .Warning: + message_type = DiagnosticSeverity.Warning + case .Error, .Fatal: + message_type = DiagnosticSeverity.Error } - + notification := Notification { jsonrpc = "2.0", method = "window/logMessage", - params = NotificationLoggingParams { + params = NotificationLoggingParams{ type = message_type, message = message, }, diff --git a/src/server/memory_index.odin b/src/server/memory_index.odin index edb3dd6..3af9ea0 100644 --- a/src/server/memory_index.odin +++ b/src/server/memory_index.odin @@ -9,24 +9,29 @@ import "core:slice" import "shared:common" MemoryIndex :: struct { - collection: SymbolCollection, + collection: SymbolCollection, last_package_name: string, - last_package: ^map[string]Symbol, + last_package: ^map[string]Symbol, } make_memory_index :: proc(collection: SymbolCollection) -> MemoryIndex { - return MemoryIndex { - collection = collection, - } + return MemoryIndex{collection = collection} } -memory_index_lookup :: proc(index: ^MemoryIndex, name: string, pkg: string) -> (Symbol, bool) { +memory_index_lookup :: proc( + index: ^MemoryIndex, + name: string, + pkg: string, +) -> ( + Symbol, + bool, +) { if index.last_package_name == pkg && index.last_package != nil { return index.last_package[name] } if _pkg, ok := &index.collection.packages[pkg]; ok { - index.last_package = _pkg + index.last_package = _pkg index.last_package_name = pkg return _pkg[name] } else { @@ -37,7 +42,14 @@ memory_index_lookup :: proc(index: ^MemoryIndex, name: string, pkg: string) -> ( return {}, false } -memory_index_fuzzy_search :: proc(index: ^MemoryIndex, name: string, pkgs: []string) -> ([]FuzzyResult, bool) { +memory_index_fuzzy_search :: proc( + index: ^MemoryIndex, + name: string, + pkgs: []string, +) -> ( + []FuzzyResult, + bool, +) { symbols := make([dynamic]FuzzyResult, 0, context.temp_allocator) fuzzy_matcher := common.make_fuzzy_matcher(name) @@ -47,16 +59,17 @@ memory_index_fuzzy_search :: proc(index: ^MemoryIndex, name: string, pkgs: []str for pkg in pkgs { if pkg, ok := index.collection.packages[pkg]; ok { for _, symbol in pkg { - if score, ok := common.fuzzy_match(fuzzy_matcher, symbol.name); ok == 1 { + if score, ok := common.fuzzy_match(fuzzy_matcher, symbol.name); + ok == 1 { result := FuzzyResult { symbol = symbol, - score = score, + score = score, } - + append(&symbols, result) } } - } + } } slice.sort_by(symbols[:], proc(i, j: FuzzyResult) -> bool { @@ -69,4 +82,3 @@ memory_index_fuzzy_search :: proc(index: ^MemoryIndex, name: string, pkgs: []str return symbols[:min(top, len(symbols))], true } } - diff --git a/src/server/reader.odin b/src/server/reader.odin index e704ad8..1a32b6f 100644 --- a/src/server/reader.odin +++ b/src/server/reader.odin @@ -12,7 +12,7 @@ Reader :: struct { } make_reader :: proc(reader_fn: ReaderFn, reader_context: rawptr) -> Reader { - return Reader {reader_context = reader_context, reader_fn = reader_fn} + return Reader{reader_context = reader_context, reader_fn = reader_fn} } read_u8 :: proc(reader: ^Reader) -> (u8, bool) { @@ -27,7 +27,11 @@ read_u8 :: proc(reader: ^Reader) -> (u8, bool) { return value[0], true } -read_until_delimiter :: proc(reader: ^Reader, delimiter: u8, builder: ^strings.Builder) -> bool { +read_until_delimiter :: proc( + reader: ^Reader, + delimiter: u8, + builder: ^strings.Builder, +) -> bool { for true { value, success := read_u8(reader) diff --git a/src/server/references.odin b/src/server/references.odin index 11631b2..4b3a6d3 100644 --- a/src/server/references.odin +++ b/src/server/references.odin @@ -1,4 +1,4 @@ -package server +package server import "shared:common" @@ -16,7 +16,13 @@ import "core:runtime" fullpaths: [dynamic]string -walk_directories :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip_dir: bool) { +walk_directories :: proc( + info: os.File_Info, + in_err: os.Errno, +) -> ( + err: os.Errno, + skip_dir: bool, +) { if info.is_dir { return 0, false } @@ -32,7 +38,10 @@ walk_directories :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno return 0, false } -position_in_struct_names :: proc(position_context: ^DocumentPositionContext, type: ^ast.Struct_Type) -> bool { +position_in_struct_names :: proc( + position_context: ^DocumentPositionContext, + type: ^ast.Struct_Type, +) -> bool { for field in type.fields.list { for name in field.names { if position_in_node(name, position_context.position) { @@ -45,7 +54,13 @@ position_in_struct_names :: proc(position_context: ^DocumentPositionContext, typ } -resolve_references :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext) -> ([]common.Location, bool) { +resolve_references :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, +) -> ( + []common.Location, + bool, +) { locations := make([dynamic]common.Location, 0, ast_context.allocator) fullpaths = make([dynamic]string, 10, ast_context.allocator) @@ -56,14 +71,21 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document pkg := "" walker_arena: mem.Arena - mem.arena_init(&walker_arena, make([]byte, mem.Megabyte*5)) - + mem.arena_init(&walker_arena, make([]byte, mem.Megabyte * 5)) + { context.temp_allocator = mem.arena_allocator(&walker_arena) - filepath.walk(filepath.dir(os.args[0], context.allocator), walk_directories) + filepath.walk( + filepath.dir(os.args[0], context.allocator), + walk_directories, + ) } - if position_context.struct_type != nil && position_in_struct_names(position_context, position_context.struct_type) { + if position_context.struct_type != nil && + position_in_struct_names( + position_context, + position_context.struct_type, + ) { return {}, true } else if position_context.enum_type != nil { return {}, true @@ -88,19 +110,22 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document symbol, ok = resolve_location_identifier(ast_context, ident^) location := common.Location { - range = common.get_token_range(position_context.identifier^, string(ast_context.file.src)), - uri = strings.clone(symbol.uri, ast_context.allocator), + range = common.get_token_range( + position_context.identifier^, + string(ast_context.file.src), + ), + uri = strings.clone(symbol.uri, ast_context.allocator), } append(&locations, location) } - + if !ok { return {}, true } resolve_arena: mem.Arena - mem.arena_init(&resolve_arena, make([]byte, mem.Megabyte*25)) + mem.arena_init(&resolve_arena, make([]byte, mem.Megabyte * 25)) context.allocator = mem.arena_allocator(&resolve_arena) @@ -131,8 +156,8 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document file := ast.File { fullpath = fullpath, - src = string(data), - pkg = pkg, + src = string(data), + pkg = pkg, } ok = parser.parse_file(&p, &file) @@ -148,7 +173,7 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document ast = file, } - document.uri = uri + document.uri = uri document.text = transmute([]u8)file.src document.used_text = len(file.src) @@ -159,20 +184,33 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document in_pkg := false for pkg in document.imports { - if pkg.name == symbol.pkg || symbol.pkg == ast_context.document_package { + if pkg.name == symbol.pkg || + symbol.pkg == ast_context.document_package { in_pkg = true } } if in_pkg { - symbols_and_nodes := resolve_entire_file(&document, reference, resolve_flag, context.allocator) + symbols_and_nodes := resolve_entire_file( + &document, + reference, + resolve_flag, + context.allocator, + ) for k, v in symbols_and_nodes { - if v.symbol.uri == symbol.uri && v.symbol.range == symbol.range { + if v.symbol.uri == symbol.uri && + v.symbol.range == symbol.range { location := common.Location { - range = common.get_token_range(v.node^, string(document.text)), - uri = strings.clone(v.symbol.uri, ast_context.allocator), - } + range = common.get_token_range( + v.node^, + string(document.text), + ), + uri = strings.clone( + v.symbol.uri, + ast_context.allocator, + ), + } append(&locations, location) } } @@ -184,25 +222,47 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document return locations[:], true } -get_references :: proc(document: ^Document, position: common.Position) -> ([]common.Location, bool) { - data := make([]byte, mem.Megabyte*55, runtime.default_allocator()) +get_references :: proc( + document: ^Document, + position: common.Position, +) -> ( + []common.Location, + bool, +) { + data := make([]byte, mem.Megabyte * 55, runtime.default_allocator()) //defer delete(data) - + arena: mem.Arena mem.arena_init(&arena, data) - - context.allocator = mem.arena_allocator(&arena) - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath, context.allocator) + context.allocator = mem.arena_allocator(&arena) - position_context, ok := get_document_position_context(document, position, .Hover) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + context.allocator, + ) + + position_context, ok := get_document_position_context( + document, + position, + .Hover, + ) get_globals(document.ast, &ast_context) ast_context.current_package = ast_context.document_package if position_context.function != nil { - get_locals(document.ast, position_context.function, &ast_context, &position_context) + get_locals( + document.ast, + position_context.function, + &ast_context, + &position_context, + ) } locations, ok2 := resolve_references(&ast_context, &position_context) @@ -212,10 +272,10 @@ get_references :: proc(document: ^Document, position: common.Position) -> ([]com for location in locations { temp_location := common.Location { range = location.range, - uri = strings.clone(location.uri, context.temp_allocator), + uri = strings.clone(location.uri, context.temp_allocator), } append(&temp_locations, temp_location) } return temp_locations[:], ok2 -}
\ No newline at end of file +} diff --git a/src/server/rename.odin b/src/server/rename.odin index 45fad45..0ab27ab 100644 --- a/src/server/rename.odin +++ b/src/server/rename.odin @@ -1,11 +1,18 @@ -package server +package server import "shared:common" import "core:log" import "core:odin/ast" -get_rename :: proc(document: ^Document, new_text: string, position: common.Position) -> (WorkspaceEdit, bool) { +get_rename :: proc( + document: ^Document, + new_text: string, + position: common.Position, +) -> ( + WorkspaceEdit, + bool, +) { workspace: WorkspaceEdit document_changes := make([dynamic]TextDocumentEdit, context.temp_allocator) @@ -15,16 +22,13 @@ get_rename :: proc(document: ^Document, new_text: string, position: common.Posit document_change := TextDocumentEdit { edits = edits[:], - textDocument = { - uri = document.uri.uri, - version = document.version, - }, + textDocument = {uri = document.uri.uri, version = document.version}, } append(&document_changes, document_change) workspace.documentChanges = document_changes[:] - + return workspace, true -}
\ No newline at end of file +} diff --git a/src/server/requests.odin b/src/server/requests.odin index 29e78c1..55052e0 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -57,20 +57,18 @@ RequestInfo :: struct { } -make_response_message :: proc (id: RequestId, params: ResponseParams) -> ResponseMessage { - return ResponseMessage { - jsonrpc = "2.0", - id = id, - result = params, - } +make_response_message :: proc( + id: RequestId, + params: ResponseParams, +) -> ResponseMessage { + return ResponseMessage{jsonrpc = "2.0", id = id, result = params} } -make_response_message_error :: proc (id: RequestId, error: ResponseError) -> ResponseMessageError { - return ResponseMessageError { - jsonrpc = "2.0", - id = id, - error = error, - } +make_response_message_error :: proc( + id: RequestId, + error: ResponseError, +) -> ResponseMessageError { + return ResponseMessageError{jsonrpc = "2.0", id = id, error = error} } RequestThreadData :: struct { @@ -137,13 +135,13 @@ thread_request_main :: proc(data: rawptr) { method := root["method"].(json.String) if method == "$/cancelRequest" { - append(&deletings, Request { id = id }) + append(&deletings, Request{id = id}) json.destroy_value(root) } else if method in notification_map { - append(&requests, Request { value = root, is_notification = true}) + append(&requests, Request{value = root, is_notification = true}) sync.sema_post(&requests_sempahore) } else { - append(&requests, Request { id = id, value = root}) + append(&requests, Request{id = id, value = root}) sync.sema_post(&requests_sempahore) } @@ -153,11 +151,11 @@ thread_request_main :: proc(data: rawptr) { } } -read_and_parse_header :: proc (reader: ^Reader) -> (Header, bool) { +read_and_parse_header :: proc(reader: ^Reader) -> (Header, bool) { header: Header builder := strings.builder_make(context.temp_allocator) - + found_content_length := false for true { @@ -186,7 +184,7 @@ read_and_parse_header :: proc (reader: ^Reader) -> (Header, bool) { return header, false } - header_name := message[0:index] + header_name := message[0:index] header_value := message[len(header_name) + 2:len(message) - 2] if strings.compare(header_name, "Content-Length") == 0 { @@ -216,7 +214,13 @@ read_and_parse_header :: proc (reader: ^Reader) -> (Header, bool) { return header, found_content_length } -read_and_parse_body :: proc (reader: ^Reader, header: Header) -> (json.Value, bool) { +read_and_parse_body :: proc( + reader: ^Reader, + header: Header, +) -> ( + json.Value, + bool, +) { value: json.Value data := make([]u8, header.content_length, context.temp_allocator) @@ -228,7 +232,11 @@ read_and_parse_body :: proc (reader: ^Reader, header: Header) -> (json.Value, bo err: json.Error - value, err = json.parse(data = data, allocator = context.allocator, parse_integers = true) + value, err = json.parse( + data = data, + allocator = context.allocator, + parse_integers = true, + ) if (err != json.Error.None) { log.error("Failed to parse body") @@ -238,39 +246,43 @@ read_and_parse_body :: proc (reader: ^Reader, header: Header) -> (json.Value, bo return value, true } -call_map : map [string] proc(json.Value, RequestId, ^common.Config, ^Writer) -> common.Error = -{ - "initialize" = request_initialize, - "initialized" = request_initialized, - "shutdown" = request_shutdown, - "exit" = notification_exit, - "textDocument/didOpen" = notification_did_open, - "textDocument/didChange" = notification_did_change, - "textDocument/didClose" = notification_did_close, - "textDocument/didSave" = notification_did_save, - "textDocument/definition" = request_definition, - "textDocument/completion" = request_completion, - "textDocument/signatureHelp" = request_signature_help, - "textDocument/documentSymbol" = request_document_symbols, - "textDocument/semanticTokens/full" = request_semantic_token_full, +call_map: map[string]proc( + _: json.Value, + _: RequestId, + _: ^common.Config, + _: ^Writer, +) -> common.Error = { + "initialize" = request_initialize, + "initialized" = request_initialized, + "shutdown" = request_shutdown, + "exit" = notification_exit, + "textDocument/didOpen" = notification_did_open, + "textDocument/didChange" = notification_did_change, + "textDocument/didClose" = notification_did_close, + "textDocument/didSave" = notification_did_save, + "textDocument/definition" = request_definition, + "textDocument/completion" = request_completion, + "textDocument/signatureHelp" = request_signature_help, + "textDocument/documentSymbol" = request_document_symbols, + "textDocument/semanticTokens/full" = request_semantic_token_full, "textDocument/semanticTokens/range" = request_semantic_token_range, - "textDocument/hover" = request_hover, - "textDocument/formatting" = request_format_document, - "odin/inlayHints" = request_inlay_hint, - "textDocument/documentLink" = request_document_links, - "textDocument/rename" = request_rename, - "textDocument/references" = request_references, + "textDocument/hover" = request_hover, + "textDocument/formatting" = request_format_document, + "odin/inlayHints" = request_inlay_hint, + "textDocument/documentLink" = request_document_links, + "textDocument/rename" = request_rename, + "textDocument/references" = request_references, } -notification_map: map [string] bool = { - "textDocument/didOpen" = true, +notification_map: map[string]bool = { + "textDocument/didOpen" = true, "textDocument/didChange" = true, - "textDocument/didClose" = true, - "textDocument/didSave" = true, - "initialized" = true, + "textDocument/didClose" = true, + "textDocument/didSave" = true, + "initialized" = true, } -consume_requests :: proc (config: ^common.Config, writer: ^Writer) -> bool { +consume_requests :: proc(config: ^common.Config, writer: ^Writer) -> bool { temp_requests := make([dynamic]Request, 0, context.allocator) defer delete(temp_requests) @@ -278,14 +290,19 @@ consume_requests :: proc (config: ^common.Config, writer: ^Writer) -> bool { for d in deletings { delete_index := -1 - for request, i in requests { + for request, i in requests { if request.id == d.id { delete_index := i break } - } + } if delete_index != -1 { - cancel(requests[delete_index].value, requests[delete_index].id, writer, config) + cancel( + requests[delete_index].value, + requests[delete_index].id, + writer, + config, + ) ordered_remove(&requests, delete_index) } } @@ -304,9 +321,9 @@ consume_requests :: proc (config: ^common.Config, writer: ^Writer) -> bool { json.destroy_value(request.value) free_all(context.temp_allocator) } - + sync.mutex_lock(&requests_mutex) - + for i := 0; i < request_index; i += 1 { pop_front(&requests) } @@ -325,34 +342,44 @@ consume_requests :: proc (config: ^common.Config, writer: ^Writer) -> bool { } -cancel :: proc(value: json.Value, id: RequestId, writer: ^Writer, config: ^common.Config) { - response := make_response_message( - id = id, - params = ResponseParams {}, - ) +cancel :: proc( + value: json.Value, + id: RequestId, + writer: ^Writer, + config: ^common.Config, +) { + response := make_response_message(id = id, params = ResponseParams{}) json.destroy_value(value) send_response(response, writer) } -call :: proc(value: json.Value, id: RequestId, writer: ^Writer, config: ^common.Config) { +call :: proc( + value: json.Value, + id: RequestId, + writer: ^Writer, + config: ^common.Config, +) { root := value.(json.Object) method := root["method"].(json.String) diff: time.Duration { time.SCOPED_TICK_DURATION(&diff) - + if fn, ok := call_map[method]; !ok { - response := make_response_message_error(id = id, error = ResponseError {code = .MethodNotFound, message = ""}) + response := make_response_message_error( + id = id, + error = ResponseError{code = .MethodNotFound, message = ""}, + ) send_error(response, writer) } else { err := fn(root["params"], id, config, writer) if err != .None { response := make_response_message_error( id = id, - error = ResponseError {code = err, message = ""}, + error = ResponseError{code = err, message = ""}, ) send_error(response, writer) } @@ -362,10 +389,15 @@ call :: proc(value: json.Value, id: RequestId, writer: ^Writer, config: ^common. //log.errorf("time duration %v for %v", time.duration_milliseconds(diff), method) } -request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_initialize :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) - - if !ok { + + if !ok { return .ParseError } @@ -381,41 +413,77 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C append(&config.workspace_folders, s) } - read_ols_config :: proc(file: string, config: ^common.Config, uri: common.Uri) { + read_ols_config :: proc( + file: string, + config: ^common.Config, + uri: common.Uri, + ) { if data, ok := os.read_entire_file(file, context.temp_allocator); ok { - if value, err := json.parse(data = data, allocator = context.temp_allocator, parse_integers = true); err == .None { - ols_config: OlsConfig - - if unmarshal(value, ols_config, context.temp_allocator) == nil { + if value, err := json.parse( + data = data, + allocator = context.temp_allocator, + parse_integers = true, + ); err == .None { + ols_config: OlsConfig + + if unmarshal(value, ols_config, context.temp_allocator) == + nil { config.thread_count = ols_config.thread_pool_count - config.enable_document_symbols = ols_config.enable_document_symbols.(bool) or_else true - config.enable_hover = ols_config.enable_hover.(bool) or_else true - config.enable_semantic_tokens = ols_config.enable_semantic_tokens - config.enable_procedure_context = ols_config.enable_procedure_context + config.enable_document_symbols = + ols_config.enable_document_symbols.(bool) or_else true + config.enable_hover = + ols_config.enable_hover.(bool) or_else true + config.enable_semantic_tokens = + ols_config.enable_semantic_tokens + config.enable_procedure_context = + ols_config.enable_procedure_context config.enable_snippets = ols_config.enable_snippets config.enable_references = false config.verbose = ols_config.verbose config.file_log = ols_config.file_log - config.odin_command = strings.clone(ols_config.odin_command, context.allocator) - config.checker_args = strings.clone(ols_config.checker_args, context.allocator) + config.odin_command = strings.clone( + ols_config.odin_command, + context.allocator, + ) + config.checker_args = strings.clone( + ols_config.checker_args, + context.allocator, + ) config.enable_inlay_hints = ols_config.enable_inlay_hints config.enable_format = true - + for p in ols_config.collections { - forward_path, _ := filepath.to_slash(p.path, context.temp_allocator) + forward_path, _ := filepath.to_slash( + p.path, + context.temp_allocator, + ) //Support a basic use of '~' when ODIN_OS != .Windows { if forward_path[0] == '~' { - home := os.get_env("HOME", context.temp_allocator) - strings.replace(forward_path, "~", home, 1, context.temp_allocator) + home := os.get_env( + "HOME", + context.temp_allocator, + ) + strings.replace( + forward_path, + "~", + home, + 1, + context.temp_allocator, + ) } } if filepath.is_abs(p.path) { - config.collections[strings.clone(p.name)] = strings.clone(forward_path) + config.collections[strings.clone(p.name)] = + strings.clone(forward_path) } else { - config.collections[strings.clone(p.name)] = path.join(elems = {uri.path, forward_path}, allocator = context.allocator) + config.collections[strings.clone(p.name)] = + path.join( + elems = {uri.path, forward_path}, + allocator = context.allocator, + ) } } @@ -439,7 +507,10 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C } if uri, ok := common.parse_uri(project_uri, context.temp_allocator); ok { - ols_config_path := path.join(elems = {uri.path, "ols.json"}, allocator = context.temp_allocator) + ols_config_path := path.join( + elems = {uri.path, "ols.json"}, + allocator = context.temp_allocator, + ) read_ols_config(ols_config_path, config, uri) } @@ -452,18 +523,33 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C } if "core" not_in config.collections && odin_core_env != "" { - forward_path, _ := filepath.to_slash(odin_core_env, context.temp_allocator) - config.collections["core"] = path.join(elems = {forward_path, "core"}, allocator = context.allocator) + forward_path, _ := filepath.to_slash( + odin_core_env, + context.temp_allocator, + ) + config.collections["core"] = path.join( + elems = {forward_path, "core"}, + allocator = context.allocator, + ) } if "vendor" not_in config.collections && odin_core_env != "" { - forward_path, _ := filepath.to_slash(odin_core_env, context.temp_allocator) - config.collections["vendor"] = path.join(elems = {forward_path, "vendor"}, allocator = context.allocator) + forward_path, _ := filepath.to_slash( + odin_core_env, + context.temp_allocator, + ) + config.collections["vendor"] = path.join( + elems = {forward_path, "vendor"}, + allocator = context.allocator, + ) } when ODIN_OS == .Windows { for k, v in config.collections { - forward, _ := filepath.to_slash(common.get_case_sensitive_path(v), context.temp_allocator) + forward, _ := filepath.to_slash( + common.get_case_sensitive_path(v), + context.temp_allocator, + ) config.collections[k] = strings.clone(forward, context.allocator) } } @@ -480,24 +566,37 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C } } - config.enable_snippets &= initialize_params.capabilities.textDocument.completion.completionItem.snippetSupport - config.signature_offset_support = initialize_params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport + config.enable_snippets &= + initialize_params.capabilities.textDocument.completion.completionItem.snippetSupport + config.signature_offset_support = + initialize_params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport - completionTriggerCharacters := []string {".", ">", "#", "\"", "/", ":"} - signatureTriggerCharacters := []string {"(", ","} - signatureRetriggerCharacters := []string {","} + completionTriggerCharacters := []string{".", ">", "#", "\"", "/", ":"} + signatureTriggerCharacters := []string{"(", ","} + signatureRetriggerCharacters := []string{","} - token_type := type_info_of(SemanticTokenTypes).variant.(runtime.Type_Info_Named).base.variant.(runtime.Type_Info_Enum) - token_modifier := type_info_of(SemanticTokenModifiers).variant.(runtime.Type_Info_Named).base.variant.(runtime.Type_Info_Enum) + token_type := type_info_of( + SemanticTokenTypes, + ).variant.(runtime.Type_Info_Named).base.variant.(runtime.Type_Info_Enum) + token_modifier := type_info_of( + SemanticTokenModifiers, + ).variant.(runtime.Type_Info_Named).base.variant.(runtime.Type_Info_Enum) - token_types := make([]string, len(token_type.names), context.temp_allocator) - token_modifiers := make([]string, len(token_modifier.names), context.temp_allocator) + token_types := make( + []string, + len(token_type.names), + context.temp_allocator, + ) + token_modifiers := make( + []string, + len(token_modifier.names), + context.temp_allocator, + ) for name, i in token_type.names { - if name == "EnumMember" { + if name == "EnumMember" { token_types[i] = "enumMember" - } - else { + } else { token_types[i] = strings.to_lower(name, context.temp_allocator) } } @@ -507,43 +606,41 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C } response := make_response_message( - params = ResponseInitializeParams { - capabilities = ServerCapabilities { - textDocumentSync = TextDocumentSyncOptions { - openClose = true, - change = 2, //incremental - save = { - includeText = true, + params = ResponseInitializeParams{ + capabilities = ServerCapabilities{ + textDocumentSync = TextDocumentSyncOptions{ + openClose = true, + change = 2, + save = {includeText = true}, }, - }, - renameProvider = config.enable_rename, - referencesProvider = config.enable_references, - definitionProvider = true, - completionProvider = CompletionOptions { - resolveProvider = false, - triggerCharacters = completionTriggerCharacters, - }, - signatureHelpProvider = SignatureHelpOptions { - triggerCharacters = signatureTriggerCharacters, - retriggerCharacters = signatureRetriggerCharacters, - }, - semanticTokensProvider = SemanticTokensOptions { - range = config.enable_semantic_tokens, - full = config.enable_semantic_tokens, - legend = SemanticTokensLegend { - tokenTypes = token_types, - tokenModifiers = token_modifiers, + renameProvider = config.enable_rename,//incremental + referencesProvider = config.enable_references, + definitionProvider = true, + completionProvider = CompletionOptions{ + resolveProvider = false, + triggerCharacters = completionTriggerCharacters, }, - }, - inlayHintsProvider = config.enable_inlay_hints, - documentSymbolProvider = config.enable_document_symbols, - hoverProvider = config.enable_hover, - documentFormattingProvider = config.enable_format, - documentLinkProvider = { - resolveProvider = false, + signatureHelpProvider = SignatureHelpOptions{ + triggerCharacters = signatureTriggerCharacters, + retriggerCharacters = signatureRetriggerCharacters, + }, + semanticTokensProvider = SemanticTokensOptions{ + range = config.enable_semantic_tokens, + full = config.enable_semantic_tokens, + legend = SemanticTokensLegend{ + tokenTypes = token_types, + tokenModifiers = token_modifiers, + }, + }, + inlayHintsProvider = config.enable_inlay_hints, + documentSymbolProvider = config.enable_document_symbols, + hoverProvider = config.enable_hover, + documentFormattingProvider = config.enable_format, + documentLinkProvider = {resolveProvider = false}, }, }, - }, id = id) + id = id, + ) send_response(response, writer) @@ -562,11 +659,21 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C return .None } -request_initialized :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { - return .None +request_initialized :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { + return .None } -request_shutdown :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_shutdown :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { response := make_response_message(params = nil, id = id) send_response(response, writer) @@ -574,7 +681,12 @@ request_shutdown :: proc (params: json.Value, id: RequestId, config: ^common.Con return .None } -request_definition :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_definition :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -586,14 +698,17 @@ request_definition :: proc (params: json.Value, id: RequestId, config: ^common.C if unmarshal(params, definition_params, context.temp_allocator) != nil { return .ParseError } - + document := document_get(definition_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } - locations, ok2 := get_definition_location(document, definition_params.position) + locations, ok2 := get_definition_location( + document, + definition_params.position, + ) if !ok2 { log.warn("Failed to get definition location") @@ -610,7 +725,12 @@ request_definition :: proc (params: json.Value, id: RequestId, config: ^common.C return .None } -request_completion :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_completion :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -626,12 +746,16 @@ request_completion :: proc (params: json.Value, id: RequestId, config: ^common.C document := document_get(completition_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } list: CompletionList - list, ok = get_completion_list(document, completition_params.position, completition_params.context_) + list, ok = get_completion_list( + document, + completition_params.position, + completition_params.context_, + ) if !ok { return .InternalError @@ -644,7 +768,12 @@ request_completion :: proc (params: json.Value, id: RequestId, config: ^common.C return .None } -request_signature_help :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_signature_help :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -659,9 +788,9 @@ request_signature_help :: proc (params: json.Value, id: RequestId, config: ^comm document := document_get(signature_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } help: SignatureHelp help, ok = get_signature_information(document, signature_params.position) @@ -682,7 +811,12 @@ request_signature_help :: proc (params: json.Value, id: RequestId, config: ^comm return .None } -request_format_document :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_format_document :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -696,10 +830,10 @@ request_format_document :: proc (params: json.Value, id: RequestId, config: ^com } document := document_get(format_params.textDocument.uri) - - if document == nil { - return .InternalError - } + + if document == nil { + return .InternalError + } edit: []TextEdit edit, ok = get_complete_format(document, config) @@ -715,12 +849,22 @@ request_format_document :: proc (params: json.Value, id: RequestId, config: ^com return .None } -notification_exit :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_exit :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { config.running = false return .None } -notification_did_open :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_did_open :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -735,14 +879,24 @@ notification_did_open :: proc (params: json.Value, id: RequestId, config: ^commo return .ParseError } - if n := document_open(open_params.textDocument.uri, open_params.textDocument.text, config, writer); n != .None { + if n := document_open( + open_params.textDocument.uri, + open_params.textDocument.text, + config, + writer, + ); n != .None { return .InternalError } return .None } -notification_did_change :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_did_change :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -755,12 +909,23 @@ notification_did_change :: proc (params: json.Value, id: RequestId, config: ^com return .ParseError } - document_apply_changes(change_params.textDocument.uri, change_params.contentChanges, change_params.textDocument.version, config, writer) + document_apply_changes( + change_params.textDocument.uri, + change_params.contentChanges, + change_params.textDocument.version, + config, + writer, + ) return .None } -notification_did_close :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_did_close :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -780,7 +945,12 @@ notification_did_close :: proc(params: json.Value, id: RequestId, config: ^commo return .None } -notification_did_save :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_did_save :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -795,7 +965,10 @@ notification_did_save :: proc (params: json.Value, id: RequestId, config: ^commo uri: common.Uri - if uri, ok = common.parse_uri(save_params.textDocument.uri, context.temp_allocator); !ok { + if uri, ok = common.parse_uri( + save_params.textDocument.uri, + context.temp_allocator, + ); !ok { return .ParseError } @@ -808,9 +981,12 @@ notification_did_save :: proc (params: json.Value, id: RequestId, config: ^commo } when ODIN_OS == .Windows { - correct := common.get_case_sensitive_path(fullpath, context.temp_allocator) + correct := common.get_case_sensitive_path( + fullpath, + context.temp_allocator, + ) fullpath, _ = filepath.to_slash(correct, context.temp_allocator) - } + } dir := filepath.base(filepath.dir(fullpath, context.temp_allocator)) @@ -825,8 +1001,8 @@ notification_did_save :: proc (params: json.Value, id: RequestId, config: ^commo file := ast.File { fullpath = fullpath, - src = save_params.text, - pkg = pkg, + src = save_params.text, + pkg = pkg, } ok = parser.parse_file(&p, &file) @@ -836,27 +1012,36 @@ notification_did_save :: proc (params: json.Value, id: RequestId, config: ^commo } corrected_uri := common.create_uri(fullpath, context.temp_allocator) - + for k, v in &indexer.index.collection.packages { for k2, v2 in &v { if corrected_uri.uri == v2.uri { free_symbol(v2, indexer.index.collection.allocator) v[k2] = {} - } + } } } - if ret := collect_symbols(&indexer.index.collection, file, corrected_uri.uri); ret != .None { + if ret := collect_symbols( + &indexer.index.collection, + file, + corrected_uri.uri, + ); ret != .None { log.errorf("failed to collect symbols on save %v", ret) } - + check(uri, writer, config) return .None } -request_semantic_token_full :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_semantic_token_full :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -871,17 +1056,13 @@ request_semantic_token_full :: proc (params: json.Value, id: RequestId, config: document := document_get(semantic_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } range := common.Range { - start = common.Position { - line = 0, - }, - end = common.Position { - line = 9000000, //should be enough - }, + start = common.Position{line = 0}, + end = common.Position{line = 9000000}, //should be enough } symbols: SemanticTokens @@ -901,7 +1082,12 @@ request_semantic_token_full :: proc (params: json.Value, id: RequestId, config: return .None } -request_semantic_token_range :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_semantic_token_range :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -916,15 +1102,19 @@ request_semantic_token_range :: proc (params: json.Value, id: RequestId, config: document := document_get(semantic_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } symbols: SemanticTokens if config.enable_semantic_tokens { if file, ok := file_resolve_cache.files[document.uri.uri]; ok { - symbols = get_semantic_tokens(document, semantic_params.range, file.symbols) + symbols = get_semantic_tokens( + document, + semantic_params.range, + file.symbols, + ) } } @@ -935,7 +1125,12 @@ request_semantic_token_range :: proc (params: json.Value, id: RequestId, config: return .None } -request_document_symbols :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_document_symbols :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -950,9 +1145,9 @@ request_document_symbols :: proc (params: json.Value, id: RequestId, config: ^co document := document_get(symbol_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } symbols := get_document_symbols(document) @@ -963,7 +1158,12 @@ request_document_symbols :: proc (params: json.Value, id: RequestId, config: ^co return .None } -request_hover :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_hover :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -978,9 +1178,9 @@ request_hover :: proc (params: json.Value, id: RequestId, config: ^common.Config document := document_get(hover_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } hover: Hover valid: bool @@ -993,8 +1193,7 @@ request_hover :: proc (params: json.Value, id: RequestId, config: ^common.Config if valid { response := make_response_message(params = hover, id = id) send_response(response, writer) - } - else { + } else { response := make_response_message(params = nil, id = id) send_response(response, writer) } @@ -1002,7 +1201,12 @@ request_hover :: proc (params: json.Value, id: RequestId, config: ^common.Config return .None } -request_inlay_hint :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_inlay_hint :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -1017,9 +1221,9 @@ request_inlay_hint :: proc (params: json.Value, id: RequestId, config: ^common.C document := document_get(inlay_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } hints: []InlayHint @@ -1040,7 +1244,12 @@ request_inlay_hint :: proc (params: json.Value, id: RequestId, config: ^common.C return .None } -request_document_links :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_document_links :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -1055,9 +1264,9 @@ request_document_links :: proc (params: json.Value, id: RequestId, config: ^comm document := document_get(link_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } links: []DocumentLink links, ok = get_document_links(document) @@ -1073,7 +1282,12 @@ request_document_links :: proc (params: json.Value, id: RequestId, config: ^comm return .None } -request_rename :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_rename :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -1088,12 +1302,16 @@ request_rename :: proc (params: json.Value, id: RequestId, config: ^common.Confi document := document_get(rename_param.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } workspace_edit: WorkspaceEdit - workspace_edit, ok = get_rename(document, rename_param.newName, rename_param.position) + workspace_edit, ok = get_rename( + document, + rename_param.newName, + rename_param.position, + ) if !ok { return .InternalError @@ -1106,7 +1324,12 @@ request_rename :: proc (params: json.Value, id: RequestId, config: ^common.Confi return .None } -request_references :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_references :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -1121,9 +1344,9 @@ request_references :: proc (params: json.Value, id: RequestId, config: ^common.C document := document_get(reference_param.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } locations: []common.Location locations, ok = get_references(document, reference_param.position) diff --git a/src/server/response.odin b/src/server/response.odin index e42f9ae..d31b3cd 100644 --- a/src/server/response.odin +++ b/src/server/response.odin @@ -3,7 +3,10 @@ package server import "core:fmt" import "core:encoding/json" -send_notification :: proc (notification: Notification, writer: ^Writer) -> bool { +send_notification :: proc( + notification: Notification, + writer: ^Writer, +) -> bool { data, error := json.marshal(notification, {}, context.temp_allocator) header := fmt.tprintf("Content-Length: %v\r\n\r\n", len(data)) @@ -23,7 +26,7 @@ send_notification :: proc (notification: Notification, writer: ^Writer) -> bool return true } -send_response :: proc (response: ResponseMessage, writer: ^Writer) -> bool { +send_response :: proc(response: ResponseMessage, writer: ^Writer) -> bool { data, error := json.marshal(response, {}, context.temp_allocator) header := fmt.tprintf("Content-Length: %v\r\n\r\n", len(data)) @@ -43,7 +46,7 @@ send_response :: proc (response: ResponseMessage, writer: ^Writer) -> bool { return true } -send_error :: proc (response: ResponseMessageError, writer: ^Writer) -> bool { +send_error :: proc(response: ResponseMessageError, writer: ^Writer) -> bool { data, error := json.marshal(response, {}, context.temp_allocator) header := fmt.tprintf("Content-Length: %v\r\n\r\n", len(data)) diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin index b936419..b22d53f 100644 --- a/src/server/semantic_tokens.odin +++ b/src/server/semantic_tokens.odin @@ -32,15 +32,15 @@ SemanticTokenTypes :: enum { Method, } -SemanticTokenModifiers :: enum(u32) { - None = 0, +SemanticTokenModifiers :: enum (u32) { + None = 0, Declaration = 2, - Definition = 4, - Deprecated = 8, + Definition = 4, + Deprecated = 8, } SemanticTokensClientCapabilities :: struct { - requests: struct { + requests: struct { range: bool, }, tokenTypes: []string, @@ -81,33 +81,48 @@ SemanticTokenBuilder :: struct { selector: bool, } -make_token_builder :: proc(allocator := context.temp_allocator) -> SemanticTokenBuilder { - return { - tokens = make([dynamic]u32, 1000, context.temp_allocator), - } +make_token_builder :: proc( + allocator := context.temp_allocator, +) -> SemanticTokenBuilder { + return {tokens = make([dynamic]u32, 1000, context.temp_allocator)} } get_tokens :: proc(builder: SemanticTokenBuilder) -> SemanticTokens { - return { - data = builder.tokens[:], - } + return {data = builder.tokens[:]} } -get_semantic_tokens :: proc(document: ^Document, range: common.Range, symbols: map[uintptr]SymbolAndNode) -> SemanticTokens { +get_semantic_tokens :: proc( + document: ^Document, + range: common.Range, + symbols: map[uintptr]SymbolAndNode, +) -> SemanticTokens { builder := make_token_builder() if document.ast.pkg_decl != nil { - write_semantic_token(&builder, document.ast.pkg_token, document.ast.src, .Keyword, .None) + write_semantic_token( + &builder, + document.ast.pkg_token, + document.ast.src, + .Keyword, + .None, + ) } - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) builder.symbols = symbols ast_context.current_package = ast_context.document_package for decl in document.ast.decls { - if range.start.line <= decl.pos.line && decl.end.line <= range.end.line { + if range.start.line <= decl.pos.line && + decl.end.line <= range.end.line { visit(decl, &builder, &ast_context) } } @@ -115,22 +130,74 @@ get_semantic_tokens :: proc(document: ^Document, range: common.Range, symbols: m return get_tokens(builder) } -write_semantic_node :: proc(builder: ^SemanticTokenBuilder, node: ^ast.Node, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { - position := common.get_relative_token_position(node.pos.offset, transmute([]u8)src, builder.current_start) +write_semantic_node :: proc( + builder: ^SemanticTokenBuilder, + node: ^ast.Node, + src: string, + type: SemanticTokenTypes, + modifier: SemanticTokenModifiers, +) { + position := common.get_relative_token_position( + node.pos.offset, + transmute([]u8)src, + builder.current_start, + ) name := common.get_ast_node_string(node, src) - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, cast(u32)modifier) + append( + &builder.tokens, + cast(u32)position.line, + cast(u32)position.character, + cast(u32)len(name), + cast(u32)type, + cast(u32)modifier, + ) builder.current_start = node.pos.offset } -write_semantic_token :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { - position := common.get_relative_token_position(token.pos.offset, transmute([]u8)src, builder.current_start) - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(token.text), cast(u32)type, cast(u32)modifier) +write_semantic_token :: proc( + builder: ^SemanticTokenBuilder, + token: tokenizer.Token, + src: string, + type: SemanticTokenTypes, + modifier: SemanticTokenModifiers, +) { + position := common.get_relative_token_position( + token.pos.offset, + transmute([]u8)src, + builder.current_start, + ) + append( + &builder.tokens, + cast(u32)position.line, + cast(u32)position.character, + cast(u32)len(token.text), + cast(u32)type, + cast(u32)modifier, + ) builder.current_start = token.pos.offset } -write_semantic_string :: proc(builder: ^SemanticTokenBuilder, pos: tokenizer.Pos, name: string, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { - position := common.get_relative_token_position(pos.offset, transmute([]u8)src, builder.current_start) - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, cast(u32)modifier) +write_semantic_string :: proc( + builder: ^SemanticTokenBuilder, + pos: tokenizer.Pos, + name: string, + src: string, + type: SemanticTokenTypes, + modifier: SemanticTokenModifiers, +) { + position := common.get_relative_token_position( + pos.offset, + transmute([]u8)src, + builder.current_start, + ) + append( + &builder.tokens, + cast(u32)position.line, + cast(u32)position.character, + cast(u32)len(name), + cast(u32)type, + cast(u32)modifier, + ) builder.current_start = pos.offset } @@ -141,23 +208,39 @@ visit :: proc { visit_stmt, } -visit_array :: proc(array: $A/[]^$T, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_array :: proc( + array: $A/[]^$T, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { for elem, i in array { visit(elem, builder, ast_context) } } -visit_dynamic_array :: proc(array: $A/[dynamic]^$T, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_dynamic_array :: proc( + array: $A/[dynamic]^$T, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { for elem, i in array { visit(elem, builder, ast_context) } } -visit_stmt :: proc(node: ^ast.Stmt, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_stmt :: proc( + node: ^ast.Stmt, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { visit_node(node, builder, ast_context) } -visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_node :: proc( + node: ^ast.Node, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { using ast if node == nil { @@ -166,47 +249,123 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: #partial switch n in node.derived { case ^Ellipsis: - write_semantic_string(builder, node.pos, "..", ast_context.file.src, .Operator, .None) + write_semantic_string( + builder, + node.pos, + "..", + ast_context.file.src, + .Operator, + .None, + ) visit(n.expr, builder, ast_context) case ^Ident: if symbol_and_node, ok := builder.symbols[cast(uintptr)node]; ok { - if symbol_and_node.symbol.type == .Variable || symbol_and_node.symbol.type == .Constant { - write_semantic_node(builder, node, ast_context.file.src, .Variable, .None) + if symbol_and_node.symbol.type == .Variable || + symbol_and_node.symbol.type == .Constant { + write_semantic_node( + builder, + node, + ast_context.file.src, + .Variable, + .None, + ) return - } + } - #partial switch v in symbol_and_node.symbol.value { + #partial switch v in symbol_and_node.symbol.value { case SymbolPackageValue: - write_semantic_node(builder, node, ast_context.file.src, .Namespace, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Namespace, + .None, + ) case SymbolStructValue: - write_semantic_node(builder, node, ast_context.file.src, .Struct, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Struct, + .None, + ) case SymbolEnumValue: - write_semantic_node(builder, node, ast_context.file.src, .Enum, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Enum, + .None, + ) case SymbolUnionValue: - write_semantic_node(builder, node, ast_context.file.src, .Enum, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Enum, + .None, + ) case SymbolProcedureValue: - write_semantic_node(builder, node, ast_context.file.src, .Function, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Function, + .None, + ) case SymbolProcedureGroupValue: - write_semantic_node(builder, node, ast_context.file.src, .Function, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Function, + .None, + ) case SymbolUntypedValue: - write_semantic_node(builder, node, ast_context.file.src, .Type, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Type, + .None, + ) case SymbolBasicValue: - write_semantic_node(builder, node, ast_context.file.src, .Type, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Type, + .None, + ) case: - //log.errorf("Unexpected symbol value: %v", symbol.value); - //panic(fmt.tprintf("Unexpected symbol value: %v", symbol.value)); + //log.errorf("Unexpected symbol value: %v", symbol.value); + //panic(fmt.tprintf("Unexpected symbol value: %v", symbol.value)); } } case ^Selector_Expr: visit_selector(cast(^Selector_Expr)node, builder, ast_context) builder.selector = false case ^When_Stmt: - write_semantic_string(builder, n.when_pos, "when", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.when_pos, + "when", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.cond, builder, ast_context) visit(n.body, builder, ast_context) visit(n.else_stmt, builder, ast_context) case ^Pointer_Type: - write_semantic_string(builder, node.pos, "^", ast_context.file.src, .Operator, .None) + write_semantic_string( + builder, + node.pos, + "^", + ast_context.file.src, + .Operator, + .None, + ) visit(n.elem, builder, ast_context) case ^Value_Decl: visit_value_decl(n^, builder, ast_context) @@ -215,52 +374,126 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: case ^Expr_Stmt: visit(n.expr, builder, ast_context) case ^Branch_Stmt: - write_semantic_token(builder, n.tok, ast_context.file.src, .Keyword, .None) + write_semantic_token( + builder, + n.tok, + ast_context.file.src, + .Keyword, + .None, + ) case ^Poly_Type: - write_semantic_string(builder, n.dollar, "$", ast_context.file.src, .Operator, .None) + write_semantic_string( + builder, + n.dollar, + "$", + ast_context.file.src, + .Operator, + .None, + ) visit(n.type, builder, ast_context) visit(n.specialization, builder, ast_context) case ^Range_Stmt: - write_semantic_string(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.for_pos, + "for", + ast_context.file.src, + .Keyword, + .None, + ) for val in n.vals { if ident, ok := val.derived.(^Ident); ok { - write_semantic_node(builder, val, ast_context.file.src, .Variable, .None) + write_semantic_node( + builder, + val, + ast_context.file.src, + .Variable, + .None, + ) } } - write_semantic_string(builder, n.in_pos, "in", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.in_pos, + "in", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.expr, builder, ast_context) visit(n.body, builder, ast_context) case ^If_Stmt: - write_semantic_string(builder, n.if_pos, "if", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.if_pos, + "if", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.init, builder, ast_context) visit(n.cond, builder, ast_context) visit(n.body, builder, ast_context) if n.else_stmt != nil { - write_semantic_string(builder, n.else_pos, "else", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.else_pos, + "else", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.else_stmt, builder, ast_context) } case ^For_Stmt: - write_semantic_string(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.for_pos, + "for", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.init, builder, ast_context) visit(n.cond, builder, ast_context) visit(n.post, builder, ast_context) visit(n.body, builder, ast_context) case ^Switch_Stmt: - write_semantic_string(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.switch_pos, + "switch", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.init, builder, ast_context) visit(n.cond, builder, ast_context) visit(n.body, builder, ast_context) case ^Type_Switch_Stmt: - write_semantic_string(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.switch_pos, + "switch", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.tag, builder, ast_context) visit(n.expr, builder, ast_context) visit(n.body, builder, ast_context) case ^Assign_Stmt: for l in n.lhs { if ident, ok := l.derived.(^Ident); ok { - write_semantic_node(builder, l, ast_context.file.src, .Variable, .None) + write_semantic_node( + builder, + l, + ast_context.file.src, + .Variable, + .None, + ) } else { visit(l, builder, ast_context) } @@ -269,14 +502,27 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: visit_token_op(builder, n.op, ast_context.file.src) visit(n.rhs, builder, ast_context) case ^Case_Clause: - write_semantic_string(builder, n.case_pos, "case", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.case_pos, + "case", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.list, builder, ast_context) visit(n.body, builder, ast_context) case ^Call_Expr: visit(n.expr, builder, ast_context) visit(n.args, builder, ast_context) case ^Implicit_Selector_Expr: - write_semantic_node(builder, n.field, ast_context.file.src, .Enum, .None) + write_semantic_node( + builder, + n.field, + ast_context.file.src, + .EnumMember, + .None, + ) case ^Array_Type: visit(n.elem, builder, ast_context) case ^Binary_Expr: @@ -287,13 +533,27 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: visit(n.type, builder, ast_context) visit(n.elems, builder, ast_context) case ^Struct_Type: - write_semantic_string(builder, n.pos, "struct", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "struct", + ast_context.file.src, + .Keyword, + .None, + ) visit_struct_fields(n^, builder, ast_context) case ^Type_Assertion: visit(n.expr, builder, ast_context) visit(n.type, builder, ast_context) case ^Type_Cast: - write_semantic_string(builder, n.pos, "cast", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "cast", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.type, builder, ast_context) visit(n.expr, builder, ast_context) case ^Paren_Expr: @@ -301,17 +561,44 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: case ^Deref_Expr: visit(n.expr, builder, ast_context) case ^Return_Stmt: - write_semantic_string(builder, n.pos, "return", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "return", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.results, builder, ast_context) case ^Dynamic_Array_Type: - write_semantic_string(builder, n.dynamic_pos, "dynamic", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.dynamic_pos, + "dynamic", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.elem, builder, ast_context) case ^Multi_Pointer_Type: - write_semantic_string(builder, n.pos, "[^]", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "[^]", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.elem, builder, ast_context) case ^Field_Value: if ident, ok := n.field.derived.(^Ident); ok { - write_semantic_node(builder, n.field, ast_context.file.src, .Property, .None) + write_semantic_node( + builder, + n.field, + ast_context.file.src, + .Property, + .None, + ) } visit(n.value, builder, ast_context) @@ -326,29 +613,80 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: case ^Slice_Expr: visit(n.expr, builder, ast_context) case ^Using_Stmt: - write_semantic_string(builder, n.pos, "using", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "using", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.list, builder, ast_context) case ^Map_Type: - write_semantic_string(builder, n.tok_pos, "map", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.tok_pos, + "map", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.key, builder, ast_context) visit(n.value, builder, ast_context) case ^Defer_Stmt: - write_semantic_string(builder, n.pos, "defer", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "defer", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.stmt, builder, ast_context) case ^Import_Decl: - write_semantic_token(builder, n.import_tok, ast_context.file.src, .Keyword, .None) + write_semantic_token( + builder, + n.import_tok, + ast_context.file.src, + .Keyword, + .None, + ) if n.name.text != "" { - write_semantic_token(builder, n.name, ast_context.file.src, .Namespace, .None) + write_semantic_token( + builder, + n.name, + ast_context.file.src, + .Namespace, + .None, + ) } - write_semantic_token(builder, n.relpath, ast_context.file.src, .String, .None) + write_semantic_token( + builder, + n.relpath, + ast_context.file.src, + .String, + .None, + ) case ^Or_Return_Expr: visit(n.expr, builder, ast_context) - write_semantic_token(builder, n.token, ast_context.file.src, .Keyword, .None) + write_semantic_token( + builder, + n.token, + ast_context.file.src, + .Keyword, + .None, + ) case ^Or_Else_Expr: visit(n.x, builder, ast_context) - write_semantic_token(builder, n.token, ast_context.file.src, .Keyword, .None) + write_semantic_token( + builder, + n.token, + ast_context.file.src, + .Keyword, + .None, + ) visit(n.y, builder, ast_context) case ^Ternary_If_Expr: if n.op1.text == "if" { @@ -359,38 +697,70 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: visit(n.cond, builder, ast_context) visit(n.x, builder, ast_context) visit(n.y, builder, ast_context) - } + } case ^Ternary_When_Expr: visit(n.cond, builder, ast_context) visit(n.x, builder, ast_context) visit(n.y, builder, ast_context) case: - //log.errorf("unhandled semantic token node %v", n); - //panic(fmt.tprintf("Missed semantic token handling %v", n)); + //log.errorf("unhandled semantic token node %v", n); + //panic(fmt.tprintf("Missed semantic token handling %v", n)); } } -visit_basic_lit :: proc(basic_lit: ast.Basic_Lit, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_basic_lit :: proc( + basic_lit: ast.Basic_Lit, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { if symbol, ok := resolve_basic_lit(ast_context, basic_lit); ok { if untyped, ok := symbol.value.(SymbolUntypedValue); ok { switch untyped.type { case .Bool: - write_semantic_token(builder, basic_lit.tok, ast_context.file.src, .Keyword, .None) + write_semantic_token( + builder, + basic_lit.tok, + ast_context.file.src, + .Keyword, + .None, + ) case .Float, .Integer: - write_semantic_token(builder, basic_lit.tok, ast_context.file.src, .Number, .None) + write_semantic_token( + builder, + basic_lit.tok, + ast_context.file.src, + .Number, + .None, + ) case .String: - write_semantic_token(builder, basic_lit.tok, ast_context.file.src, .String, .None) + write_semantic_token( + builder, + basic_lit.tok, + ast_context.file.src, + .String, + .None, + ) } } } } -visit_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_value_decl :: proc( + value_decl: ast.Value_Decl, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { using ast if value_decl.type != nil { for name in value_decl.names { - write_semantic_node(builder, name, ast_context.file.src, .Variable, .None) + write_semantic_node( + builder, + name, + ast_context.file.src, + .Variable, + .None, + ) } visit(value_decl.type, builder, ast_context) @@ -401,41 +771,124 @@ visit_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuil if len(value_decl.values) == 1 { #partial switch v in value_decl.values[0].derived { case ^Union_Type: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Enum, .None) - write_semantic_string(builder, v.pos, "union", ast_context.file.src, .Keyword, .None) + write_semantic_node( + builder, + value_decl.names[0], + ast_context.file.src, + .Enum, + .None, + ) + write_semantic_string( + builder, + v.pos, + "union", + ast_context.file.src, + .Keyword, + .None, + ) visit(v.variants, builder, ast_context) case ^Struct_Type: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Struct, .None) - write_semantic_string(builder, v.pos, "struct", ast_context.file.src, .Keyword, .None) + write_semantic_node( + builder, + value_decl.names[0], + ast_context.file.src, + .Struct, + .None, + ) + write_semantic_string( + builder, + v.pos, + "struct", + ast_context.file.src, + .Keyword, + .None, + ) visit_struct_fields(v^, builder, ast_context) case ^Enum_Type: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Enum, .None) - write_semantic_string(builder, v.pos, "enum", ast_context.file.src, .Keyword, .None) + write_semantic_node( + builder, + value_decl.names[0], + ast_context.file.src, + .Enum, + .None, + ) + write_semantic_string( + builder, + v.pos, + "enum", + ast_context.file.src, + .Keyword, + .None, + ) visit_enum_fields(v^, builder, ast_context) case ^Proc_Group: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Function, .None) - write_semantic_string(builder, v.pos, "proc", ast_context.file.src, .Keyword, .None) + write_semantic_node( + builder, + value_decl.names[0], + ast_context.file.src, + .Function, + .None, + ) + write_semantic_string( + builder, + v.pos, + "proc", + ast_context.file.src, + .Keyword, + .None, + ) for arg in v.args { if ident, ok := arg.derived.(^Ident); ok { - write_semantic_node(builder, arg, ast_context.file.src, .Function, .None) + write_semantic_node( + builder, + arg, + ast_context.file.src, + .Function, + .None, + ) } } case ^Proc_Lit: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Function, .None) - write_semantic_string(builder, v.pos, "proc", ast_context.file.src, .Keyword, .None) + write_semantic_node( + builder, + value_decl.names[0], + ast_context.file.src, + .Function, + .None, + ) + write_semantic_string( + builder, + v.pos, + "proc", + ast_context.file.src, + .Keyword, + .None, + ) visit_proc_type(v.type, builder, ast_context) visit(v.body, builder, ast_context) case: for name in value_decl.names { - write_semantic_node(builder, name, ast_context.file.src, .Variable, .None) + write_semantic_node( + builder, + name, + ast_context.file.src, + .Variable, + .None, + ) } visit(value_decl.values[0], builder, ast_context) } } else { for name in value_decl.names { - write_semantic_node(builder, name, ast_context.file.src, .Variable, .None) + write_semantic_node( + builder, + name, + ast_context.file.src, + .Variable, + .None, + ) } for value in value_decl.values { @@ -444,15 +897,37 @@ visit_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuil } } -visit_token_op :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: string) { +visit_token_op :: proc( + builder: ^SemanticTokenBuilder, + token: tokenizer.Token, + src: string, +) { if token.text == "in" { - write_semantic_string(builder, token.pos, token.text, src, .Keyword, .None) + write_semantic_string( + builder, + token.pos, + token.text, + src, + .Keyword, + .None, + ) } else { - write_semantic_string(builder, token.pos, token.text, src, .Operator, .None) + write_semantic_string( + builder, + token.pos, + token.text, + src, + .Operator, + .None, + ) } } -visit_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_proc_type :: proc( + node: ^ast.Proc_Type, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { using ast if node == nil { @@ -463,7 +938,13 @@ visit_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder, as for param in node.params.list { for name in param.names { if ident, ok := name.derived.(^Ident); ok { - write_semantic_node(builder, name, ast_context.file.src, .Parameter, .None) + write_semantic_node( + builder, + name, + ast_context.file.src, + .Parameter, + .None, + ) } } @@ -479,7 +960,11 @@ visit_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder, as } } -visit_enum_fields :: proc(node: ast.Enum_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_enum_fields :: proc( + node: ast.Enum_Type, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { using ast if node.fields == nil { @@ -488,18 +973,33 @@ visit_enum_fields :: proc(node: ast.Enum_Type, builder: ^SemanticTokenBuilder, a for field in node.fields { if ident, ok := field.derived.(^Ident); ok { - write_semantic_node(builder, field, ast_context.file.src, .EnumMember, .None) - } - else if f, ok := field.derived.(^Field_Value); ok { + write_semantic_node( + builder, + field, + ast_context.file.src, + .EnumMember, + .None, + ) + } else if f, ok := field.derived.(^Field_Value); ok { if _, ok := f.field.derived.(^Ident); ok { - write_semantic_node(builder, f.field, ast_context.file.src, .EnumMember, .None) + write_semantic_node( + builder, + f.field, + ast_context.file.src, + .EnumMember, + .None, + ) } visit(f.value, builder, ast_context) } } } -visit_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_struct_fields :: proc( + node: ast.Struct_Type, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { using ast if node.fields == nil { @@ -509,7 +1009,13 @@ visit_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilde for field in node.fields.list { for name in field.names { if ident, ok := name.derived.(^Ident); ok { - write_semantic_node(builder, name, ast_context.file.src, .Property, .None) + write_semantic_node( + builder, + name, + ast_context.file.src, + .Property, + .None, + ) } } @@ -517,9 +1023,17 @@ visit_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilde } } -visit_selector :: proc(selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_selector :: proc( + selector: ^ast.Selector_Expr, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { if _, ok := selector.expr.derived.(^ast.Selector_Expr); ok { - visit_selector(cast(^ast.Selector_Expr)selector.expr, builder, ast_context) + visit_selector( + cast(^ast.Selector_Expr)selector.expr, + builder, + ast_context, + ) } else { visit(selector.expr, builder, ast_context) builder.selector = true @@ -527,21 +1041,63 @@ visit_selector :: proc(selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuil if symbol_and_node, ok := builder.symbols[cast(uintptr)selector]; ok { if symbol_and_node.symbol.type == .Variable { - write_semantic_node(builder, selector.field, ast_context.file.src, .Property, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Property, + .None, + ) } - #partial switch v in symbol_and_node.symbol.value { + #partial switch v in symbol_and_node.symbol.value { case SymbolPackageValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Namespace, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Namespace, + .None, + ) case SymbolStructValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Struct, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Struct, + .None, + ) case SymbolEnumValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Enum, + .None, + ) case SymbolUnionValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Enum, + .None, + ) case SymbolProcedureValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Function, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Function, + .None, + ) case SymbolProcedureGroupValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Function, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Function, + .None, + ) } } -}
\ No newline at end of file +} diff --git a/src/server/signature.odin b/src/server/signature.odin index 0036bf2..e5acfa9 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -52,7 +52,7 @@ ParameterInformation :: struct { build_procedure_symbol_signature :: proc(symbol: ^Symbol) { if value, ok := symbol.value.(SymbolProcedureValue); ok { builder := strings.builder_make(context.temp_allocator) - + strings.write_string(&builder, "proc") strings.write_string(&builder, "(") for arg, i in value.arg_types { @@ -69,14 +69,14 @@ build_procedure_symbol_signature :: proc(symbol: ^Symbol) { if len(value.return_types) > 1 { strings.write_string(&builder, "(") } - + for arg, i in value.return_types { strings.write_string(&builder, common.node_to_string(arg)) if i != len(value.return_types) - 1 { strings.write_string(&builder, ", ") } } - + if len(value.return_types) > 1 { strings.write_string(&builder, ")") } @@ -90,7 +90,7 @@ build_procedure_symbol_signature :: proc(symbol: ^Symbol) { seperate_proc_field_arguments :: proc(procedure: ^Symbol) { if value, ok := &procedure.value.(SymbolProcedureValue); ok { types := make([dynamic]^ast.Field, context.temp_allocator) - + for arg, i in value.arg_types { if len(arg.names) == 1 { append(&types, arg) @@ -98,7 +98,12 @@ seperate_proc_field_arguments :: proc(procedure: ^Symbol) { } for name in arg.names { - field : ^ast.Field = new_type(ast.Field, {}, {}, context.temp_allocator) + field: ^ast.Field = new_type( + ast.Field, + {}, + {}, + context.temp_allocator, + ) field.names = make([]^ast.Expr, 1, context.temp_allocator) field.names[0] = name field.type = arg.type @@ -110,12 +115,28 @@ seperate_proc_field_arguments :: proc(procedure: ^Symbol) { } } -get_signature_information :: proc(document: ^Document, position: common.Position) -> (SignatureHelp, bool) { +get_signature_information :: proc( + document: ^Document, + position: common.Position, +) -> ( + SignatureHelp, + bool, +) { signature_help: SignatureHelp - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) - position_context, ok := get_document_position_context(document, position, .SignatureHelp) + position_context, ok := get_document_position_context( + document, + position, + .SignatureHelp, + ) if !ok { return signature_help, true @@ -129,12 +150,17 @@ get_signature_information :: proc(document: ^Document, position: common.Position get_globals(document.ast, &ast_context) if position_context.function != nil { - get_locals(document.ast, position_context.function, &ast_context, &position_context) + get_locals( + document.ast, + position_context.function, + &ast_context, + &position_context, + ) } for comma, i in position_context.call_commas { if position_context.position > comma { - signature_help.activeParameter = i+1 + signature_help.activeParameter = i + 1 } else if position_context.position == comma { signature_help.activeParameter = i } @@ -144,20 +170,31 @@ get_signature_information :: proc(document: ^Document, position: common.Position call, ok = resolve_type_expression(&ast_context, position_context.call) if !ok { - return signature_help, true + return signature_help, true } seperate_proc_field_arguments(&call) - signature_information := make([dynamic]SignatureInformation, context.temp_allocator) + signature_information := make( + [dynamic]SignatureInformation, + context.temp_allocator, + ) if value, ok := call.value.(SymbolProcedureValue); ok { - parameters := make([]ParameterInformation, len(value.arg_types), context.temp_allocator) - + parameters := make( + []ParameterInformation, + len(value.arg_types), + context.temp_allocator, + ) + for arg, i in value.arg_types { if arg.type != nil { - if _, is_ellipsis := arg.type.derived.(^ast.Ellipsis); is_ellipsis { - signature_help.activeParameter = min(i, signature_help.activeParameter) + if _, is_ellipsis := arg.type.derived.(^ast.Ellipsis); + is_ellipsis { + signature_help.activeParameter = min( + i, + signature_help.activeParameter, + ) } } @@ -167,10 +204,14 @@ get_signature_information :: proc(document: ^Document, position: common.Position build_procedure_symbol_signature(&call) info := SignatureInformation { - label = concatenate_symbol_information(&ast_context, call, false), + label = concatenate_symbol_information( + &ast_context, + call, + false, + ), documentation = call.doc, - parameters = parameters, - } + parameters = parameters, + } append(&signature_information, info) } else if value, ok := call.value.(SymbolAggregateValue); ok { //function overloaded procedures @@ -178,12 +219,20 @@ get_signature_information :: proc(document: ^Document, position: common.Position symbol := symbol if value, ok := symbol.value.(SymbolProcedureValue); ok { - parameters := make([]ParameterInformation, len(value.arg_types), context.temp_allocator) + parameters := make( + []ParameterInformation, + len(value.arg_types), + context.temp_allocator, + ) - for arg, i in value.arg_types { + for arg, i in value.arg_types { if arg.type != nil { - if _, is_ellipsis := arg.type.derived.(^ast.Ellipsis); is_ellipsis { - signature_help.activeParameter = min(i, signature_help.activeParameter) + if _, is_ellipsis := arg.type.derived.(^ast.Ellipsis); + is_ellipsis { + signature_help.activeParameter = min( + i, + signature_help.activeParameter, + ) } } @@ -193,9 +242,13 @@ get_signature_information :: proc(document: ^Document, position: common.Position build_procedure_symbol_signature(&symbol) info := SignatureInformation { - label = concatenate_symbol_information(&ast_context, symbol, false), + label = concatenate_symbol_information( + &ast_context, + symbol, + false, + ), documentation = symbol.doc, - } + } append(&signature_information, info) } @@ -205,4 +258,4 @@ get_signature_information :: proc(document: ^Document, position: common.Position signature_help.signatures = signature_information[:] return signature_help, true -}
\ No newline at end of file +} diff --git a/src/server/snippets.odin b/src/server/snippets.odin index 94cb919..c8144bb 100644 --- a/src/server/snippets.odin +++ b/src/server/snippets.odin @@ -7,6 +7,14 @@ Snippet_Info :: struct { } snippets: map[string]Snippet_Info = { - "ff" = {insert = "fmt.printf(\"${1:text}\", ${0:args})", packages = []string{"fmt"}, detail = "printf"}, - "fl" = {insert = "fmt.println(\"${1:text}\")", packages = []string{"fmt"}, detail = "println"}, + "ff" = { + insert = "fmt.printf(\"${1:text}\", ${0:args})", + packages = []string{"fmt"}, + detail = "printf", + }, + "fl" = { + insert = "fmt.println(\"${1:text}\")", + packages = []string{"fmt"}, + detail = "println", + }, } diff --git a/src/server/symbol.odin b/src/server/symbol.odin index 4b4eea7..f143e5c 100644 --- a/src/server/symbol.odin +++ b/src/server/symbol.odin @@ -12,7 +12,7 @@ import "shared:common" SymbolAndNode :: struct { symbol: Symbol, - node: ^ast.Node, + node: ^ast.Node, } SymbolStructValue :: struct { @@ -46,7 +46,7 @@ SymbolEnumValue :: struct { SymbolUnionValue :: struct { types: []^ast.Expr, - poly: ^ast.Field_List, + poly: ^ast.Field_List, } SymbolDynamicArrayValue :: struct { @@ -75,7 +75,12 @@ SymbolBitSetValue :: struct { } SymbolUntypedValue :: struct { - type: enum {Integer, Float, String, Bool}, + type: enum { + Integer, + Float, + String, + Bool, + }, } SymbolMapValue :: struct { @@ -122,16 +127,16 @@ SymbolFlag :: enum { SymbolFlags :: bit_set[SymbolFlag] Symbol :: struct { - range: common.Range, //the range of the symbol in the file - uri: string, //uri of the file the symbol resides - pkg: string, //absolute directory path where the symbol resides - name: string, //name of the symbol - doc: string, - signature: string, //type signature - type: SymbolType, - value: SymbolValue, - pointers: int, //how many `^` are applied to the symbol - flags: SymbolFlags, + range: common.Range, //the range of the symbol in the file + uri: string, //uri of the file the symbol resides + pkg: string, //absolute directory path where the symbol resides + name: string, //name of the symbol + doc: string, + signature: string, //type signature + type: SymbolType, + value: SymbolValue, + pointers: int, //how many `^` are applied to the symbol + flags: SymbolFlags, } SymbolType :: enum { @@ -148,7 +153,10 @@ SymbolType :: enum { Unresolved = 1, //Use text if not being able to resolve it. } -new_clone_symbol :: proc(data: Symbol, allocator := context.allocator) -> (^Symbol) { +new_clone_symbol :: proc( + data: Symbol, + allocator := context.allocator, +) -> ^Symbol { new_symbol := new(Symbol, allocator) new_symbol^ = data new_symbol.value = data.value @@ -156,8 +164,10 @@ new_clone_symbol :: proc(data: Symbol, allocator := context.allocator) -> (^Symb } free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { - if symbol.signature != "" && symbol.signature != "struct" && - symbol.signature != "union" && symbol.signature != "enum" && + if symbol.signature != "" && + symbol.signature != "struct" && + symbol.signature != "union" && + symbol.signature != "enum" && symbol.signature != "bitset" { delete(symbol.signature, allocator) } @@ -203,4 +213,4 @@ free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { common.free_ast(v.value, allocator) case SymbolUntypedValue, SymbolPackageValue: } -}
\ No newline at end of file +} diff --git a/src/server/types.odin b/src/server/types.odin index dcc741a..80f13ad 100644 --- a/src/server/types.odin +++ b/src/server/types.odin @@ -119,7 +119,7 @@ HoverClientCapabilities :: struct { } DocumentSymbolClientCapabilities :: struct { - symbolKind: struct { + symbolKind: struct { valueSet: [dynamic]SymbolKind, }, hierarchicalDocumentSymbolSupport: bool, @@ -147,7 +147,7 @@ CompletionItemCapabilities :: struct { CompletionClientCapabilities :: struct { documentationFormat: [dynamic]string, completionItem: CompletionItemCapabilities, -} +} ParameterInformationCapabilities :: struct { labelOffsetSupport: bool, @@ -155,7 +155,7 @@ ParameterInformationCapabilities :: struct { ClientCapabilities :: struct { textDocument: TextDocumentClientCapabilities, - general: GeneralClientCapabilities, + general: GeneralClientCapabilities, } RangeOptional :: union { @@ -283,7 +283,7 @@ InsertTextFormat :: enum { } InsertTextMode :: enum { - asIs = 1, + asIs = 1, adjustIndentation = 2, } @@ -410,8 +410,8 @@ DocumentLinkParams :: struct { } DocumentLink :: struct { - range: common.Range, - target: string, + range: common.Range, + target: string, tooltip: string, } @@ -424,9 +424,9 @@ PrepareSupportDefaultBehavior :: enum { } RenameClientCapabilities :: struct { - prepareSupport: bool, + prepareSupport: bool, prepareSupportDefaultBehavior: PrepareSupportDefaultBehavior, - honorsChangeAnnotations: bool, + honorsChangeAnnotations: bool, } RenameParams :: struct { @@ -447,10 +447,9 @@ OptionalVersionedTextDocumentIdentifier :: struct { TextDocumentEdit :: struct { textDocument: OptionalVersionedTextDocumentIdentifier, - edits: []TextEdit, + edits: []TextEdit, } WorkspaceEdit :: struct { documentChanges: []TextDocumentEdit, } - diff --git a/src/server/unmarshal.odin b/src/server/unmarshal.odin index 7aba429..bda15a7 100644 --- a/src/server/unmarshal.odin +++ b/src/server/unmarshal.odin @@ -10,7 +10,11 @@ import "core:fmt" Right now union handling is type specific so you can only have one struct type, int type, etc. */ -unmarshal :: proc(json_value: json.Value, v: any, allocator: mem.Allocator) -> json.Marshal_Error { +unmarshal :: proc( + json_value: json.Value, + v: any, + allocator: mem.Allocator, +) -> json.Marshal_Error { using runtime @@ -29,11 +33,18 @@ unmarshal :: proc(json_value: json.Value, v: any, allocator: mem.Allocator) -> j #partial switch variant in type_info.variant { case Type_Info_Struct: for field, i in variant.names { - a := any {rawptr(uintptr(v.data) + uintptr(variant.offsets[i])), variant.types[i].id} + a := any{ + rawptr(uintptr(v.data) + uintptr(variant.offsets[i])), + variant.types[i].id, + } //TEMP most likely have to rewrite the entire unmarshal using tags instead, because i sometimes have to support names like 'context', which can't be written like that - if field[len(field)-1] == '_' { - if ret := unmarshal(j[field[:len(field)-1]], a, allocator); ret != nil { + if field[len(field) - 1] == '_' { + if ret := unmarshal( + j[field[:len(field) - 1]], + a, + allocator, + ); ret != nil { return ret } } else { @@ -47,31 +58,44 @@ unmarshal :: proc(json_value: json.Value, v: any, allocator: mem.Allocator) -> j case Type_Info_Union: tag_ptr := uintptr(v.data) + variant.tag_offset - tag_any := any {rawptr(tag_ptr), variant.tag_type.id} + tag_any := any{rawptr(tag_ptr), variant.tag_type.id} not_optional := 1 - mem.copy(cast(rawptr)tag_ptr, ¬_optional, size_of(variant.tag_type)) + mem.copy( + cast(rawptr)tag_ptr, + ¬_optional, + size_of(variant.tag_type), + ) id := variant.variants[0].id - unmarshal(json_value, any {v.data, id}, allocator) + unmarshal(json_value, any{v.data, id}, allocator) } case json.Array: #partial switch variant in type_info.variant { case Type_Info_Dynamic_Array: array := (^mem.Raw_Dynamic_Array)(v.data) if array.data == nil { - array.data = mem.alloc(len(j) * variant.elem_size, variant.elem.align, allocator) - array.len = len(j) - array.cap = len(j) + array.data = mem.alloc( + len(j) * variant.elem_size, + variant.elem.align, + allocator, + ) + array.len = len(j) + array.cap = len(j) array.allocator = allocator } else { return .Unsupported_Type } - for i in 0..<array.len { - a := any {rawptr(uintptr(array.data) + uintptr(variant.elem_size * i)), variant.elem.id} + for i in 0 ..< array.len { + a := any{ + rawptr( + uintptr(array.data) + uintptr(variant.elem_size * i), + ), + variant.elem.id, + } if ret := unmarshal(j[i], a, allocator); ret != nil { return ret @@ -91,7 +115,7 @@ unmarshal :: proc(json_value: json.Value, v: any, allocator: mem.Allocator) -> j for name, i in variant.names { lower_name := strings.to_lower(name, allocator) - lower_j := strings.to_lower(string(j), allocator) + lower_j := strings.to_lower(string(j), allocator) if lower_name == lower_j { mem.copy(v.data, &variant.values[i], size_of(variant.base)) @@ -142,20 +166,24 @@ unmarshal :: proc(json_value: json.Value, v: any, allocator: mem.Allocator) -> j case json.Null: case json.Boolean: #partial switch variant in &type_info.variant { - case Type_Info_Boolean: - tmp := bool(j) - mem.copy(v.data, &tmp, type_info.size) - case Type_Info_Union: - tag_ptr := uintptr(v.data) + variant.tag_offset - tag_any := any {rawptr(tag_ptr), variant.tag_type.id} - - not_optional := 1 - - mem.copy(cast(rawptr)tag_ptr, ¬_optional, size_of(variant.tag_type)) - - id := variant.variants[0].id - - unmarshal(json_value, any {v.data, id}, allocator) + case Type_Info_Boolean: + tmp := bool(j) + mem.copy(v.data, &tmp, type_info.size) + case Type_Info_Union: + tag_ptr := uintptr(v.data) + variant.tag_offset + tag_any := any{rawptr(tag_ptr), variant.tag_type.id} + + not_optional := 1 + + mem.copy( + cast(rawptr)tag_ptr, + ¬_optional, + size_of(variant.tag_type), + ) + + id := variant.variants[0].id + + unmarshal(json_value, any{v.data, id}, allocator) } case: return .Unsupported_Type diff --git a/src/server/writer.odin b/src/server/writer.odin index bbd0cac..5c39f69 100644 --- a/src/server/writer.odin +++ b/src/server/writer.odin @@ -15,7 +15,10 @@ Writer :: struct { } make_writer :: proc(writer_fn: WriterFn, writer_context: rawptr) -> Writer { - writer := Writer {writer_context = writer_context, writer_fn = writer_fn} + writer := Writer { + writer_context = writer_context, + writer_fn = writer_fn, + } return writer } |