package server import "core:fmt" import "core:hash" import "core:log" import "core:mem" import "core:odin/ast" import "core:odin/tokenizer" import "core:path/filepath" import path "core:path/slashpath" import "core:slice" import "core:strings" import "shared:common" SymbolAndNode :: struct { symbol: Symbol, node: ^ast.Node, is_resolved: bool, } SymbolStructValue :: struct { names: []string, ranges: []common.Range, types: []^ast.Expr, usings: map[int]bool, poly: ^ast.Field_List, args: []^ast.Expr, //The arguments in the call expression for poly } SymbolPackageValue :: struct {} SymbolProcedureValue :: struct { return_types: []^ast.Field, arg_types: []^ast.Field, generic: bool, } SymbolProcedureGroupValue :: struct { group: ^ast.Expr, } //runtime temp symbol value SymbolAggregateValue :: struct { symbols: []Symbol, } SymbolEnumValue :: struct { names: []string, ranges: []common.Range, } SymbolUnionValue :: struct { types: []^ast.Expr, poly: ^ast.Field_List, } SymbolDynamicArrayValue :: struct { expr: ^ast.Expr, } SymbolMultiPointer :: struct { expr: ^ast.Expr, } SymbolFixedArrayValue :: struct { len: ^ast.Expr, expr: ^ast.Expr, } SymbolSliceValue :: struct { expr: ^ast.Expr, } SymbolBasicValue :: struct { ident: ^ast.Ident, } SymbolBitSetValue :: struct { expr: ^ast.Expr, } SymbolUntypedValue :: struct { type: enum { Integer, Float, String, Bool, }, tok: tokenizer.Token, } SymbolMapValue :: struct { key: ^ast.Expr, value: ^ast.Expr, } SymbolMatrixValue :: struct { x: ^ast.Expr, y: ^ast.Expr, expr: ^ast.Expr, } /* Generic symbol that is used by the indexer for any variable type(constants, defined global variables, etc), */ SymbolGenericValue :: struct { expr: ^ast.Expr, } SymbolValue :: union { SymbolStructValue, SymbolPackageValue, SymbolProcedureValue, SymbolGenericValue, SymbolProcedureGroupValue, SymbolUnionValue, SymbolEnumValue, SymbolBitSetValue, SymbolAggregateValue, SymbolDynamicArrayValue, SymbolFixedArrayValue, SymbolMultiPointer, SymbolMapValue, SymbolSliceValue, SymbolBasicValue, SymbolUntypedValue, SymbolMatrixValue, } SymbolFlag :: enum { Distinct, Deprecated, PrivateFile, PrivatePackage, Anonymous, //Usually applied to structs that are defined inline inside another struct Variable, //Symbols that are variable, this means their value decl was mutable Local, ObjC, ObjCIsClassMethod, // should be set true only when ObjC is enabled } 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, } SymbolType :: enum { Function = 3, Field = 5, Variable = 6, Package = 9, Enum = 13, Keyword = 14, EnumMember = 20, Constant = 21, Struct = 22, Type_Function = 23, Union = 7, Unresolved = 1, //Use text if not being able to resolve it. } new_clone_symbol :: proc( data: Symbol, allocator := context.allocator, ) -> ^Symbol { new_symbol := new(Symbol, allocator) new_symbol^ = data new_symbol.value = data.value return new_symbol } free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { if symbol.signature != "" && symbol.signature != "struct" && symbol.signature != "union" && symbol.signature != "enum" && symbol.signature != "bitset" { delete(symbol.signature, allocator) } if symbol.doc != "" { delete(symbol.doc, allocator) } switch v in symbol.value { case SymbolMatrixValue: common.free_ast(v.expr, allocator) common.free_ast(v.x, allocator) common.free_ast(v.y, allocator) case SymbolMultiPointer: common.free_ast(v.expr, allocator) case SymbolProcedureValue: common.free_ast(v.return_types, allocator) common.free_ast(v.arg_types, allocator) case SymbolStructValue: delete(v.names, allocator) common.free_ast(v.types, allocator) case SymbolGenericValue: common.free_ast(v.expr, allocator) case SymbolProcedureGroupValue: common.free_ast(v.group, allocator) case SymbolEnumValue: delete(v.names, allocator) case SymbolUnionValue: common.free_ast(v.types, allocator) case SymbolBitSetValue: common.free_ast(v.expr, allocator) case SymbolDynamicArrayValue: common.free_ast(v.expr, allocator) case SymbolFixedArrayValue: common.free_ast(v.expr, allocator) common.free_ast(v.len, allocator) case SymbolSliceValue: common.free_ast(v.expr, allocator) case SymbolBasicValue: common.free_ast(v.ident, allocator) case SymbolAggregateValue: for symbol in v.symbols { free_symbol(symbol, allocator) } case SymbolMapValue: common.free_ast(v.key, allocator) common.free_ast(v.value, allocator) case SymbolUntypedValue: delete(v.tok.text) case SymbolPackageValue: } } symbol_type_to_completion_kind :: proc( type: SymbolType, ) -> CompletionItemKind { switch type { case .Function: return .Function case .Field: return .Field case .Variable: return .Variable case .Package: return .Module case .Enum: return .Enum case .Keyword: return .Keyword case .EnumMember: return .EnumMember case .Constant: return .Constant case .Struct: return .Struct case .Type_Function: return .Function case .Union: return .Enum case .Unresolved: return .Text case: return .Text } } symbol_kind_to_type :: proc(type: SymbolType) -> SymbolKind { #partial switch type { case .Function: return .Function case .Constant: return .Constant case .Variable: return .Variable case .Union: return .Enum case .Struct: return .Struct case .Enum: return .Enum case .Keyword: return .Key case: return .Null } } symbol_to_expr :: proc( symbol: Symbol, file: string, allocator := context.temp_allocator, ) -> ^ast.Expr { pos := tokenizer.Pos { file = file, } end := tokenizer.Pos { file = file, } #partial switch v in symbol.value { case SymbolDynamicArrayValue: type := new_type(ast.Dynamic_Array_Type, pos, end, allocator) type.elem = v.expr return type case SymbolFixedArrayValue: type := new_type(ast.Array_Type, pos, end, allocator) type.elem = v.expr type.len = v.len return type case SymbolMapValue: type := new_type(ast.Map_Type, pos, end, allocator) type.key = v.key type.value = v.value return type case SymbolBasicValue: return v.ident case SymbolSliceValue: type := new_type(ast.Array_Type, pos, end, allocator) type.elem = v.expr return type case SymbolStructValue: type := new_type(ast.Struct_Type, pos, end, allocator) return type case SymbolUntypedValue: type := new_type(ast.Basic_Lit, pos, end, allocator) return type case SymbolMatrixValue: type := new_type(ast.Matrix_Type, pos, end, allocator) type.row_count = v.x type.column_count = v.y type.elem = v.expr return type case SymbolProcedureValue: type := new_type(ast.Proc_Type, pos, end, allocator) type.results = new_type(ast.Field_List, pos, end, allocator) type.results.list = v.return_types type.params = new_type(ast.Field_List, pos, end, allocator) type.params.list = v.arg_types return type case: return nil } return nil }