aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorDanielGavin <danielgavin5@hotmail.com>2021-03-12 16:31:09 +0100
committerDanielGavin <danielgavin5@hotmail.com>2021-03-12 16:31:09 +0100
commit00ccd7e03e17dac40efb9b34a048d968dd77c218 (patch)
tree24e9e8d9743bc3e98b63183d1f976b11ab6d93d2 /src/server
parentbaf86e02a2c45170d58ab828a13f52361129b255 (diff)
ran odinfmt on project
Diffstat (limited to 'src/server')
-rw-r--r--src/server/action.odin16
-rw-r--r--src/server/analysis.odin4238
-rw-r--r--src/server/background.odin8
-rw-r--r--src/server/completion.odin1253
-rw-r--r--src/server/documents.odin638
-rw-r--r--src/server/format.odin46
-rw-r--r--src/server/hover.odin242
-rw-r--r--src/server/log.odin66
-rw-r--r--src/server/reader.odin68
-rw-r--r--src/server/requests.odin1599
-rw-r--r--src/server/response.odin81
-rw-r--r--src/server/semantic_tokens.odin980
-rw-r--r--src/server/types.odin470
-rw-r--r--src/server/unmarshal.odin281
-rw-r--r--src/server/workspace.odin2
-rw-r--r--src/server/writer.odin38
16 files changed, 4765 insertions, 5261 deletions
diff --git a/src/server/action.odin b/src/server/action.odin
index f0b97ed..44b3458 100644
--- a/src/server/action.odin
+++ b/src/server/action.odin
@@ -1,22 +1,16 @@
package server
-CodeActionKind :: struct {
-
-};
+CodeActionKind :: struct {}
CodeActionClientCapabilities :: struct {
-
codeActionLiteralSupport: struct {
-
codeActionKind: struct {
- valueSet: [] CodeActionKind,
+ valueSet: []CodeActionKind,
},
},
-
-};
+}
CodeActionOptions :: struct {
- codeActionKinds: [] CodeActionKind,
+ codeActionKinds: []CodeActionKind,
resolveProvider: bool,
-};
-
+} \ No newline at end of file
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index d9b9dc2..8dc4509 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -18,2701 +18,2479 @@ import "shared:common"
import "shared:index"
/*
- TODO(replace all of the possible ast walking with the new odin visitor function)
- TODO(improve the current_package logic, kinda confusing switching between different packages with selectors)
+ TODO(replace all of the possible ast walking with the new odin visitor function)
+ TODO(improve the current_package logic, kinda confusing switching between different packages with selectors)
*/
-bool_lit := "bool";
-int_lit := "int";
+bool_lit := "bool";
+int_lit := "int";
string_lit := "string";
DocumentPositionContextHint :: enum {
- Completion,
- SignatureHelp,
- Definition,
- Hover,
-};
+ Completion,
+ SignatureHelp,
+ Definition,
+ Hover,
+}
DocumentPositionContext :: struct {
- file: ast.File,
- position: common.AbsolutePosition,
- line: int,
- function: ^ast.Proc_Lit, //used to help with type resolving in function scope
- selector: ^ast.Expr, //used for completion
- identifier: ^ast.Node,
- 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
- implicit: bool, //used for completion
- arrow: bool,
- 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
- hint: DocumentPositionContextHint,
-};
+ file: ast.File,
+ position: common.AbsolutePosition,
+ line: int,
+ function: ^ast.Proc_Lit, //used to help with type resolving in function scope
+ selector: ^ast.Expr, //used for completion
+ identifier: ^ast.Node,
+ 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
+ implicit: bool, //used for completion
+ arrow: bool,
+ 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
+ hint: DocumentPositionContextHint,
+}
DocumentLocal :: struct {
- expr: ^ast.Expr,
- offset: int,
+ expr: ^ast.Expr,
+ offset: int,
}
AstContext :: struct {
- locals: map [string] [dynamic] DocumentLocal, //locals all the way to the document position
- globals: map [string] ^ast.Expr,
- variables: map [string] bool,
- parameters: map [string] bool,
- in_package: map[string] string, //sometimes you have to extract types from arrays/maps and you lose package information
- usings: [dynamic] string,
- file: ast.File,
- allocator: mem.Allocator,
- imports: [] Package, //imports for the current document
- current_package: string,
- document_package: string,
- use_globals: bool,
- use_locals: bool,
- 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,
- field_name: string,
-};
-
-make_ast_context :: proc(file: ast.File, imports: [] Package, package_name: string, allocator := context.temp_allocator) -> AstContext {
-
- ast_context := AstContext {
- locals = make(map [string] [dynamic] DocumentLocal, 0, allocator),
- globals = make(map [string] ^ast.Expr, 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,
- };
- return ast_context;
+ locals: map[string][dynamic]DocumentLocal, //locals all the way to the document position
+ globals: map[string]^ast.Expr,
+ variables: map[string]bool,
+ parameters: map[string]bool,
+ in_package: map[string]string, //sometimes you have to extract types from arrays/maps and you lose package information
+ usings: [dynamic]string,
+ file: ast.File,
+ allocator: mem.Allocator,
+ imports: []Package, //imports for the current document
+ current_package: string,
+ document_package: string,
+ use_globals: bool,
+ use_locals: bool,
+ 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,
+ field_name: string,
}
-tokenizer_error_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) {
+make_ast_context :: proc (file: ast.File, imports: []Package, package_name: string, allocator := context.temp_allocator) -> AstContext {
+
+ ast_context := AstContext {
+ locals = make(map[string][dynamic]DocumentLocal, 0, allocator),
+ globals = make(map[string]^ast.Expr, 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,
+ };
+ return ast_context;
+}
+tokenizer_error_handler :: proc (pos: tokenizer.Pos, msg: string, args: ..any) {
}
/*
- Walk through the type expression while both the call expression and specialization type are the same
- */
+ Walk through the type expression while both the call expression and specialization type are the same
+*/
resolve_poly_spec :: proc {
- resolve_poly_spec_node,
- resolve_poly_spec_array,
- resolve_poly_spec_dynamic_array,
-};
+resolve_poly_spec_node,
+resolve_poly_spec_array,
+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;
- }
-
- for elem, i in call_array {
- resolve_poly_spec(ast_context, elem, spec_array[i], poly_map);
- }
+ if len(call_array) != len(spec_array) {
+ return;
+ }
+ for elem, i in call_array {
+ resolve_poly_spec(ast_context, elem, spec_array[i], poly_map);
+ }
}
-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;
- }
-
- for elem, i in call_array {
- resolve_poly_spec(ast_context, elem, spec_array[i], poly_map);
- }
+ if len(call_array) != len(spec_array) {
+ return;
+ }
+ for elem, i in call_array {
+ resolve_poly_spec(ast_context, elem, spec_array[i], poly_map);
+ }
}
-get_poly_node_to_expr :: proc(node: ^ast.Node) -> ^ast.Expr {
-
- using ast;
+get_poly_node_to_expr :: proc (node: ^ast.Node) -> ^ast.Expr {
- switch v in node.derived {
- case Ident:
- return cast(^Expr)node;
- case:
- log.warnf("Unhandled poly to node kind %v", v);
- }
+ using ast;
- return nil;
-}
-
-resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, spec_node: ^ast.Node, poly_map: ^map[string]^ast.Expr) {
-
- /*
- Note(Daniel, uncertain about the switch cases being enough or too little)
- */
-
- using ast;
-
- if call_node == nil || spec_node == nil {
- return;
- }
-
- switch m in spec_node.derived {
- case Bad_Expr:
- case Ident:
- case Implicit:
- case Undef:
- case Basic_Lit:
- case Poly_Type:
- if expr := get_poly_node_to_expr(call_node); expr != nil {
- poly_map[m.type.name] = expr;
- }
- case Ellipsis:
- if n, ok := call_node.derived.(Ellipsis); ok {
- resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
- }
- case Tag_Expr:
- if n, ok := call_node.derived.(Tag_Expr); ok {
- resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
- }
- case Unary_Expr:
- if n, ok := call_node.derived.(Unary_Expr); ok {
- resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
- }
- case Binary_Expr:
- if n, ok := call_node.derived.(Binary_Expr); ok {
- resolve_poly_spec(ast_context, n.left, m.left, poly_map);
- resolve_poly_spec(ast_context, n.right, m.right, poly_map);
- }
- case Paren_Expr:
- if n, ok := call_node.derived.(Paren_Expr); ok {
- resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
- }
- case Selector_Expr:
- if n, ok := call_node.derived.(Selector_Expr); ok {
- resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
- resolve_poly_spec(ast_context, n.field, m.field, poly_map);
- }
- case Slice_Expr:
- if n, ok := call_node.derived.(Slice_Expr); ok {
- resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
- resolve_poly_spec(ast_context, n.low, m.low, poly_map);
- resolve_poly_spec(ast_context, n.high, m.high, poly_map);
- }
- case Distinct_Type:
- if n, ok := call_node.derived.(Distinct_Type); ok {
- resolve_poly_spec(ast_context, n.type, m.type, poly_map);
- }
- case Proc_Type:
- if n, ok := call_node.derived.(Proc_Type); ok {
- resolve_poly_spec(ast_context, n.params, m.params, poly_map);
- resolve_poly_spec(ast_context, n.results, m.results, poly_map);
- }
- case Pointer_Type:
- if n, ok := call_node.derived.(Pointer_Type); ok {
- resolve_poly_spec(ast_context, n.elem, m.elem, poly_map);
- }
- case Array_Type:
- if n, ok := call_node.derived.(Array_Type); ok {
- resolve_poly_spec(ast_context, n.len, m.len, poly_map);
- resolve_poly_spec(ast_context, n.elem, m.elem, poly_map);
- }
- case Dynamic_Array_Type:
- if n, ok := call_node.derived.(Dynamic_Array_Type); ok {
- resolve_poly_spec(ast_context, n.elem, m.elem, poly_map);
- }
- 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.align, m.align, poly_map);
- resolve_poly_spec(ast_context, n.fields, m.fields, poly_map);
- }
- case Field:
- 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);
- }
- case Field_List:
- if n, ok := call_node.derived.(Field_List); ok {
- resolve_poly_spec(ast_context, n.list, m.list, poly_map);
- }
- case Field_Value:
- if n, ok := call_node.derived.(Field_Value); ok {
- resolve_poly_spec(ast_context, n.field, m.field, poly_map);
- resolve_poly_spec(ast_context, n.value, m.value, poly_map);
- }
- 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.align, m.align, poly_map);
- resolve_poly_spec(ast_context, n.variants, m.variants, poly_map);
- }
- case Enum_Type:
- if n, ok := call_node.derived.(Enum_Type); ok {
- resolve_poly_spec(ast_context, n.base_type, m.base_type, poly_map);
- resolve_poly_spec(ast_context, n.fields, m.fields, poly_map);
- }
- 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);
- }
- case Map_Type:
- if n, ok := call_node.derived.(Map_Type); ok {
- resolve_poly_spec(ast_context, n.key, m.key, poly_map);
- resolve_poly_spec(ast_context, n.value, m.value, poly_map);
- }
- case Call_Expr:
- if n, ok := call_node.derived.(Call_Expr); ok {
- resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
- resolve_poly_spec(ast_context, n.args, m.args, poly_map);
- }
- case Typeid_Type:
- if n, ok := call_node.derived.(Typeid_Type); ok {
- resolve_poly_spec(ast_context, n.specialization, m.specialization, poly_map);
- }
- case:
- log.error("Unhandled poly node kind: %T", m);
- }
+ switch v in node.derived {
+ case Ident:
+ return cast(^Expr)node;
+ case:
+ log.warnf("Unhandled poly to node kind %v", v);
+ }
+ return nil;
}
-resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, current_symbol: index.Symbol, current_comp_lit: ^ast.Comp_Lit) -> (index.Symbol, bool) {
-
- if position_context.comp_lit == current_comp_lit {
- return current_symbol, true;
- }
+resolve_poly_spec_node :: proc (ast_context: ^AstContext, call_node: ^ast.Node, spec_node: ^ast.Node, poly_map: ^map[string]^ast.Expr) {
- for elem in current_comp_lit.elems {
+ /*
+ Note(Daniel, uncertain about the switch cases being enough or too little)
+ */
- if !position_in_node(elem, position_context.position) {
- continue;
- }
+ using ast;
- if field_value, ok := elem.derived.(ast.Field_Value); ok {
+ if call_node == nil || spec_node == nil {
+ return;
+ }
- if comp_lit, ok := field_value.value.derived.(ast.Comp_Lit); ok {
+ switch m in spec_node.derived {
+ case Bad_Expr:
+ case Ident:
+ case Implicit:
+ case Undef:
+ case Basic_Lit:
+ case Poly_Type:
+ if expr := get_poly_node_to_expr(call_node); expr != nil {
+ poly_map[m.type.name] = expr;
+ }
+ case Ellipsis:
+ if n, ok := call_node.derived.(Ellipsis); ok {
+ resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
+ }
+ case Tag_Expr:
+ if n, ok := call_node.derived.(Tag_Expr); ok {
+ resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
+ }
+ case Unary_Expr:
+ if n, ok := call_node.derived.(Unary_Expr); ok {
+ resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
+ }
+ case Binary_Expr:
+ if n, ok := call_node.derived.(Binary_Expr); ok {
+ resolve_poly_spec(ast_context, n.left, m.left, poly_map);
+ resolve_poly_spec(ast_context, n.right, m.right, poly_map);
+ }
+ case Paren_Expr:
+ if n, ok := call_node.derived.(Paren_Expr); ok {
+ resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
+ }
+ case Selector_Expr:
+ if n, ok := call_node.derived.(Selector_Expr); ok {
+ resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
+ resolve_poly_spec(ast_context, n.field, m.field, poly_map);
+ }
+ case Slice_Expr:
+ if n, ok := call_node.derived.(Slice_Expr); ok {
+ resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
+ resolve_poly_spec(ast_context, n.low, m.low, poly_map);
+ resolve_poly_spec(ast_context, n.high, m.high, poly_map);
+ }
+ case Distinct_Type:
+ if n, ok := call_node.derived.(Distinct_Type); ok {
+ resolve_poly_spec(ast_context, n.type, m.type, poly_map);
+ }
+ case Proc_Type:
+ if n, ok := call_node.derived.(Proc_Type); ok {
+ resolve_poly_spec(ast_context, n.params, m.params, poly_map);
+ resolve_poly_spec(ast_context, n.results, m.results, poly_map);
+ }
+ case Pointer_Type:
+ if n, ok := call_node.derived.(Pointer_Type); ok {
+ resolve_poly_spec(ast_context, n.elem, m.elem, poly_map);
+ }
+ case Array_Type:
+ if n, ok := call_node.derived.(Array_Type); ok {
+ resolve_poly_spec(ast_context, n.len, m.len, poly_map);
+ resolve_poly_spec(ast_context, n.elem, m.elem, poly_map);
+ }
+ case Dynamic_Array_Type:
+ if n, ok := call_node.derived.(Dynamic_Array_Type); ok {
+ resolve_poly_spec(ast_context, n.elem, m.elem, poly_map);
+ }
+ 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.align, m.align, poly_map);
+ resolve_poly_spec(ast_context, n.fields, m.fields, poly_map);
+ }
+ case Field:
+ 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);
+ }
+ case Field_List:
+ if n, ok := call_node.derived.(Field_List); ok {
+ resolve_poly_spec(ast_context, n.list, m.list, poly_map);
+ }
+ case Field_Value:
+ if n, ok := call_node.derived.(Field_Value); ok {
+ resolve_poly_spec(ast_context, n.field, m.field, poly_map);
+ resolve_poly_spec(ast_context, n.value, m.value, poly_map);
+ }
+ 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.align, m.align, poly_map);
+ resolve_poly_spec(ast_context, n.variants, m.variants, poly_map);
+ }
+ case Enum_Type:
+ if n, ok := call_node.derived.(Enum_Type); ok {
+ resolve_poly_spec(ast_context, n.base_type, m.base_type, poly_map);
+ resolve_poly_spec(ast_context, n.fields, m.fields, poly_map);
+ }
+ 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);
+ }
+ case Map_Type:
+ if n, ok := call_node.derived.(Map_Type); ok {
+ resolve_poly_spec(ast_context, n.key, m.key, poly_map);
+ resolve_poly_spec(ast_context, n.value, m.value, poly_map);
+ }
+ case Call_Expr:
+ if n, ok := call_node.derived.(Call_Expr); ok {
+ resolve_poly_spec(ast_context, n.expr, m.expr, poly_map);
+ resolve_poly_spec(ast_context, n.args, m.args, poly_map);
+ }
+ case Typeid_Type:
+ if n, ok := call_node.derived.(Typeid_Type); ok {
+ resolve_poly_spec(ast_context, n.specialization, m.specialization, poly_map);
+ }
+ case:
+ log.error("Unhandled poly node kind: %T", m);
+ }
+}
- if s, ok := current_symbol.value.(index.SymbolStructValue); ok {
+resolve_type_comp_literal :: proc (ast_context: ^AstContext, position_context: ^DocumentPositionContext, current_symbol: index.Symbol, current_comp_lit: ^ast.Comp_Lit) -> (index.Symbol, bool) {
- for name, i in s.names {
+ if position_context.comp_lit == current_comp_lit {
+ return current_symbol, true;
+ }
- if name == field_value.field.derived.(ast.Ident).name {
+ for elem in current_comp_lit.elems {
- if symbol, ok := resolve_type_expression(ast_context, s.types[i]); ok {
- return resolve_type_comp_literal(ast_context, position_context, symbol, cast(^ast.Comp_Lit)field_value.value);
- }
+ if !position_in_node(elem, position_context.position) {
+ continue;
+ }
- }
+ if field_value, ok := elem.derived.(ast.Field_Value); ok {
- }
+ if comp_lit, ok := field_value.value.derived.(ast.Comp_Lit); ok {
- }
+ if s, ok := current_symbol.value.(index.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 {
+ return resolve_type_comp_literal(ast_context, position_context, symbol, cast(^ast.Comp_Lit)field_value.value);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
- return current_symbol, true;
+ return current_symbol, true;
}
resolve_generic_function :: proc {
- resolve_generic_function_ast,
- resolve_generic_function_symbol,
-};
-
-resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast.Field, results: []^ast.Field) -> (index.Symbol, bool) {
- using ast;
-
- if params == nil {
- return index.Symbol {}, false;
- }
-
- if results == nil {
- return index.Symbol {}, false;
- }
-
- if ast_context.call == nil {
- return index.Symbol {}, false;
- }
-
- call_expr := ast_context.call;
- poly_map := make(map[string]^Expr, 0, context.temp_allocator);
- i := 0;
-
+resolve_generic_function_ast,
+resolve_generic_function_symbol};
- for param in params {
+resolve_generic_function_symbol :: proc (ast_context: ^AstContext, params: []^ast.Field, results: []^ast.Field) -> (index.Symbol, bool) {
+ using ast;
- for name in param.names {
-
- if len(call_expr.args) <= i {
- break;
- }
-
- if poly, ok := name.derived.(Poly_Type); ok {
- poly_map[poly.type.name] = call_expr.args[i];
- }
-
- if param.type == nil {
- continue;
- }
-
- if poly, ok := param.type.derived.(Poly_Type); ok {
-
- if arg_eval, ok := resolve_type_expression(ast_context, call_expr.args[i]); ok {
+ if params == nil {
+ return index.Symbol {}, false;
+ }
- if value, ok := arg_eval.value.(index.SymbolGenericValue); ok {
- resolve_poly_spec_node(ast_context, value.expr, poly.specialization, &poly_map);
- }
+ if results == nil {
+ return index.Symbol {}, false;
+ }
- }
- }
+ if ast_context.call == nil {
+ return index.Symbol {}, false;
+ }
- i += 1;
- }
+ call_expr := ast_context.call;
+ poly_map := make(map[string]^Expr, 0, context.temp_allocator);
+ i := 0;
- }
+ for param in params {
- function_name := "";
- function_range: common.Range;
+ for name in param.names {
- if ident, ok := call_expr.expr.derived.(Ident); ok {
- function_name = ident.name;
- function_range = common.get_token_range(ident, ast_context.file.src);
- }
+ if len(call_expr.args) <= i {
+ break;
+ }
- else if selector, ok := call_expr.expr.derived.(Selector_Expr); ok {
- function_name = selector.field.name;
- function_range = common.get_token_range(selector, ast_context.file.src);
- }
+ if poly, ok := name.derived.(Poly_Type); ok {
+ poly_map[poly.type.name] = call_expr.args[i];
+ }
- else {
- log.debug("call expr expr could not be derived correctly");
- return index.Symbol {}, false;
- }
+ if param.type == nil {
+ continue;
+ }
- symbol := index.Symbol {
- range = function_range,
- type = .Function,
- name = function_name,
- };
+ if poly, ok := param.type.derived.(Poly_Type); ok {
- return_types := make([dynamic] ^ast.Field, context.temp_allocator);
+ if arg_eval, ok := resolve_type_expression(ast_context, call_expr.args[i]); ok {
- for result in results {
+ if value, ok := arg_eval.value.(index.SymbolGenericValue); ok {
+ resolve_poly_spec_node(ast_context, value.expr, poly.specialization, &poly_map);
+ }
+ }
+ }
- if result.type == nil {
- continue;
- }
+ i += 1;
+ }
+ }
- if ident, ok := result.type.derived.(Ident); ok {
- field := cast(^Field)index.clone_node(result, context.temp_allocator, nil);
+ function_name := "";
+ function_range: common.Range;
+
+ if ident, ok := call_expr.expr.derived.(Ident); ok {
+ function_name = ident.name;
+ function_range = common.get_token_range(ident, ast_context.file.src);
+ } else if selector, ok := call_expr.expr.derived.(Selector_Expr); ok {
+ function_name = selector.field.name;
+ function_range = common.get_token_range(selector, ast_context.file.src);
+ } else {
+ log.debug("call expr expr could not be derived correctly");
+ return index.Symbol {}, false;
+ }
- if m := &poly_map[ident.name]; m != nil {
- field.type = poly_map[ident.name];
- append(&return_types, field);
- }
+ symbol := index.Symbol {
+ range = function_range,
+ type = .Function,
+ name = function_name,
+ };
- else{
- return index.Symbol {}, false;
- }
+ return_types := make([dynamic]^ast.Field, context.temp_allocator);
- }
+ for result in results {
- }
+ if result.type == nil {
+ continue;
+ }
+ if ident, ok := result.type.derived.(Ident); ok {
+ field := cast(^Field)index.clone_node(result, context.temp_allocator, nil);
- symbol.value = index.SymbolProcedureValue {
- return_types = return_types[:],
- arg_types = params,
- };
+ if m := &poly_map[ident.name]; m != nil {
+ field.type = poly_map[ident.name];
+ append(&return_types, field);
+ } else {
+ return index.Symbol {}, false;
+ }
+ }
+ }
+ symbol.value = index.SymbolProcedureValue {
+ return_types = return_types[:],
+ arg_types = params,
+ };
- //log.infof("return %v", poly_map);
+ //log.infof("return %v", poly_map);
- return symbol, true;
+ return symbol, true;
}
-resolve_generic_function_ast :: proc(ast_context: ^AstContext, proc_lit: ast.Proc_Lit) -> (index.Symbol, bool) {
+resolve_generic_function_ast :: proc (ast_context: ^AstContext, proc_lit: ast.Proc_Lit) -> (index.Symbol, bool) {
- using ast;
+ using ast;
- if proc_lit.type.params == nil {
- return index.Symbol {}, false;
- }
+ if proc_lit.type.params == nil {
+ return index.Symbol {}, false;
+ }
- if proc_lit.type.results == nil {
- return index.Symbol {}, false;
- }
+ if proc_lit.type.results == nil {
+ return index.Symbol {}, false;
+ }
- if ast_context.call == nil {
- return index.Symbol {}, false;
- }
+ if ast_context.call == nil {
+ return index.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);
}
-
/*
- 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) -> (index.Symbol, bool) {
-
- using ast;
-
- //log.info("overload");
-
- if ast_context.call == nil {
- //log.info("no call");
- return index.Symbol {}, false;
- }
-
- call_expr := ast_context.call;
-
- for arg_expr in group.args {
+ 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) -> (index.Symbol, bool) {
- next_fn: if f, ok := resolve_type_expression(ast_context, arg_expr); ok {
+ using ast;
- if procedure, ok := f.value.(index.SymbolProcedureValue); ok {
+ //log.info("overload");
- if len(procedure.arg_types) < len(call_expr.args) {
- continue;
- }
+ if ast_context.call == nil {
+ //log.info("no call");
+ return index.Symbol {}, false;
+ }
- for arg, i in call_expr.args {
+ call_expr := ast_context.call;
- if eval_call_expr, ok := resolve_type_expression(ast_context, arg); ok {
+ for arg_expr in group.args {
- #partial switch v in eval_call_expr.value {
- case index.SymbolProcedureValue:
- case index.SymbolGenericValue:
- if !common.node_equal(v.expr, procedure.arg_types[i].type) {
- break next_fn;
- }
- case index.SymbolStructValue:
- }
+ next_fn: if f, ok := resolve_type_expression(ast_context, arg_expr); ok {
- }
+ if procedure, ok := f.value.(index.SymbolProcedureValue); ok {
- else {
- //log.debug("Failed to resolve call expr");
- return index.Symbol {}, false;
- }
- }
+ if len(procedure.arg_types) < len(call_expr.args) {
+ continue;
+ }
- //log.debugf("return overload %v", f);
- return f, true;
- }
+ for arg, i in call_expr.args {
- }
+ if eval_call_expr, ok := resolve_type_expression(ast_context, arg); ok {
- }
+ #partial switch v in eval_call_expr.value {
+ case index.SymbolProcedureValue:
+ case index.SymbolGenericValue:
+ if !common.node_equal(v.expr, procedure.arg_types[i].type) {
+ break next_fn;
+ }
+ case index.SymbolStructValue:
+ }
+ } else {
+ //log.debug("Failed to resolve call expr");
+ return index.Symbol {}, false;
+ }
+ }
+ //log.debugf("return overload %v", f);
+ return f, true;
+ }
+ }
+ }
- return index.Symbol {}, false;
+ return index.Symbol {}, false;
}
-resolve_basic_lit :: proc(ast_context: ^AstContext, basic_lit: ast.Basic_Lit) -> (index.Symbol, bool) {
+resolve_basic_lit :: proc (ast_context: ^AstContext, basic_lit: ast.Basic_Lit) -> (index.Symbol, bool) {
- /*
- This is temporary, since basic lit is untyped, but either way it's going to be an ident representing a keyword.
+ /*
+ This is temporary, since basic lit is untyped, but either way it's going to be an ident representing a keyword.
- Could perhaps name them "$integer", "$float", etc.
- */
+ Could perhaps name them "$integer", "$float", etc.
+ */
- ident := index.new_type(ast.Ident, basic_lit.pos, basic_lit.end, context.temp_allocator);
+ ident := index.new_type(ast.Ident, basic_lit.pos, basic_lit.end, context.temp_allocator);
- symbol := index.Symbol {
- type = .Keyword,
- };
-
- if v, ok := strconv.parse_bool(basic_lit.tok.text); ok {
- ident.name = bool_lit;
- }
-
- else if v, ok := strconv.parse_int(basic_lit.tok.text); ok {
- ident.name = int_lit;
- }
-
- else {
- ident.name = string_lit;
- }
+ symbol := index.Symbol {
+ type = .Keyword
+ };
- symbol.value = index.SymbolGenericValue {
- expr = ident,
- };
+ if v, ok := strconv.parse_bool(basic_lit.tok.text); ok {
+ ident.name = bool_lit;
+ } else if v, ok := strconv.parse_int(basic_lit.tok.text); ok {
+ ident.name = int_lit;
+ } else {
+ ident.name = string_lit;
+ }
- return symbol, true;
-}
+ symbol.value = index.SymbolGenericValue {
+ expr = ident
+ };
-resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (index.Symbol, bool) {
-
- if node == nil {
- return {}, false;
- }
-
- using ast;
-
- switch v in node.derived {
- case Proc_Type:
- return make_symbol_procedure_from_ast(ast_context, node, v, ast_context.field_name), true;
- 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);
- case Auto_Cast:
- return resolve_type_expression(ast_context, v.expr);
- case Unary_Expr:
- if v.op.kind == .And {
- return resolve_type_expression(ast_context, make_pointer_ast(v.expr));
- }
-
- else {
- return resolve_type_expression(ast_context, v.expr);
- }
- case Deref_Expr:
- return resolve_type_expression(ast_context, v.expr);
- case Paren_Expr:
- return resolve_type_expression(ast_context, v.expr);
- case Slice_Expr:
- return resolve_type_expression(ast_context, v.expr);
- case Tag_Expr:
- return resolve_type_expression(ast_context, v.expr);
- case Helper_Type:
- return resolve_type_expression(ast_context, v.type);
- case Ellipsis:
- return resolve_type_expression(ast_context, v.expr);
- case Implicit:
- ident := index.new_type(Ident, v.node.pos, v.node.end, context.temp_allocator);
- ident.name = v.tok.text;
- return resolve_type_identifier(ast_context, ident^);
- case Type_Assertion:
- 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);
- }
- }
- case Pointer_Type:
-
- /*
- Add flag to not pull out a type from a pointer for function overloading.
- */
-
- if v2, ok := v.elem.derived.(ast.Pointer_Type); !ok {
- return resolve_type_expression(ast_context, v.elem);
- }
-
- else if v2, ok := v.elem.derived.(ast.Type_Assertion); !ok {
- return resolve_type_expression(ast_context, v.elem);
- }
-
- else {
- return make_symbol_generic_from_ast(ast_context, node), true;
- }
-
- case Index_Expr:
- indexed, ok := resolve_type_expression(ast_context, v.expr);
-
- if generic, ok := indexed.value.(index.SymbolGenericValue); ok {
-
- switch c in generic.expr.derived {
- case Array_Type:
- return resolve_type_expression(ast_context, c.elem);
- case Dynamic_Array_Type:
- return resolve_type_expression(ast_context, c.elem);
- case Map_Type:
- return resolve_type_expression(ast_context, c.value);
- }
-
- }
-
- return index.Symbol {}, false;
- case Call_Expr:
- ast_context.call = cast(^Call_Expr)node;
- return resolve_type_expression(ast_context, v.expr);
- case Implicit_Selector_Expr:
- return index.Symbol {}, false;
- case Selector_Call_Expr:
- return resolve_type_expression(ast_context, v.expr);
- case Selector_Expr:
-
- if selector, ok := resolve_type_expression(ast_context, v.expr); ok {
-
- ast_context.use_locals = false;
-
- #partial switch s in selector.value {
- case index.SymbolProcedureValue:
-
- if len(s.return_types) == 1 {
- selector_expr := index.new_type(ast.Selector_Expr, s.return_types[0].node.pos, s.return_types[0].node.end, context.temp_allocator);
- selector_expr.expr = s.return_types[0].type;
- selector_expr.field = v.field;
- return resolve_type_expression(ast_context, selector_expr);
- }
- case index.SymbolStructValue:
- if selector.pkg != "" {
- ast_context.current_package = selector.pkg;
- }
-
- else {
- ast_context.current_package = ast_context.document_package;
- }
-
- for name, i in s.names {
- if v.field != nil && name == v.field.name {
- ast_context.field_name = v.field.name;
- return resolve_type_expression(ast_context, s.types[i]);
- }
- }
- case index.SymbolPackageValue:
-
- ast_context.current_package = selector.pkg;
-
- if v.field != nil {
- return resolve_symbol_return(ast_context, index.lookup(v.field.name, selector.pkg));
- }
-
- else {
- return index.Symbol {}, false;
- }
- }
- }
-
- else {
- return index.Symbol {}, false;
- }
- case:
- log.warnf("default node kind, resolve_type_expression: %T", v);
-
- if v == nil {
- return {}, false;
- }
-
- return make_symbol_generic_from_ast(ast_context, node), true;
- }
-
- return index.Symbol {}, false;
+ return symbol, true;
}
-store_local :: proc(ast_context: ^AstContext, expr: ^ast.Expr, offset: int, name: string) {
+resolve_type_expression :: proc (ast_context: ^AstContext, node: ^ast.Expr) -> (index.Symbol, bool) {
- local_stack := &ast_context.locals[name];
+ if node == nil {
+ return {}, false;
+ }
- if local_stack == nil {
- ast_context.locals[name] = make([dynamic] DocumentLocal, context.temp_allocator);
- local_stack = &ast_context.locals[name];
- }
+ using ast;
+
+ switch v in node.derived {
+ case Proc_Type:
+ return make_symbol_procedure_from_ast(ast_context, node, v, ast_context.field_name), true;
+ 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);
+ case Auto_Cast:
+ return resolve_type_expression(ast_context, v.expr);
+ case Unary_Expr:
+ if v.op.kind == .And {
+ return resolve_type_expression(ast_context, make_pointer_ast(v.expr));
+ } else {
+ return resolve_type_expression(ast_context, v.expr);
+ }
+ case Deref_Expr:
+ return resolve_type_expression(ast_context, v.expr);
+ case Paren_Expr:
+ return resolve_type_expression(ast_context, v.expr);
+ case Slice_Expr:
+ return resolve_type_expression(ast_context, v.expr);
+ case Tag_Expr:
+ return resolve_type_expression(ast_context, v.expr);
+ case Helper_Type:
+ return resolve_type_expression(ast_context, v.type);
+ case Ellipsis:
+ return resolve_type_expression(ast_context, v.expr);
+ case Implicit:
+ ident := index.new_type(Ident, v.node.pos, v.node.end, context.temp_allocator);
+ ident.name = v.tok.text;
+ return resolve_type_identifier(ast_context, ident^);
+ case Type_Assertion:
+ 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);
+ }
+ }
+ case Pointer_Type:
+
+ /*
+ Add flag to not pull out a type from a pointer for function overloading.
+ */
+
+ if v2, ok := v.elem.derived.(ast.Pointer_Type); !ok {
+ return resolve_type_expression(ast_context, v.elem);
+ } else if v2, ok := v.elem.derived.(ast.Type_Assertion); !ok {
+ return resolve_type_expression(ast_context, v.elem);
+ } else {
+ return make_symbol_generic_from_ast(ast_context, node), true;
+ }
+
+ case Index_Expr:
+ indexed, ok := resolve_type_expression(ast_context, v.expr);
+
+ if generic, ok := indexed.value.(index.SymbolGenericValue); ok {
+
+ switch c in generic.expr.derived {
+ case Array_Type:
+ return resolve_type_expression(ast_context, c.elem);
+ case Dynamic_Array_Type:
+ return resolve_type_expression(ast_context, c.elem);
+ case Map_Type:
+ return resolve_type_expression(ast_context, c.value);
+ }
+ }
+
+ return index.Symbol {}, false;
+ case Call_Expr:
+ ast_context.call = cast(^Call_Expr)node;
+ return resolve_type_expression(ast_context, v.expr);
+ case Implicit_Selector_Expr:
+ return index.Symbol {}, false;
+ case Selector_Call_Expr:
+ return resolve_type_expression(ast_context, v.expr);
+ case Selector_Expr:
+
+ if selector, ok := resolve_type_expression(ast_context, v.expr); ok {
+
+ ast_context.use_locals = false;
+
+ #partial switch s in selector.value {
+ case index.SymbolProcedureValue:
+
+ if len(s.return_types) == 1 {
+ selector_expr := index.new_type(ast.Selector_Expr, s.return_types[0].node.pos, s.return_types[0].node.end, context.temp_allocator);
+ selector_expr.expr = s.return_types[0].type;
+ selector_expr.field = v.field;
+ return resolve_type_expression(ast_context, selector_expr);
+ }
+ case index.SymbolStructValue:
+ if selector.pkg != "" {
+ ast_context.current_package = selector.pkg;
+ } else {
+ ast_context.current_package = ast_context.document_package;
+ }
+
+ for name, i in s.names {
+ if v.field != nil && name == v.field.name {
+ ast_context.field_name = v.field.name;
+ return resolve_type_expression(ast_context, s.types[i]);
+ }
+ }
+ case index.SymbolPackageValue:
+
+ ast_context.current_package = selector.pkg;
+
+ if v.field != nil {
+ return resolve_symbol_return(ast_context, index.lookup(v.field.name, selector.pkg));
+ } else {
+ return index.Symbol {}, false;
+ }
+ }
+ } else {
+ return index.Symbol {}, false;
+ }
+ case:
+ log.warnf("default node kind, resolve_type_expression: %T", v);
+
+ if v == nil {
+ return {}, false;
+ }
+
+ return make_symbol_generic_from_ast(ast_context, node), true;
+ }
- append(local_stack, DocumentLocal { expr = expr, offset = offset });
+ return index.Symbol {}, false;
}
-get_local :: proc(ast_context: ^AstContext, offset: int, name: string) -> ^ast.Expr {
-
- previous := 0;
+store_local :: proc (ast_context: ^AstContext, expr: ^ast.Expr, offset: int, name: string) {
- //is the local we are getting being declared?
- if ast_context.value_decl != nil {
+ local_stack := &ast_context.locals[name];
- for value_decl_name in ast_context.value_decl.names {
+ if local_stack == nil {
+ ast_context.locals[name] = make([dynamic]DocumentLocal, context.temp_allocator);
+ local_stack = &ast_context.locals[name];
+ }
- if ident, ok := value_decl_name.derived.(ast.Ident); ok {
+ append(local_stack, DocumentLocal {expr = expr, offset = offset});
+}
- if ident.name == name {
- previous = 1;
- break;
- }
- }
+get_local :: proc (ast_context: ^AstContext, offset: int, name: string) -> ^ast.Expr {
- }
+ previous := 0;
+ //is the local we are getting being declared?
+ if ast_context.value_decl != nil {
- }
+ for value_decl_name in ast_context.value_decl.names {
- if local_stack, ok := ast_context.locals[name]; ok {
+ if ident, ok := value_decl_name.derived.(ast.Ident); ok {
- for i := len(local_stack)-1; i >= 0; i -= 1 {
+ if ident.name == name {
+ previous = 1;
+ break;
+ }
+ }
+ }
+ }
- if local_stack[i].offset <= offset {
- return local_stack[max(0, i - previous)].expr;
- }
+ if local_stack, ok := ast_context.locals[name]; ok {
- }
+ for i := len(local_stack) - 1; i >= 0; i -= 1 {
- }
+ if local_stack[i].offset <= offset {
+ return local_stack[max(0, i - previous)].expr;
+ }
+ }
+ }
- return nil;
+ return nil;
}
/*
- Function recusively goes through the identifier until it hits a struct, enum, procedure literals, since you can
- have chained variable declarations. ie. a := foo { test = 2}; b := a; c := b;
- */
-resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (index.Symbol, bool) {
-
- using ast;
-
- if pkg, ok := ast_context.in_package[node.name]; ok {
- ast_context.current_package = pkg;
- }
-
- if _, ok := ast_context.parameters[node.name]; ok {
- for imp in ast_context.imports {
-
- if strings.compare(imp.base, node.name) == 0 {
-
- symbol := index.Symbol {
- type = .Package,
- pkg = imp.name,
- value = index.SymbolPackageValue {
- }
- };
-
- return symbol, true;
- }
-
- }
- }
-
- //note(Daniel, if global and local ends up being 100% same just make a function that takes the map)
- if local := get_local(ast_context, node.pos.offset, node.name); local != nil && ast_context.use_locals {
-
- switch v in local.derived {
- case Ident:
-
- if node.name == v.name {
- break;
- }
-
- return resolve_type_identifier(ast_context, v);
- case Union_Type:
- return make_symbol_union_from_ast(ast_context, v, node), true;
- case Enum_Type:
- return make_symbol_enum_from_ast(ast_context, v, node), true;
- case Struct_Type:
- return make_symbol_struct_from_ast(ast_context, v, node), true;
- case Bit_Set_Type:
- return make_symbol_bitset_from_ast(ast_context, v, node), true;
- case Proc_Lit:
- if !v.type.generic {
- return make_symbol_procedure_from_ast(ast_context, local, v.type^, node.name), true;
- }
- else {
- return resolve_generic_function(ast_context, v);
- }
- case Proc_Group:
- return resolve_function_overload(ast_context, v);
- case Array_Type:
- return make_symbol_generic_from_ast(ast_context, local), true;
- case Dynamic_Array_Type:
- return make_symbol_generic_from_ast(ast_context, local), true;
- case Call_Expr:
- return resolve_type_expression(ast_context, local);
- case:
- log.warnf("default type node kind: %T", v);
- return resolve_type_expression(ast_context, local);
- //return make_symbol_generic_from_ast(ast_context, local), true;
- }
- }
-
- else if global, ok := ast_context.globals[node.name]; ast_context.use_globals && ok {
-
- switch v in global.derived {
- case Ident:
-
- if node.name == v.name {
- break;
- }
-
- return resolve_type_identifier(ast_context, v);
- case Struct_Type:
- return make_symbol_struct_from_ast(ast_context, v, node), true;
- case Bit_Set_Type:
- return make_symbol_bitset_from_ast(ast_context, v, node), true;
- case Union_Type:
- return make_symbol_union_from_ast(ast_context, v, node), true;
- case Enum_Type:
- return make_symbol_enum_from_ast(ast_context, v, node), true;
- case Proc_Lit:
- if !v.type.generic {
- return make_symbol_procedure_from_ast(ast_context, global, v.type^, node.name), true;
- }
- else {
- return resolve_generic_function(ast_context, v);
- }
- case Proc_Group:
- return resolve_function_overload(ast_context, v);
- case Array_Type:
- return make_symbol_generic_from_ast(ast_context, global), true;
- case Dynamic_Array_Type:
- return make_symbol_generic_from_ast(ast_context, global), true;
- case Call_Expr:
- return resolve_type_expression(ast_context, global);
- case:
- log.warnf("default type node kind: %T", v);
- return resolve_type_expression(ast_context, global);
- }
-
- }
-
- //if there are more of these variables that hard builtin, move them to the indexer
- else if node.name == "context" {
- return index.lookup("Context", ast_context.current_package);
- }
- //keywords
- else if v, ok := common.keyword_map[node.name]; ok {
-
- ident := index.new_type(Ident, node.pos, node.end, context.temp_allocator);
- ident.name = node.name;
-
- symbol := index.Symbol {
- type = .Keyword,
- signature = node.name,
- pkg = ast_context.current_package,
- value = index.SymbolGenericValue {
- expr = ident,
- },
- };
-
- return symbol, true;
- }
-
- else {
-
- //right now we replace the package ident with the absolute directory name, so it should have '/' which is not a valid ident character
- if strings.contains(node.name, "/") {
-
- symbol := index.Symbol {
- type = .Package,
- pkg = node.name,
- value = index.SymbolPackageValue {
- }
- };
-
- return symbol, true;
-
- }
-
- //part of the ast so we check the imports of the document
- else {
-
- for imp in ast_context.imports {
-
- if strings.compare(imp.base, node.name) == 0 {
-
- symbol := index.Symbol {
- type = .Package,
- pkg = imp.name,
- value = index.SymbolPackageValue {
- }
- };
-
- return symbol, true;
- }
-
- }
-
- }
-
- //last option is to check the index
-
- if symbol, ok := index.lookup(node.name, ast_context.current_package); ok {
- return resolve_symbol_return(ast_context, symbol);
- }
-
- for u in ast_context.usings {
-
- //TODO(Daniel, make into a map, not really required for performance but looks nicer)
- for imp in ast_context.imports {
-
- if strings.compare(imp.base, u) == 0 {
-
- if symbol, ok := index.lookup(node.name, imp.name); ok {
- return resolve_symbol_return(ast_context, symbol);
- }
- }
-
- }
- }
-
- //TODO(daniel, index can be used on identifiers if using is in the function scope)
- }
-
- return index.Symbol {}, false;
-}
+ Function recusively goes through the identifier until it hits a struct, enum, procedure literals, since you can
+ have chained variable declarations. ie. a := foo { test = 2}; b := a; c := b;
+*/
+resolve_type_identifier :: proc (ast_context: ^AstContext, node: ast.Ident) -> (index.Symbol, bool) {
-resolve_ident_is_variable :: proc(ast_context: ^AstContext, node: ast.Ident) -> bool {
+ using ast;
- if v, ok := ast_context.variables[node.name]; ok && v {
- return true;
- }
+ if pkg, ok := ast_context.in_package[node.name]; ok {
+ ast_context.current_package = pkg;
+ }
- if symbol, ok := index.lookup(node.name, ast_context.current_package); ok {
- return symbol.type == .Variable;
- }
+ if _, ok := ast_context.parameters[node.name]; ok {
+ for imp in ast_context.imports {
- return false;
-}
+ if strings.compare(imp.base, node.name) == 0 {
-resolve_ident_is_package :: proc(ast_context: ^AstContext, node: ast.Ident) -> bool {
+ symbol := index.Symbol {
+ type = .Package,
+ pkg = imp.name,
+ value = index.SymbolPackageValue {},
+ };
- if strings.contains(node.name, "/") {
- return true;
- }
+ return symbol, true;
+ }
+ }
+ }
- else {
+ //note(Daniel, if global and local ends up being 100% same just make a function that takes the map)
+ if local := get_local(ast_context, node.pos.offset, node.name); local != nil && ast_context.use_locals {
+
+ switch v in local.derived {
+ case Ident:
+
+ if node.name == v.name {
+ break;
+ }
+
+ return resolve_type_identifier(ast_context, v);
+ case Union_Type:
+ return make_symbol_union_from_ast(ast_context, v, node), true;
+ case Enum_Type:
+ return make_symbol_enum_from_ast(ast_context, v, node), true;
+ case Struct_Type:
+ return make_symbol_struct_from_ast(ast_context, v, node), true;
+ case Bit_Set_Type:
+ return make_symbol_bitset_from_ast(ast_context, v, node), true;
+ case Proc_Lit:
+ if !v.type.generic {
+ return make_symbol_procedure_from_ast(ast_context, local, v.type^, node.name), true;
+ } else {
+ return resolve_generic_function(ast_context, v);
+ }
+ case Proc_Group:
+ return resolve_function_overload(ast_context, v);
+ case Array_Type:
+ return make_symbol_generic_from_ast(ast_context, local), true;
+ case Dynamic_Array_Type:
+ return make_symbol_generic_from_ast(ast_context, local), true;
+ case Call_Expr:
+ return resolve_type_expression(ast_context, local);
+ case:
+ log.warnf("default type node kind: %T", v);
+ return resolve_type_expression(ast_context, local);
+ //return make_symbol_generic_from_ast(ast_context, local), true;
+ }
+ } else if global, ok := ast_context.globals[node.name]; ast_context.use_globals && ok {
+
+ switch v in global.derived {
+ case Ident:
+
+ if node.name == v.name {
+ break;
+ }
+
+ return resolve_type_identifier(ast_context, v);
+ case Struct_Type:
+ return make_symbol_struct_from_ast(ast_context, v, node), true;
+ case Bit_Set_Type:
+ return make_symbol_bitset_from_ast(ast_context, v, node), true;
+ case Union_Type:
+ return make_symbol_union_from_ast(ast_context, v, node), true;
+ case Enum_Type:
+ return make_symbol_enum_from_ast(ast_context, v, node), true;
+ case Proc_Lit:
+ if !v.type.generic {
+ return make_symbol_procedure_from_ast(ast_context, global, v.type^, node.name), true;
+ } else {
+ return resolve_generic_function(ast_context, v);
+ }
+ case Proc_Group:
+ return resolve_function_overload(ast_context, v);
+ case Array_Type:
+ return make_symbol_generic_from_ast(ast_context, global), true;
+ case Dynamic_Array_Type:
+ return make_symbol_generic_from_ast(ast_context, global), true;
+ case Call_Expr:
+ return resolve_type_expression(ast_context, global);
+ case:
+ log.warnf("default type node kind: %T", v);
+ return resolve_type_expression(ast_context, global);
+ }
+ } else
+
+ //if there are more of these variables that hard builtin, move them to the indexer
+ if node.name == "context" {
+ return index.lookup("Context", ast_context.current_package);
+ } else
+ //keywords
+ if v, ok := common.keyword_map[node.name]; ok {
+
+ ident := index.new_type(Ident, node.pos, node.end, context.temp_allocator);
+ ident.name = node.name;
+
+ symbol := index.Symbol {
+ type = .Keyword,
+ signature = node.name,
+ pkg = ast_context.current_package,
+ value = index.SymbolGenericValue {
+ expr = ident
+ },
+ };
+
+ return symbol, true;
+ } else {
+
+ //right now we replace the package ident with the absolute directory name, so it should have '/' which is not a valid ident character
+ if strings.contains(node.name, "/") {
+
+ symbol := index.Symbol {
+ type = .Package,
+ pkg = node.name,
+ value = index.SymbolPackageValue {},
+ };
+
+ return symbol, true;
+ } else
+
+ //part of the ast so we check the imports of the document
+ {
+
+ for imp in ast_context.imports {
+
+ if strings.compare(imp.base, node.name) == 0 {
+
+ symbol := index.Symbol {
+ type = .Package,
+ pkg = imp.name,
+ value = index.SymbolPackageValue {},
+ };
+
+ return symbol, true;
+ }
+ }
+ }
+
+ //last option is to check the index
+
+ if symbol, ok := index.lookup(node.name, ast_context.current_package); ok {
+ return resolve_symbol_return(ast_context, symbol);
+ }
+
+ for u in ast_context.usings {
+
+ //TODO(Daniel, make into a map, not really required for performance but looks nicer)
+ for imp in ast_context.imports {
+
+ if strings.compare(imp.base, u) == 0 {
+
+ if symbol, ok := index.lookup(node.name, imp.name); ok {
+ return resolve_symbol_return(ast_context, symbol);
+ }
+ }
+ }
+ }
+
+ //TODO(daniel, index can be used on identifiers if using is in the function scope)
+ }
- for imp in ast_context.imports {
+ return index.Symbol {}, false;
+}
- if imp.base == node.name {
- return true;
- }
+resolve_ident_is_variable :: proc (ast_context: ^AstContext, node: ast.Ident) -> bool {
- }
+ if v, ok := ast_context.variables[node.name]; ok && v {
+ return true;
+ }
- }
+ if symbol, ok := index.lookup(node.name, ast_context.current_package); ok {
+ return symbol.type == .Variable;
+ }
- return false;
+ return false;
}
-expand_struct_usings :: proc(ast_context: ^AstContext, symbol: index.Symbol, value: index.SymbolStructValue) -> index.SymbolStructValue {
+resolve_ident_is_package :: proc (ast_context: ^AstContext, node: ast.Ident) -> bool {
- //ERROR no completion or over on names and types - generic resolve error
- names := slice.to_dynamic(value.names, context.temp_allocator);
- types := slice.to_dynamic(value.types, context.temp_allocator);
+ if strings.contains(node.name, "/") {
+ return true;
+ } else {
- //ERROR no hover on k and v(completion works)
- for k, v in value.usings {
+ for imp in ast_context.imports {
- ast_context.current_package = symbol.pkg;
+ if imp.base == node.name {
+ return true;
+ }
+ }
+ }
- field_expr: ^ast.Expr;
+ return false;
+}
- for name, i in value.names {
+expand_struct_usings :: proc (ast_context: ^AstContext, symbol: index.Symbol, value: index.SymbolStructValue) -> index.SymbolStructValue {
- if name == k && v {
- field_expr = value.types[i];
- }
+ //ERROR no completion or over on names and types - generic resolve error
+ names := slice.to_dynamic(value.names, context.temp_allocator);
+ types := slice.to_dynamic(value.types, context.temp_allocator);
- }
+ //ERROR no hover on k and v(completion works)
+ for k, v in value.usings {
- if field_expr == nil {
- continue;
- }
+ ast_context.current_package = symbol.pkg;
- if s, ok := resolve_type_expression(ast_context, field_expr); ok {
+ field_expr: ^ast.Expr;
- if struct_value, ok := s.value.(index.SymbolStructValue); ok {
+ for name, i in value.names {
- for name in struct_value.names {
- append(&names, name);
- }
+ if name == k && v {
+ field_expr = value.types[i];
+ }
+ }
- for type in struct_value.types {
- append(&types, type);
- }
+ if field_expr == nil {
+ continue;
+ }
- }
+ if s, ok := resolve_type_expression(ast_context, field_expr); ok {
- }
+ if struct_value, ok := s.value.(index.SymbolStructValue); ok {
- }
+ for name in struct_value.names {
+ append(&names, name);
+ }
- return {
- names = names[:],
- types = types[:],
- };
+ for type in struct_value.types {
+ append(&types, type);
+ }
+ }
+ }
+ }
+ return {
+ names = names[:],
+ types = types[:],
+ };
}
-resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok := true) -> (index.Symbol, bool) {
-
- if !ok {
- return symbol, ok;
- }
-
- #partial switch v in symbol.value {
- case index.SymbolProcedureGroupValue:
- if symbol, ok := resolve_function_overload(ast_context, v.group.derived.(ast.Proc_Group)); ok {
- return symbol, true;
- }
- else {
- return symbol, false;
- }
- case index.SymbolProcedureValue:
- if v.generic {
- return resolve_generic_function_symbol(ast_context, v.arg_types, v.return_types);
- }
- else {
- return symbol, true;
- }
- case index.SymbolStructValue:
-
- //expand the types and names from the using - can't be done while indexing without complicating everything(this also saves memory)
- if len(v.usings) > 0 {
- expanded := symbol;
- expanded.value = expand_struct_usings(ast_context, symbol, v);
- return expanded, true;
- }
- else {
- return symbol, true;
- }
-
- case index.SymbolGenericValue:
- return resolve_type_expression(ast_context, v.expr);
- }
-
- return symbol, true;
-}
+resolve_symbol_return :: proc (ast_context: ^AstContext, symbol: index.Symbol, ok := true) -> (index.Symbol, bool) {
-resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (index.Symbol, bool) {
+ if !ok {
+ return symbol, ok;
+ }
- symbol: index.Symbol;
+ #partial switch v in symbol.value {
+ case index.SymbolProcedureGroupValue:
+ if symbol, ok := resolve_function_overload(ast_context, v.group.derived.(ast.Proc_Group)); ok {
+ return symbol, true;
+ } else {
+ return symbol, false;
+ }
+ case index.SymbolProcedureValue:
+ if v.generic {
+ return resolve_generic_function_symbol(ast_context, v.arg_types, v.return_types);
+ } else {
+ return symbol, true;
+ }
+ case index.SymbolStructValue:
+
+ //expand the types and names from the using - can't be done while indexing without complicating everything(this also saves memory)
+ if len(v.usings) > 0 {
+ expanded := symbol;
+ expanded.value = expand_struct_usings(ast_context, symbol, v);
+ return expanded, true;
+ } else {
+ return symbol, true;
+ }
+
+ case index.SymbolGenericValue:
+ return resolve_type_expression(ast_context, v.expr);
+ }
- if local := get_local(ast_context, node.pos.offset, node.name); local != nil {
- symbol.range = common.get_token_range(get_local(ast_context, node.pos.offset, node.name), ast_context.file.src);
- return symbol, true;
- }
+ return symbol, true;
+}
- else if global, ok := ast_context.globals[node.name]; ok {
- symbol.range = common.get_token_range(global, ast_context.file.src);
- return symbol, true;
- }
+resolve_location_identifier :: proc (ast_context: ^AstContext, node: ast.Ident) -> (index.Symbol, bool) {
+ symbol: index.Symbol;
- return index.lookup(node.name, ast_context.document_package);
-}
+ if local := get_local(ast_context, node.pos.offset, node.name); local != nil {
+ symbol.range = common.get_token_range(get_local(ast_context, node.pos.offset, node.name), ast_context.file.src);
+ return symbol, true;
+ } else if global, ok := ast_context.globals[node.name]; ok {
+ symbol.range = common.get_token_range(global, ast_context.file.src);
+ return symbol, true;
+ }
-make_pointer_ast :: proc(elem: ^ast.Expr) -> ^ast.Pointer_Type {
- pointer := index.new_type(ast.Pointer_Type, elem.pos, elem.end, context.temp_allocator);
- pointer.elem = elem;
- return pointer;
+ return index.lookup(node.name, ast_context.document_package);
}
-make_bool_ast :: proc() -> ^ast.Ident {
- ident := index.new_type(ast.Ident, {}, {}, context.temp_allocator);
- ident.name = bool_lit;
- return ident;
+make_pointer_ast :: proc (elem: ^ast.Expr) -> ^ast.Pointer_Type {
+ pointer := index.new_type(ast.Pointer_Type, elem.pos, elem.end, context.temp_allocator);
+ pointer.elem = elem;
+ return pointer;
}
-make_int_ast :: proc() -> ^ast.Ident {
- ident := index.new_type(ast.Ident, {}, {}, context.temp_allocator);
- ident.name = int_lit;
- return ident;
+make_bool_ast :: proc () -> ^ast.Ident {
+ ident := index.new_type(ast.Ident, {}, {}, context.temp_allocator);
+ ident.name = bool_lit;
+ return ident;
}
-get_package_from_node :: proc(node: ast.Node) -> string {
- slashed, _ := filepath.to_slash(node.pos.file, context.temp_allocator);
- ret := strings.to_lower(path.dir(slashed, context.temp_allocator), context.temp_allocator);
- return ret;
+make_int_ast :: proc () -> ^ast.Ident {
+ ident := index.new_type(ast.Ident, {}, {}, context.temp_allocator);
+ ident.name = int_lit;
+ return ident;
}
-get_using_packages :: proc(ast_context: ^AstContext) -> [] string {
-
- usings := make([] string, len(ast_context.usings), context.temp_allocator);
+get_package_from_node :: proc (node: ast.Node) -> string {
+ slashed, _ := filepath.to_slash(node.pos.file, context.temp_allocator);
+ ret := strings.to_lower(path.dir(slashed, context.temp_allocator), context.temp_allocator);
+ return ret;
+}
- if len(ast_context.usings) == 0 {
- return usings;
- }
+get_using_packages :: proc (ast_context: ^AstContext) -> []string {
- //probably map instead
- for u, i in ast_context.usings {
+ usings := make([]string, len(ast_context.usings), context.temp_allocator);
- for imp in ast_context.imports {
+ if len(ast_context.usings) == 0 {
+ return usings;
+ }
- if strings.compare(imp.base, u) == 0 {
- usings[i] = imp.name;
- }
+ //probably map instead
+ for u, i in ast_context.usings {
- }
+ for imp in ast_context.imports {
- }
+ if strings.compare(imp.base, u) == 0 {
+ usings[i] = imp.name;
+ }
+ }
+ }
- return usings;
+ return usings;
}
-make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v: ast.Proc_Type, name: string) -> index.Symbol {
+make_symbol_procedure_from_ast :: proc (ast_context: ^AstContext, n: ^ast.Node, v: ast.Proc_Type, name: string) -> index.Symbol {
- symbol := index.Symbol {
- range = common.get_token_range(n^, ast_context.file.src),
- type = .Function,
- pkg = get_package_from_node(n^),
- };
-
- symbol.name = name;
+ symbol := index.Symbol {
+ range = common.get_token_range(n^, ast_context.file.src),
+ type = .Function,
+ pkg = get_package_from_node(n^),
+ };
- return_types := make([dynamic] ^ast.Field, context.temp_allocator);
- arg_types := make([dynamic] ^ast.Field, context.temp_allocator);
+ symbol.name = name;
- if v.results != nil {
+ return_types := make([dynamic]^ast.Field, context.temp_allocator);
+ arg_types := make([dynamic]^ast.Field, context.temp_allocator);
- for ret in v.results.list {
- append(&return_types, ret);
- }
+ if v.results != nil {
- symbol.returns = strings.concatenate( {"(", string(ast_context.file.src[v.results.pos.offset:v.results.end.offset]), ")"}, context.temp_allocator);
+ for ret in v.results.list {
+ append(&return_types, ret);
+ }
- }
+ symbol.returns = strings.concatenate({"(", string(ast_context.file.src[v.results.pos.offset:v.results.end.offset]), ")"}, context.temp_allocator);
+ }
- if v.params != nil {
+ if v.params != nil {
- for param in v.params.list {
- append(&arg_types, param);
- }
+ for param in v.params.list {
+ append(&arg_types, param);
+ }
- symbol.signature = strings.concatenate( {"(", string(ast_context.file.src[v.params.pos.offset:v.params.end.offset]), ")"}, context.temp_allocator);
- }
+ symbol.signature = strings.concatenate({"(", string(ast_context.file.src[v.params.pos.offset:v.params.end.offset]), ")"}, context.temp_allocator);
+ }
- symbol.value = index.SymbolProcedureValue {
- return_types = return_types[:],
- arg_types = arg_types[:],
- };
+ symbol.value = index.SymbolProcedureValue {
+ return_types = return_types[:],
+ arg_types = arg_types[:],
+ };
- return symbol;
+ return symbol;
}
-make_symbol_generic_from_ast :: proc(ast_context: ^AstContext, expr: ^ast.Expr) -> index.Symbol {
+make_symbol_generic_from_ast :: proc (ast_context: ^AstContext, expr: ^ast.Expr) -> index.Symbol {
- symbol := index.Symbol {
- range = common.get_token_range(expr, ast_context.file.src),
- type = .Variable,
- signature = index.node_to_string(expr),
- pkg = get_package_from_node(expr^),
- };
+ symbol := index.Symbol {
+ range = common.get_token_range(expr, ast_context.file.src),
+ type = .Variable,
+ signature = index.node_to_string(expr),
+ pkg = get_package_from_node(expr^),
+ };
- symbol.value = index.SymbolGenericValue {
- expr = expr,
- };
+ symbol.value = index.SymbolGenericValue {
+ expr = expr
+ };
- return symbol;
+ return symbol;
}
-make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, ident: ast.Ident) -> index.Symbol {
-
- symbol := index.Symbol {
- range = common.get_token_range(v, ast_context.file.src),
- type = .Enum,
- name = ident.name,
- pkg = get_package_from_node(v.node),
- };
+make_symbol_union_from_ast :: proc (ast_context: ^AstContext, v: ast.Union_Type, ident: ast.Ident) -> index.Symbol {
- names := make([dynamic] string, context.temp_allocator);
+ symbol := index.Symbol {
+ range = common.get_token_range(v, ast_context.file.src),
+ type = .Enum,
+ name = ident.name,
+ pkg = get_package_from_node(v.node),
+ };
- for variant in v.variants {
+ names := make([dynamic]string, context.temp_allocator);
- if ident, ok := variant.derived.(ast.Ident); ok {
- append(&names, ident.name);
- }
+ for variant in v.variants {
- }
+ if ident, ok := variant.derived.(ast.Ident); ok {
+ append(&names, ident.name);
+ }
+ }
- symbol.value = index.SymbolUnionValue {
- names = names[:],
- };
+ symbol.value = index.SymbolUnionValue {
+ names = names[:]
+ };
- return symbol;
+ return symbol;
}
-make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, ident: ast.Ident) -> index.Symbol {
-
- symbol := index.Symbol {
- range = common.get_token_range(v, ast_context.file.src),
- type = .Enum,
- name = ident.name,
- pkg = get_package_from_node(v.node),
- };
+make_symbol_enum_from_ast :: proc (ast_context: ^AstContext, v: ast.Enum_Type, ident: ast.Ident) -> index.Symbol {
- names := make([dynamic] string, context.temp_allocator);
-
- for n in v.fields {
+ symbol := index.Symbol {
+ range = common.get_token_range(v, ast_context.file.src),
+ type = .Enum,
+ name = ident.name,
+ pkg = get_package_from_node(v.node),
+ };
- if ident, ok := n.derived.(ast.Ident); ok {
- append(&names, ident.name);
- }
+ names := make([dynamic]string, context.temp_allocator);
- else if field, ok := n.derived.(ast.Field_Value); ok {
- append(&names, field.field.derived.(ast.Ident).name);
- }
+ for n in v.fields {
- }
+ if ident, ok := n.derived.(ast.Ident); ok {
+ append(&names, ident.name);
+ } else if field, ok := n.derived.(ast.Field_Value); ok {
+ append(&names, field.field.derived.(ast.Ident).name);
+ }
+ }
- symbol.value = index.SymbolEnumValue {
- names = names[:],
- };
+ symbol.value = index.SymbolEnumValue {
+ names = names[:]
+ };
- return symbol;
+ return symbol;
}
-make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Type, ident: ast.Ident) -> index.Symbol {
+make_symbol_bitset_from_ast :: proc (ast_context: ^AstContext, v: ast.Bit_Set_Type, ident: ast.Ident) -> index.Symbol {
- symbol := index.Symbol {
- range = common.get_token_range(v, ast_context.file.src),
- type = .Enum,
- name = ident.name,
- pkg = get_package_from_node(v.node),
- };
+ symbol := index.Symbol {
+ range = common.get_token_range(v, ast_context.file.src),
+ type = .Enum,
+ name = ident.name,
+ pkg = get_package_from_node(v.node),
+ };
- symbol.value = index.SymbolBitSetValue {
- expr = v.elem,
- };
+ symbol.value = index.SymbolBitSetValue {
+ expr = v.elem
+ };
- return symbol;
+ return symbol;
}
-make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type, ident: ast.Ident) -> index.Symbol {
-
- symbol := index.Symbol {
- range = common.get_token_range(v, ast_context.file.src),
- type = .Struct,
- name = ident.name,
- pkg = get_package_from_node(v.node),
- };
+make_symbol_struct_from_ast :: proc (ast_context: ^AstContext, v: ast.Struct_Type, ident: ast.Ident) -> index.Symbol {
- names := make([dynamic] string, context.temp_allocator);
- types := make([dynamic] ^ast.Expr, context.temp_allocator);
- usings := make(map [string] bool, 0, context.temp_allocator);
-
- for field in v.fields.list {
+ symbol := index.Symbol {
+ range = common.get_token_range(v, ast_context.file.src),
+ type = .Struct,
+ name = ident.name,
+ pkg = get_package_from_node(v.node),
+ };
- for n in field.names {
- if identifier, ok := n.derived.(ast.Ident); ok {
- append(&names, identifier.name);
- append(&types, index.clone_type(field.type, context.temp_allocator, nil));
+ names := make([dynamic]string, context.temp_allocator);
+ types := make([dynamic]^ast.Expr, context.temp_allocator);
+ usings := make(map[string]bool, 0, context.temp_allocator);
- if .Using in field.flags {
- usings[identifier.name] = true;
- }
+ for field in v.fields.list {
- }
- }
+ for n in field.names {
+ if identifier, ok := n.derived.(ast.Ident); ok {
+ append(&names, identifier.name);
+ append(&types, index.clone_type(field.type, context.temp_allocator, nil));
- }
+ if .Using in field.flags {
+ usings[identifier.name] = true;
+ }
+ }
+ }
+ }
- symbol.value = index.SymbolStructValue {
- names = names[:],
- types = types[:],
- usings = usings,
- };
+ symbol.value = index.SymbolStructValue {
+ names = names[:],
+ types = types[:],
+ usings = usings,
+ };
- if v.poly_params != nil {
- resolve_poly_struct(ast_context, v, &symbol);
- }
+ if v.poly_params != nil {
+ resolve_poly_struct(ast_context, v, &symbol);
+ }
- //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.(index.SymbolStructValue));
- }
+ //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.(index.SymbolStructValue));
+ }
- return symbol;
+ return symbol;
}
-resolve_poly_struct :: proc(ast_context: ^AstContext, v: ast.Struct_Type, symbol: ^index.Symbol) {
-
- if ast_context.call == nil {
- log.infof("no call");
- return;
- }
-
- symbol_value := &symbol.value.(index.SymbolStructValue);
-
- if symbol_value == nil {
- log.infof("no value");
- return;
- }
-
- i := 0;
-
- poly_map := make(map [string] ^ast.Expr, 0, context.temp_allocator);
-
- for param in v.poly_params.list {
-
- for name in param.names {
-
- if len(ast_context.call.args) <= i {
- break;
- }
-
- 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];
- }
-
- }
+resolve_poly_struct :: proc (ast_context: ^AstContext, v: ast.Struct_Type, symbol: ^index.Symbol) {
+ if ast_context.call == nil {
+ log.infof("no call");
+ return;
+ }
- i += 1;
- }
+ symbol_value := &symbol.value.(index.SymbolStructValue);
+ if symbol_value == nil {
+ log.infof("no value");
+ return;
+ }
- }
+ i := 0;
- for type, i in symbol_value.types {
+ poly_map := make(map[string]^ast.Expr, 0, context.temp_allocator);
- if ident, ok := type.derived.(ast.Ident); ok {
+ for param in v.poly_params.list {
- if expr, ok := poly_map[ident.name]; ok {
- symbol_value.types[i] = expr;
- }
+ for name in param.names {
- }
+ if len(ast_context.call.args) <= i {
+ break;
+ }
- else if call_expr, ok := type.derived.(ast.Call_Expr); ok {
+ if param.type == nil {
+ continue;
+ }
- if call_expr.args == nil {
- continue;
- }
+ if poly, ok := param.type.derived.(ast.Typeid_Type); ok {
- for arg, i in call_expr.args {
+ if ident, ok := name.derived.(ast.Ident); ok {
+ poly_map[ident.name] = ast_context.call.args[i];
+ }
+ }
- if ident, ok := arg.derived.(ast.Ident); ok {
+ i += 1;
+ }
+ }
- if expr, ok := poly_map[ident.name]; ok {
- call_expr.args[i] = expr;
- }
+ for type, i in symbol_value.types {
- }
+ if ident, ok := type.derived.(ast.Ident); ok {
+ if expr, ok := poly_map[ident.name]; ok {
+ symbol_value.types[i] = expr;
+ }
+ } else if call_expr, ok := type.derived.(ast.Call_Expr); ok {
- }
+ if call_expr.args == nil {
+ continue;
+ }
- }
+ for arg, i in call_expr.args {
- }
+ if ident, ok := arg.derived.(ast.Ident); ok {
+ if expr, ok := poly_map[ident.name]; ok {
+ call_expr.args[i] = expr;
+ }
+ }
+ }
+ }
+ }
}
-get_globals :: proc(file: ast.File, ast_context: ^AstContext) {
+get_globals :: proc (file: ast.File, ast_context: ^AstContext) {
- ast_context.variables["context"] = true;
+ ast_context.variables["context"] = true;
- exprs := common.collect_globals(file);
+ exprs := common.collect_globals(file);
- for expr in exprs {
- ast_context.globals[expr.name] = expr.expr;
- ast_context.variables[expr.name] = expr.mutable;
- }
+ for expr in exprs {
+ ast_context.globals[expr.name] = expr.expr;
+ ast_context.variables[expr.name] = expr.mutable;
+ }
}
-get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^AstContext, results: ^[dynamic]^ast.Expr) {
-
- using ast;
-
- ast_context.use_locals = true;
- ast_context.use_globals = true;
-
- switch v in value.derived {
- 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.(index.SymbolProcedureValue); ok {
-
- for ret in procedure.return_types {
- append(results, ret.type);
- }
-
- }
-
- }
-
- case Comp_Lit:
- if v.type != nil {
- append(results, v.type);
- }
- case Array_Type:
- if v.elem != nil {
- append(results, v.elem);
- }
- case Dynamic_Array_Type:
- if v.elem != nil {
- append(results, v.elem);
- }
- case Selector_Expr:
- if v.expr != nil {
- append(results, value);
- }
- case Type_Assertion:
- if v.type != nil {
- append(results, v.type);
- append(results, make_bool_ast());
- }
- case:
- //log.debugf("default node get_generic_assignment %v", v);
- append(results, value);
- }
-
+get_generic_assignment :: proc (file: ast.File, value: ^ast.Expr, ast_context: ^AstContext, results: ^[dynamic]^ast.Expr) {
+
+ using ast;
+
+ ast_context.use_locals = true;
+ ast_context.use_globals = true;
+
+ switch v in value.derived {
+ 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.(index.SymbolProcedureValue); ok {
+
+ for ret in procedure.return_types {
+ append(results, ret.type);
+ }
+ }
+ }
+
+ case Comp_Lit:
+ if v.type != nil {
+ append(results, v.type);
+ }
+ case Array_Type:
+ if v.elem != nil {
+ append(results, v.elem);
+ }
+ case Dynamic_Array_Type:
+ if v.elem != nil {
+ append(results, v.elem);
+ }
+ case Selector_Expr:
+ if v.expr != nil {
+ append(results, value);
+ }
+ case Type_Assertion:
+ if v.type != nil {
+ append(results, v.type);
+ append(results, make_bool_ast());
+ }
+ case:
+ //log.debugf("default node get_generic_assignment %v", v);
+ append(results, value);
+ }
}
-get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_context: ^AstContext) {
-
- using ast;
-
- if len(value_decl.names) <= 0 {
- return;
- }
-
-
- if value_decl.type != nil {
- str := common.get_ast_node_string(value_decl.names[0], file.src);
- ast_context.variables[str] = value_decl.is_mutable;
- store_local(ast_context, value_decl.type, value_decl.pos.offset, str);
- return;
- }
+get_locals_value_decl :: proc (file: ast.File, value_decl: ast.Value_Decl, ast_context: ^AstContext) {
- results := make([dynamic]^Expr, context.temp_allocator);
+ using ast;
- for value in value_decl.values {
- get_generic_assignment(file, value, ast_context, &results);
- }
-
- for name, i in value_decl.names {
- if i < len(results) {
- str := common.get_ast_node_string(name, file.src);
- ast_context.in_package[str] = get_package_from_node(results[i]);
- store_local(ast_context, results[i], name.pos.offset, str);
- ast_context.variables[str] = value_decl.is_mutable;
- }
- }
-
-}
+ if len(value_decl.names) <= 0 {
+ return;
+ }
-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;
-
- using ast;
-
- if stmt == nil {
- return;
- }
-
- if stmt.pos.offset > document_position.position {
- return;
- }
-
- switch v in stmt.derived {
- case Value_Decl:
- get_locals_value_decl(file, v, ast_context);
- case Type_Switch_Stmt:
- get_locals_type_switch_stmt(file, v, ast_context, document_position);
- case Switch_Stmt:
- get_locals_switch_stmt(file, v, ast_context, document_position);
- case For_Stmt:
- get_locals_for_stmt(file, v, ast_context, document_position);
- case Inline_Range_Stmt:
- get_locals_stmt(file, v.body, ast_context, document_position);
- case Range_Stmt:
- get_locals_for_range_stmt(file, v, ast_context, document_position);
- case If_Stmt:
- get_locals_if_stmt(file, v, ast_context, document_position);
- case Block_Stmt:
- for stmt in v.stmts {
- get_locals_stmt(file, stmt, ast_context, document_position);
- }
- case Proc_Lit:
- get_locals_stmt(file, v.body, ast_context, document_position);
- case Assign_Stmt:
- if save_assign {
- get_locals_assign_stmt(file, v, ast_context);
- }
- case Using_Stmt:
- get_locals_using_stmt(file, v, ast_context);
- case When_Stmt:
- get_locals_stmt(file, v.else_stmt, ast_context, document_position);
- get_locals_stmt(file, v.body, ast_context, document_position);
- case:
- //log.debugf("default node local stmt %v", v);
- }
+ if value_decl.type != nil {
+ str := common.get_ast_node_string(value_decl.names[0], file.src);
+ ast_context.variables[str] = value_decl.is_mutable;
+ store_local(ast_context, value_decl.type, value_decl.pos.offset, str);
+ return;
+ }
+ results := make([dynamic]^Expr, context.temp_allocator);
+ for value in value_decl.values {
+ get_generic_assignment(file, value, ast_context, &results);
+ }
+ for name, i in value_decl.names {
+ if i < len(results) {
+ str := common.get_ast_node_string(name, file.src);
+ ast_context.in_package[str] = get_package_from_node(results[i]);
+ store_local(ast_context, results[i], name.pos.offset, str);
+ ast_context.variables[str] = value_decl.is_mutable;
+ }
+ }
}
-get_locals_using_stmt :: proc(file: ast.File, stmt: ast.Using_Stmt, ast_context: ^AstContext) {
-
- for u in stmt.list {
-
- if symbol, ok := resolve_type_expression(ast_context, u); ok {
+get_locals_stmt :: proc (file: ast.File, stmt: ^ast.Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext, save_assign := false) {
- #partial switch v in symbol.value {
- case index.SymbolPackageValue:
- if ident, ok := u.derived.(ast.Ident); ok {
- append(&ast_context.usings, ident.name);
- }
- case index.SymbolStructValue:
- for name, i in v.names {
- selector := index.new_type(ast.Selector_Expr, v.types[i].pos, v.types[i].end, context.temp_allocator);
- selector.expr = u;
- selector.field = index.new_type(ast.Ident, v.types[i].pos, v.types[i].end, context.temp_allocator);
- selector.field.name = name;
- store_local(ast_context, selector, 0, name);
- ast_context.variables[name] = true;
- }
+ ast_context.use_locals = true;
+ ast_context.use_globals = true;
+ ast_context.current_package = ast_context.document_package;
- }
-
-
- }
+ using ast;
+ if stmt == nil {
+ return;
+ }
- }
+ if stmt.pos.offset > document_position.position {
+ return;
+ }
+ switch v in stmt.derived {
+ case Value_Decl:
+ get_locals_value_decl(file, v, ast_context);
+ case Type_Switch_Stmt:
+ get_locals_type_switch_stmt(file, v, ast_context, document_position);
+ case Switch_Stmt:
+ get_locals_switch_stmt(file, v, ast_context, document_position);
+ case For_Stmt:
+ get_locals_for_stmt(file, v, ast_context, document_position);
+ case Inline_Range_Stmt:
+ get_locals_stmt(file, v.body, ast_context, document_position);
+ case Range_Stmt:
+ get_locals_for_range_stmt(file, v, ast_context, document_position);
+ case If_Stmt:
+ get_locals_if_stmt(file, v, ast_context, document_position);
+ case Block_Stmt:
+ for stmt in v.stmts {
+ get_locals_stmt(file, stmt, ast_context, document_position);
+ }
+ case Proc_Lit:
+ get_locals_stmt(file, v.body, ast_context, document_position);
+ case Assign_Stmt:
+ if save_assign {
+ get_locals_assign_stmt(file, v, ast_context);
+ }
+ case Using_Stmt:
+ get_locals_using_stmt(file, v, ast_context);
+ case When_Stmt:
+ get_locals_stmt(file, v.else_stmt, ast_context, document_position);
+ get_locals_stmt(file, v.body, ast_context, document_position);
+ case:
+ //log.debugf("default node local stmt %v", v);
+ }
}
-get_locals_assign_stmt :: proc(file: ast.File, stmt: ast.Assign_Stmt, ast_context: ^AstContext) {
-
- using ast;
+get_locals_using_stmt :: proc (file: ast.File, stmt: ast.Using_Stmt, ast_context: ^AstContext) {
+
+ for u in stmt.list {
+
+ if symbol, ok := resolve_type_expression(ast_context, u); ok {
+
+ #partial switch v in symbol.value {
+ case index.SymbolPackageValue:
+ if ident, ok := u.derived.(ast.Ident); ok {
+ append(&ast_context.usings, ident.name);
+ }
+ case index.SymbolStructValue:
+ for name, i in v.names {
+ selector := index.new_type(ast.Selector_Expr, v.types[i].pos, v.types[i].end, context.temp_allocator);
+ selector.expr = u;
+ selector.field = index.new_type(ast.Ident, v.types[i].pos, v.types[i].end, context.temp_allocator);
+ selector.field.name = name;
+ store_local(ast_context, selector, 0, name);
+ ast_context.variables[name] = true;
+ }
+ }
+ }
+ }
+}
- if stmt.lhs == nil || stmt.rhs == nil {
- return;
- }
+get_locals_assign_stmt :: proc (file: ast.File, stmt: ast.Assign_Stmt, ast_context: ^AstContext) {
- results := make([dynamic]^Expr, context.temp_allocator);
+ using ast;
- for rhs in stmt.rhs {
- get_generic_assignment(file, rhs, ast_context, &results);
- }
+ if stmt.lhs == nil || stmt.rhs == nil {
+ return;
+ }
+ results := make([dynamic]^Expr, context.temp_allocator);
- if len(stmt.lhs) != len(results) {
- return;
- }
+ for rhs in stmt.rhs {
+ get_generic_assignment(file, rhs, ast_context, &results);
+ }
- for lhs, i in stmt.lhs {
- if ident, ok := lhs.derived.(ast.Ident); ok {
- store_local(ast_context, results[i], ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
- }
- }
+ if len(stmt.lhs) != len(results) {
+ return;
+ }
+ for lhs, i in stmt.lhs {
+ if ident, ok := lhs.derived.(ast.Ident); ok {
+ store_local(ast_context, results[i], ident.pos.offset, ident.name);
+ ast_context.variables[ident.name] = true;
+ }
+ }
}
-get_locals_if_stmt :: proc(file: ast.File, stmt: ast.If_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) {
+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;
- }
+ if !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) {
+ return;
+ }
- get_locals_stmt(file, stmt.init, ast_context, document_position, true);
- get_locals_stmt(file, stmt.body, ast_context, document_position);
- get_locals_stmt(file, stmt.else_stmt, ast_context, document_position);
+ get_locals_stmt(file, stmt.init, ast_context, document_position, true);
+ get_locals_stmt(file, stmt.body, ast_context, document_position);
+ 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) {
-
- using ast;
-
- if !(stmt.body.pos.offset <= document_position.position && document_position.position <= stmt.body.end.offset) {
- return;
- }
-
- results := make([dynamic]^Expr, context.temp_allocator);
-
- if stmt.expr == nil {
- return;
- }
-
- if symbol, ok := resolve_type_expression(ast_context, stmt.expr); ok {
-
- if generic, ok := symbol.value.(index.SymbolGenericValue); ok {
+get_locals_for_range_stmt :: proc (file: ast.File, stmt: ast.Range_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) {
- switch v in generic.expr.derived {
- case Map_Type:
- if stmt.val0 != nil {
+ using ast;
- if ident, ok := stmt.val0.derived.(Ident); ok {
- store_local(ast_context, v.key, ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
- ast_context.in_package[ident.name] = symbol.pkg;
- }
-
- }
-
- if stmt.val1 != nil {
-
- if ident, ok := stmt.val1.derived.(Ident); ok {
- store_local(ast_context, v.value, ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
- ast_context.in_package[ident.name] = symbol.pkg;
- }
-
- }
- case Dynamic_Array_Type:
- if stmt.val0 != nil {
-
- if ident, ok := stmt.val0.derived.(Ident); ok {
- store_local(ast_context, v.elem, ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
- ast_context.in_package[ident.name] = symbol.pkg;
- }
-
- }
-
- if stmt.val1 != nil {
-
- if ident, ok := stmt.val1.derived.(Ident); ok {
- store_local(ast_context, make_int_ast(), ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
- ast_context.in_package[ident.name] = symbol.pkg;
- }
-
- }
- case Array_Type:
- if stmt.val0 != nil {
-
- if ident, ok := stmt.val0.derived.(Ident); ok {
- store_local(ast_context, v.elem, ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
- ast_context.in_package[ident.name] = symbol.pkg;
- }
-
- }
-
- if stmt.val1 != nil {
-
- if ident, ok := stmt.val1.derived.(Ident); ok {
- store_local(ast_context, make_int_ast(), ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
- ast_context.in_package[ident.name] = symbol.pkg;
- }
+ if !(stmt.body.pos.offset <= document_position.position && document_position.position <= stmt.body.end.offset) {
+ return;
+ }
- }
- }
+ results := make([dynamic]^Expr, context.temp_allocator);
- }
+ if stmt.expr == nil {
+ return;
+ }
- }
+ if symbol, ok := resolve_type_expression(ast_context, stmt.expr); ok {
+
+ if generic, ok := symbol.value.(index.SymbolGenericValue); ok {
+
+ switch v in generic.expr.derived {
+ case Map_Type:
+ if stmt.val0 != nil {
+
+ if ident, ok := stmt.val0.derived.(Ident); ok {
+ store_local(ast_context, v.key, ident.pos.offset, ident.name);
+ ast_context.variables[ident.name] = true;
+ ast_context.in_package[ident.name] = symbol.pkg;
+ }
+ }
+
+ if stmt.val1 != nil {
+
+ if ident, ok := stmt.val1.derived.(Ident); ok {
+ store_local(ast_context, v.value, ident.pos.offset, ident.name);
+ ast_context.variables[ident.name] = true;
+ ast_context.in_package[ident.name] = symbol.pkg;
+ }
+ }
+ case Dynamic_Array_Type:
+ if stmt.val0 != nil {
+
+ if ident, ok := stmt.val0.derived.(Ident); ok {
+ store_local(ast_context, v.elem, ident.pos.offset, ident.name);
+ ast_context.variables[ident.name] = true;
+ ast_context.in_package[ident.name] = symbol.pkg;
+ }
+ }
+
+ if stmt.val1 != nil {
+
+ if ident, ok := stmt.val1.derived.(Ident); ok {
+ store_local(ast_context, make_int_ast(), ident.pos.offset, ident.name);
+ ast_context.variables[ident.name] = true;
+ ast_context.in_package[ident.name] = symbol.pkg;
+ }
+ }
+ case Array_Type:
+ if stmt.val0 != nil {
+
+ if ident, ok := stmt.val0.derived.(Ident); ok {
+ store_local(ast_context, v.elem, ident.pos.offset, ident.name);
+ ast_context.variables[ident.name] = true;
+ ast_context.in_package[ident.name] = symbol.pkg;
+ }
+ }
+
+ if stmt.val1 != nil {
+
+ if ident, ok := stmt.val1.derived.(Ident); ok {
+ store_local(ast_context, make_int_ast(), ident.pos.offset, ident.name);
+ 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_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) {
+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;
- }
+ if !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) {
+ return;
+ }
- get_locals_stmt(file, stmt.init, ast_context, document_position, true);
- get_locals_stmt(file, stmt.body, ast_context, document_position);
+ get_locals_stmt(file, stmt.init, ast_context, document_position, true);
+ 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) {
+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;
- }
+ 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_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) {
-
- using ast;
+get_locals_type_switch_stmt :: proc (file: ast.File, stmt: ast.Type_Switch_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) {
- if !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) {
- return;
- }
+ using ast;
- if stmt.body == nil {
- return;
- }
-
- 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 !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) {
+ return;
+ }
- for b in cause.body {
- get_locals_stmt(file, b, ast_context, document_position);
- }
+ if stmt.body == nil {
+ return;
+ }
- tag := stmt.tag.derived.(Assign_Stmt);
+ if block, ok := stmt.body.derived.(Block_Stmt); ok {
- if len(tag.lhs) == 1 && len(cause.list) == 1 {
- ident := tag.lhs[0].derived.(Ident);
- store_local(ast_context, cause.list[0], ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
- }
+ 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 {
- }
+ for b in cause.body {
+ get_locals_stmt(file, b, ast_context, document_position);
+ }
- }
+ 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, cause.list[0], ident.pos.offset, ident.name);
+ ast_context.variables[ident.name] = true;
+ }
+ }
+ }
+ }
}
-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;
- }
-
-
- if proc_lit.type != nil && proc_lit.type.params != nil {
+get_locals :: proc (file: ast.File, function: ^ast.Node, ast_context: ^AstContext, document_position: ^DocumentPositionContext) {
- for arg in proc_lit.type.params.list {
+ proc_lit, ok := function.derived.(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, arg.type, name.pos.offset, str);
- ast_context.variables[str] = true;
- ast_context.parameters[str] = true;
-
- log.info(arg.flags);
+ if !ok || proc_lit.body == nil {
+ return;
+ }
- if .Using in arg.flags {
- using_stmt: ast.Using_Stmt;
- using_stmt.list = make([] ^ ast.Expr, 1, context.temp_allocator);
- using_stmt.list[0] = arg.type;
- get_locals_using_stmt(file, using_stmt, ast_context);
- }
- }
- }
+ if proc_lit.type != nil && proc_lit.type.params != nil {
- }
+ for arg in proc_lit.type.params.list {
+ for name in arg.names {
+ if arg.type != nil {
+ str := common.get_ast_node_string(name, file.src);
+ store_local(ast_context, arg.type, name.pos.offset, str);
+ ast_context.variables[str] = true;
+ ast_context.parameters[str] = true;
- }
+ log.info(arg.flags);
- block: ast.Block_Stmt;
- block, ok = proc_lit.body.derived.(ast.Block_Stmt);
+ if .Using in arg.flags {
+ using_stmt: ast.Using_Stmt;
+ using_stmt.list = make([]^ast.Expr, 1, context.temp_allocator);
+ using_stmt.list[0] = arg.type;
+ get_locals_using_stmt(file, using_stmt, ast_context);
+ }
+ }
+ }
+ }
+ }
- if !ok {
- log.error("Proc_List body not block");
- return;
- }
+ block: ast.Block_Stmt;
+ block, ok = proc_lit.body.derived.(ast.Block_Stmt);
- for stmt in block.stmts {
- get_locals_stmt(file, stmt, ast_context, document_position);
- }
+ if !ok {
+ log.error("Proc_List body not block");
+ return;
+ }
+ for stmt in block.stmts {
+ get_locals_stmt(file, stmt, ast_context, document_position);
+ }
}
-clear_locals :: proc(ast_context: ^AstContext) {
- clear(&ast_context.locals);
- clear(&ast_context.parameters);
- clear(&ast_context.variables);
- clear(&ast_context.usings);
+clear_locals :: proc (ast_context: ^AstContext) {
+ clear(&ast_context.locals);
+ clear(&ast_context.parameters);
+ clear(&ast_context.variables);
+ clear(&ast_context.usings);
}
-concatenate_symbols_information :: proc(ast_context: ^AstContext, symbol: index.Symbol) -> string {
-
- pkg := path.base(symbol.pkg, false, context.temp_allocator);
-
- if symbol.type == .Function {
-
- if symbol.returns != "" {
- return fmt.tprintf("%v.%v: proc %v -> %v", pkg, symbol.name, symbol.signature, symbol.returns);
- }
-
- else {
- return fmt.tprintf("%v.%v: proc%v", pkg, symbol.name, symbol.signature);
- }
+concatenate_symbols_information :: proc (ast_context: ^AstContext, symbol: index.Symbol) -> string {
- }
+ pkg := path.base(symbol.pkg, false, context.temp_allocator);
- else if symbol.type == .Package {
- return symbol.name;
- }
+ if symbol.type == .Function {
- else {
+ if symbol.returns != "" {
+ return fmt.tprintf("%v.%v: proc %v -> %v", pkg, symbol.name, symbol.signature, symbol.returns);
+ } else {
+ return fmt.tprintf("%v.%v: proc%v", pkg, symbol.name, symbol.signature);
+ }
+ } else if symbol.type == .Package {
+ return symbol.name;
+ } else {
- if symbol.signature != "" {
- return fmt.tprintf("%v.%v: %v", pkg, symbol.name, symbol.signature);
- }
-
- else {
- return fmt.tprintf("%v.%v", pkg, symbol.name);
- }
-
- }
+ if symbol.signature != "" {
+ return fmt.tprintf("%v.%v: %v", pkg, symbol.name, symbol.signature);
+ } else {
+ return fmt.tprintf("%v.%v", pkg, symbol.name);
+ }
+ }
- return ""; //weird bug requires this
+ return ""; //weird bug requires this
}
-get_definition_location :: proc(document: ^Document, position: common.Position) -> (common.Location, bool) {
-
- location: common.Location;
-
- ast_context := make_ast_context(document.ast, document.imports, document.package_name);
-
- uri: string;
-
- position_context, ok := get_document_position_context(document, position, .Definition);
-
- if !ok {
- log.warn("Failed to get position context");
- return location, false;
- }
-
- get_globals(document.ast, &ast_context);
-
- if position_context.function != nil {
- get_locals(document.ast, position_context.function, &ast_context, &position_context);
- }
-
- if position_context.selector != 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 {
-
- ident := position_context.identifier.derived.(ast.Ident);
-
- if ident.name == base.name {
-
- if resolved, ok := resolve_location_identifier(&ast_context, ident); ok {
- location.range = resolved.range;
-
- if resolved.uri == "" {
- location.uri = document.uri.uri;
- }
-
- else {
- location.uri = resolved.uri;
- }
-
- return location, true;
- }
-
- else {
- return location, false;
- }
+get_definition_location :: proc (document: ^Document, position: common.Position) -> (common.Location, bool) {
- }
+ location: common.Location;
- }
+ ast_context := make_ast_context(document.ast, document.imports, document.package_name);
- //otherwise it's the field the client wants to go to.
+ uri: string;
- selector: index.Symbol;
+ position_context, ok := get_document_position_context(document, position, .Definition);
- ast_context.use_locals = true;
- ast_context.use_globals = true;
- ast_context.current_package = ast_context.document_package;
-
- selector, ok = resolve_type_expression(&ast_context, position_context.selector);
-
- if !ok {
- return location, false;
- }
-
- field: string;
-
- if position_context.field != nil {
-
- switch v in position_context.field.derived {
- case ast.Ident:
- field = v.name;
- }
-
- }
-
- uri = selector.uri;
-
- #partial switch v in selector.value {
- case index.SymbolEnumValue:
- location.range = selector.range;
- case index.SymbolStructValue:
- for name, i in v.names {
- if strings.compare(name, field) == 0 {
- location.range = common.get_token_range(v.types[i]^, document.ast.src);
- }
- }
- case index.SymbolPackageValue:
- if symbol, ok := index.lookup(field, selector.pkg); ok {
- location.range = symbol.range;
- uri = symbol.uri;
- }
- else {
- return location, false;
- }
- }
-
- if !ok {
- return location, false;
- }
-
- }
-
- else if position_context.identifier != nil {
-
- if resolved, ok := resolve_location_identifier(&ast_context, position_context.identifier.derived.(ast.Ident)); ok {
- location.range = resolved.range;
- uri = resolved.uri;
- }
-
- else {
- return location, false;
- }
+ if !ok {
+ log.warn("Failed to get position context");
+ return location, false;
+ }
- }
+ get_globals(document.ast, &ast_context);
- else {
- return location, false;
- }
+ if position_context.function != nil {
+ get_locals(document.ast, position_context.function, &ast_context, &position_context);
+ }
- //if the symbol is generated by the ast we don't set the uri.
- if uri == "" {
- location.uri = document.uri.uri;
- }
+ if position_context.selector != 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 {
+
+ ident := position_context.identifier.derived.(ast.Ident);
+
+ if ident.name == base.name {
+
+ if resolved, ok := resolve_location_identifier(&ast_context, ident); ok {
+ location.range = resolved.range;
+
+ if resolved.uri == "" {
+ location.uri = document.uri.uri;
+ } else {
+ location.uri = resolved.uri;
+ }
+
+ return location, true;
+ } else {
+ return location, false;
+ }
+ }
+ }
+
+ //otherwise it's the field the client wants to go to.
+
+ selector: index.Symbol;
+
+ ast_context.use_locals = true;
+ ast_context.use_globals = true;
+ ast_context.current_package = ast_context.document_package;
+
+ selector, ok = resolve_type_expression(&ast_context, position_context.selector);
+
+ if !ok {
+ return location, false;
+ }
+
+ field: string;
+
+ if position_context.field != nil {
+
+ switch v in position_context.field.derived {
+ case ast.Ident:
+ field = v.name;
+ }
+ }
+
+ uri = selector.uri;
+
+ #partial switch v in selector.value {
+ case index.SymbolEnumValue:
+ location.range = selector.range;
+ case index.SymbolStructValue:
+ for name, i in v.names {
+ if strings.compare(name, field) == 0 {
+ location.range = common.get_token_range(v.types[i]^, document.ast.src);
+ }
+ }
+ case index.SymbolPackageValue:
+ if symbol, ok := index.lookup(field, selector.pkg); ok {
+ location.range = symbol.range;
+ uri = symbol.uri;
+ } else {
+ return location, false;
+ }
+ }
+
+ if !ok {
+ return location, false;
+ }
+ } else if position_context.identifier != nil {
+
+ if resolved, ok := resolve_location_identifier(&ast_context, position_context.identifier.derived.(ast.Ident)); ok {
+ location.range = resolved.range;
+ uri = resolved.uri;
+ } else {
+ return location, false;
+ }
+ } else {
+ return location, false;
+ }
- else {
- location.uri = uri;
- }
+ //if the symbol is generated by the ast we don't set the uri.
+ if uri == "" {
+ location.uri = document.uri.uri;
+ } else {
+ location.uri = uri;
+ }
- return location, true;
+ return location, true;
}
-write_hover_content :: proc(ast_context: ^AstContext, symbol: index.Symbol) -> MarkupContent {
- content: MarkupContent;
+write_hover_content :: proc (ast_context: ^AstContext, symbol: index.Symbol) -> MarkupContent {
+ content: MarkupContent;
- cat := concatenate_symbols_information(ast_context, symbol);
+ cat := concatenate_symbols_information(ast_context, symbol);
- if cat != "" {
- content.kind = "markdown";
- content.value = fmt.tprintf("```odin\n %v\n```\n%v", cat, symbol.doc);
- }
-
- else {
- content.kind = "plaintext";
- }
+ if cat != "" {
+ content.kind = "markdown";
+ content.value = fmt.tprintf("```odin\n %v\n```\n%v", cat, symbol.doc);
+ } else {
+ content.kind = "plaintext";
+ }
- return content;
+ return content;
}
-get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: index.Symbol, was_variable := false) -> string {
+get_signature :: proc (ast_context: ^AstContext, ident: ast.Ident, symbol: index.Symbol, was_variable := false) -> string {
- if symbol.type == .Function {
- return symbol.signature;
- }
-
- if is_variable, ok := ast_context.variables[ident.name]; ok && is_variable {
-
- if local := get_local(ast_context, ident.pos.offset, ident.name); local != nil {
-
- if i, ok := local.derived.(ast.Ident); ok {
- return get_signature(ast_context, i, symbol, true);
- }
+ if symbol.type == .Function {
+ return symbol.signature;
+ }
- else {
- return index.node_to_string(local);
- }
- }
+ if is_variable, ok := ast_context.variables[ident.name]; ok && is_variable {
- if global, ok := ast_context.globals[ident.name]; ok {
- if i, ok := global.derived.(ast.Ident); ok {
- return get_signature(ast_context, i, symbol, true);
- }
+ if local := get_local(ast_context, ident.pos.offset, ident.name); local != nil {
- else {
- return index.node_to_string(global);
- }
- }
+ if i, ok := local.derived.(ast.Ident); ok {
+ return get_signature(ast_context, i, symbol, true);
+ } else {
+ return index.node_to_string(local);
+ }
+ }
- }
+ if global, ok := ast_context.globals[ident.name]; ok {
+ if i, ok := global.derived.(ast.Ident); ok {
+ return get_signature(ast_context, i, symbol, true);
+ } else {
+ return index.node_to_string(global);
+ }
+ }
+ }
- if !was_variable {
- #partial switch v in symbol.value {
- case index.SymbolStructValue:
- return "struct";
- case index.SymbolUnionValue:
- return "union";
- case index.SymbolEnumValue:
- return "enum";
- }
- }
+ if !was_variable {
+ #partial switch v in symbol.value {
+ case index.SymbolStructValue:
+ return "struct";
+ case index.SymbolUnionValue:
+ return "union";
+ case index.SymbolEnumValue:
+ return "enum";
+ }
+ }
- return ident.name;
+ return ident.name;
}
-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;
+ signature_help: SignatureHelp;
- ast_context := make_ast_context(document.ast, document.imports, document.package_name);
+ ast_context := make_ast_context(document.ast, document.imports, document.package_name);
- 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;
- }
+ if !ok {
+ return signature_help, true;
+ }
- if position_context.call == nil {
- return signature_help, true;
- }
+ if position_context.call == nil {
+ return signature_help, true;
+ }
- get_globals(document.ast, &ast_context);
+ get_globals(document.ast, &ast_context);
- if position_context.function != nil {
- get_locals(document.ast, position_context.function, &ast_context, &position_context);
- }
+ if position_context.function != nil {
+ get_locals(document.ast, position_context.function, &ast_context, &position_context);
+ }
- call: index.Symbol;
- call, ok = resolve_type_expression(&ast_context, position_context.call);
+ call: index.Symbol;
+ call, ok = resolve_type_expression(&ast_context, position_context.call);
- if symbol, ok := call.value.(index.SymbolProcedureValue); !ok {
- return signature_help, true;
- }
+ if symbol, ok := call.value.(index.SymbolProcedureValue); !ok {
+ return signature_help, true;
+ }
- signature_information := make([] SignatureInformation, 1, context.temp_allocator);
+ signature_information := make([]SignatureInformation, 1, context.temp_allocator);
- signature_information[0].label = concatenate_symbols_information(&ast_context, call);
- signature_information[0].documentation = call.doc;
+ signature_information[0].label = concatenate_symbols_information(&ast_context, call);
+ signature_information[0].documentation = call.doc;
- signature_help.signatures = signature_information;
+ signature_help.signatures = signature_information;
- return signature_help, true;
+ return signature_help, true;
}
-get_document_symbols :: proc(document: ^Document) -> [] DocumentSymbol {
+get_document_symbols :: proc (document: ^Document) -> []DocumentSymbol {
- ast_context := make_ast_context(document.ast, document.imports, document.package_name);
+ ast_context := make_ast_context(document.ast, document.imports, document.package_name);
- get_globals(document.ast, &ast_context);
+ get_globals(document.ast, &ast_context);
- symbols := make([dynamic] DocumentSymbol, context.temp_allocator);
+ symbols := make([dynamic]DocumentSymbol, context.temp_allocator);
- package_symbol: DocumentSymbol;
+ package_symbol: DocumentSymbol;
- if len(document.ast.decls) == 0 {
- return {};
- }
-
- package_symbol.kind = .Package;
- package_symbol.name = path.base(document.package_name, false, context.temp_allocator);
- package_symbol.range = {
- start = {
- line = document.ast.decls[0].pos.line,
- },
- end = {
- line = document.ast.decls[len(document.ast.decls)-1].end.line,
- },
- };
- package_symbol.selectionRange = package_symbol.range;
-
- children_symbols := make([dynamic] DocumentSymbol, context.temp_allocator);
-
- for k, expr in ast_context.globals {
-
- symbol: DocumentSymbol;
-
- symbol.range = common.get_token_range(expr, ast_context.file.src);
- symbol.selectionRange = symbol.range;
- symbol.name = k;
-
- switch v in expr.derived {
- case ast.Struct_Type:
- symbol.kind = .Struct;
- case ast.Proc_Lit, ast.Proc_Group:
- symbol.kind = .Function;
- case ast.Enum_Type, ast.Union_Type:
- symbol.kind = .Enum;
- case:
- symbol.kind = .Variable;
- }
+ if len(document.ast.decls) == 0 {
+ return {};
+ }
- append(&children_symbols, symbol);
- }
+ package_symbol.kind = .Package;
+ package_symbol.name = path.base(document.package_name, false, context.temp_allocator);
+ package_symbol.range = {
+ start = {
+ line = document.ast.decls[0].pos.line
+ },
+ end = {
+ line = document.ast.decls[len(document.ast.decls) - 1].end.line
+ },
+ };
+ package_symbol.selectionRange = package_symbol.range;
+
+ children_symbols := make([dynamic]DocumentSymbol, context.temp_allocator);
+
+ for k, expr in ast_context.globals {
+
+ symbol: DocumentSymbol;
+
+ symbol.range = common.get_token_range(expr, ast_context.file.src);
+ symbol.selectionRange = symbol.range;
+ symbol.name = k;
+
+ switch v in expr.derived {
+ case ast.Struct_Type:
+ symbol.kind = .Struct;
+ case ast.Proc_Lit,ast.Proc_Group:
+ symbol.kind = .Function;
+ case ast.Enum_Type,ast.Union_Type:
+ symbol.kind = .Enum;
+ case:
+ symbol.kind = .Variable;
+ }
+
+ append(&children_symbols, symbol);
+ }
- package_symbol.children = children_symbols[:];
+ package_symbol.children = children_symbols[:];
- append(&symbols, package_symbol);
+ append(&symbols, package_symbol);
- return symbols[:];
+ return symbols[:];
}
/*
- All these fallback functions are not perfect and should be fixed. A lot of weird use of the odin tokenizer and parser.
+ All these fallback functions are not perfect and should be fixed. A lot of weird use of the odin tokenizer and parser.
*/
/*
- Figure out what exactly is at the given position and whether it is in a function, struct, etc.
+ 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) {
-
- position_context: DocumentPositionContext;
+get_document_position_context :: proc (document: ^Document, position: common.Position, hint: DocumentPositionContextHint) -> (DocumentPositionContext, bool) {
- position_context.hint = hint;
- position_context.file = document.ast;
- position_context.line = position.line;
+ position_context: DocumentPositionContext;
- absolute_position, ok := common.get_absolute_position(position, document.text);
+ position_context.hint = hint;
+ position_context.file = document.ast;
+ position_context.line = position.line;
- if !ok {
- log.error("failed to get absolute position");
- return position_context, false;
- }
+ absolute_position, ok := common.get_absolute_position(position, document.text);
- position_context.position = absolute_position;
+ if !ok {
+ log.error("failed to get absolute position");
+ return position_context, false;
+ }
- for decl in document.ast.decls {
- get_document_position(decl, &position_context);
- }
+ position_context.position = absolute_position;
- if hint == .Completion && position_context.selector == nil && position_context.field == nil {
- fallback_position_context_completion(document, position, &position_context);
- }
+ for decl in document.ast.decls {
+ get_document_position(decl, &position_context);
+ }
- else if hint == .SignatureHelp && position_context.call == nil {
- fallback_position_context_signature(document, position, &position_context);
- }
+ if hint == .Completion && position_context.selector == nil && position_context.field == nil {
+ fallback_position_context_completion(document, position, &position_context);
+ } else if hint == .SignatureHelp && position_context.call == nil {
+ fallback_position_context_signature(document, position, &position_context);
+ }
- return position_context, true;
+ return position_context, true;
}
+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;
+
+ i := position_context.position - 1;
+
+ end = i;
+
+ for i > 0 {
+
+ c := position_context.file.src[i];
+
+ if c == '(' && paren_count == 0 {
+ start = i + 1;
+ break;
+ } else if c == '[' && bracket_count == 0 {
+ start = i + 1;
+ break;
+ } else if c == ']' && !last_dot {
+ start = i + 1;
+ break;
+ } else if c == ')' && !last_dot {
+ start = i + 1;
+ break;
+ } else if c == ')' {
+ paren_count -= 1;
+ } else if c == '(' {
+ paren_count += 1;
+ } else if c == '[' {
+ bracket_count += 1;
+ } else if c == ']' {
+ bracket_count -= 1;
+ } else if c == '.' {
+ last_dot = true;
+ i -= 1;
+ continue;
+ } else if position_context.file.src[max(0, i - 1)] == '-' && c == '>' {
+ last_arrow = true;
+ i -= 2;
+ continue;
+ }
+
+ //yeah..
+ if c == ' ' || c == '{' || c == ',' ||
+ c == '}' || c == '^' || c == ':' ||
+ c == '\n' || c == '\r' || c == '=' ||
+ c == '<' || c == '>' || c == '-' ||
+ c == '+' || c == '&' {
+ start = i + 1;
+ break;
+ }
+
+ last_dot = false;
+ last_arrow = false;
+
+ i -= 1;
+ }
-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;
-
- i := position_context.position-1;
-
- end = i;
-
- for i > 0 {
-
- c := position_context.file.src[i];
-
- if c == '(' && paren_count == 0 {
- start = i+1;
- break;
- }
-
- else if c == '[' && bracket_count == 0 {
- start = i+1;
- break;
- }
-
- else if c == ']' && !last_dot {
- start = i+1;
- break;
- }
-
- else if c == ')' && !last_dot {
- start = i+1;
- break;
- }
-
- else if c == ')' {
- paren_count -= 1;
- }
-
- else if c == '(' {
- paren_count += 1;
- }
-
- else if c == '[' {
- bracket_count += 1;
- }
-
- else if c == ']' {
- bracket_count -= 1;
- }
-
- else if c == '.' {
- last_dot = true;
- i -= 1;
- continue;
- }
-
- else if position_context.file.src[max(0, i-1)] == '-' && c == '>' {
- last_arrow = true;
- i -= 2;
- continue;
- }
-
- //yeah..
- if c == ' ' || c == '{' || c == ',' ||
- c == '}' || c == '^' || c == ':' ||
- c == '\n' || c == '\r' || c == '=' ||
- c == '<' || c == '>' || c == '-' ||
- c == '+' || c == '&' {
- start = i+1;
- break;
- }
-
- last_dot = false;
- last_arrow = false;
-
- i -= 1;
- }
-
- 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] == '>' {
- empty_arrow = true;
- end -= 2;
- position_context.arrow = true;
- }
-
- begin_offset := max(0, start);
- end_offset := max(start, end+1);
-
- str := position_context.file.src[0:end_offset];
-
- if empty_dot && end_offset - begin_offset == 0 {
- position_context.implicit = true;
- return;
- }
-
- p := parser.Parser {
- err = parser_warning_handler, //empty
- warn = parser_warning_handler, //empty
- file = &position_context.file,
- };
-
- tokenizer.init(&p.tok, str, position_context.file.fullpath, parser_warning_handler);
+ 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] == '>' {
+ empty_arrow = true;
+ end -= 2;
+ position_context.arrow = true;
+ }
- p.tok.ch = ' ';
- p.tok.line_count = position.line;
- p.tok.offset = begin_offset;
- p.tok.read_offset = begin_offset;
+ begin_offset := max(0, start);
+ end_offset := max(start, end + 1);
- tokenizer.advance_rune(&p.tok);
+ str := position_context.file.src[0:end_offset];
- if p.tok.ch == utf8.RUNE_BOM {
- tokenizer.advance_rune(&p.tok);
+ if empty_dot && end_offset - begin_offset == 0 {
+ position_context.implicit = true;
+ return;
}
- parser.advance_token(&p);
-
- context.allocator = context.temp_allocator;
+ p := parser.Parser {
+ err = parser_warning_handler, //empty
+ warn = parser_warning_handler, //empty
+ file = &position_context.file,
+ };
- e := parser.parse_expr(&p, true);
+ tokenizer.init(&p.tok, str, position_context.file.fullpath, parser_warning_handler);
- if empty_dot || empty_arrow {
- position_context.selector = e;
- }
+ p.tok.ch = ' ';
+ p.tok.line_count = position.line;
+ p.tok.offset = begin_offset;
+ p.tok.read_offset = begin_offset;
- else if s, ok := e.derived.(ast.Selector_Expr); ok {
- position_context.selector = s.expr;
- position_context.field = s.field;
- }
+ tokenizer.advance_rune(&p.tok);
- else if s, ok := e.derived.(ast.Implicit_Selector_Expr); ok {
- position_context.implicit = true;
- }
+ if p.tok.ch == utf8.RUNE_BOM {
+ tokenizer.advance_rune(&p.tok);
+ }
- else if bad_expr, ok := e.derived.(ast.Bad_Expr); ok {
- //this is most likely because of use of 'in', 'context', etc.
- //try to go back one dot.
+ parser.advance_token(&p);
- src_with_dot := string(position_context.file.src[0:end_offset+1]);
- last_dot := strings.last_index(src_with_dot, ".");
+ context.allocator = context.temp_allocator;
- if last_dot == -1 {
- return;
- }
+ e := parser.parse_expr(&p, true);
- tokenizer.init(&p.tok, position_context.file.src[0:last_dot], position_context.file.fullpath, parser_warning_handler);
+ if empty_dot || empty_arrow {
+ position_context.selector = e;
+ } else if s, ok := e.derived.(ast.Selector_Expr); ok {
+ position_context.selector = s.expr;
+ position_context.field = s.field;
+ } else if s, ok := e.derived.(ast.Implicit_Selector_Expr); ok {
+ position_context.implicit = true;
+ } else if bad_expr, ok := e.derived.(ast.Bad_Expr); ok {
+ //this is most likely because of use of 'in', 'context', etc.
+ //try to go back one dot.
- p.tok.ch = ' ';
- p.tok.line_count = position.line;
- p.tok.offset = begin_offset;
- p.tok.read_offset = begin_offset;
+ src_with_dot := string(position_context.file.src[0:end_offset + 1]);
+ last_dot := strings.last_index(src_with_dot, ".");
- tokenizer.advance_rune(&p.tok);
+ if last_dot == -1 {
+ return;
+ }
- if p.tok.ch == utf8.RUNE_BOM {
- tokenizer.advance_rune(&p.tok);
- }
+ tokenizer.init(&p.tok, position_context.file.src[0:last_dot], position_context.file.fullpath, parser_warning_handler);
- parser.advance_token(&p);
+ p.tok.ch = ' ';
+ p.tok.line_count = position.line;
+ p.tok.offset = begin_offset;
+ p.tok.read_offset = begin_offset;
- e := parser.parse_expr(&p, true);
+ tokenizer.advance_rune(&p.tok);
- if e == nil {
- return;
- }
+ if p.tok.ch == utf8.RUNE_BOM {
+ tokenizer.advance_rune(&p.tok);
+ }
- position_context.selector = e;
+ parser.advance_token(&p);
- ident := index.new_type(ast.Ident, e.pos, e.end, context.temp_allocator);
- ident.name = string(position_context.file.src[last_dot+1:end_offset]);
+ e := parser.parse_expr(&p, true);
- if ident.name != "" {
- position_context.field = ident;
- }
+ if e == nil {
+ return;
+ }
- }
+ position_context.selector = e;
- else {
- position_context.identifier = e;
- }
+ ident := index.new_type(ast.Ident, e.pos, e.end, context.temp_allocator);
+ ident.name = string(position_context.file.src[last_dot + 1:end_offset]);
+ if ident.name != "" {
+ position_context.field = ident;
+ }
+ } else {
+ position_context.identifier = e;
+ }
}
-fallback_position_context_signature :: proc(document: ^Document, position: common.Position, position_context: ^DocumentPositionContext) {
-
- paren_count: int;
- end: int;
- start: int;
- first_paren: bool;
- i := position_context.position-1;
-
- for i > 0 {
-
- c := position_context.file.src[i];
-
- if c == '(' && (paren_count == 0 || paren_count == -1) {
- end = i;
- first_paren = true;
- }
-
- else if c == ')' {
- paren_count -= 1;
- }
-
- else if c == '(' {
- paren_count += 1;
- }
-
- else if c == ' ' && end != 0 {
- start = i+1;
- break;
- }
- //not good enough if you want multi function signature help
- else if c == '\n' || c == '\r' {
- start = i+1;
- break;
- }
-
- i -= 1;
- }
+fallback_position_context_signature :: proc (document: ^Document, position: common.Position, position_context: ^DocumentPositionContext) {
+
+ paren_count: int;
+ end: int;
+ start: int;
+ first_paren: bool;
+ i := position_context.position - 1;
+
+ for i > 0 {
+
+ c := position_context.file.src[i];
+
+ if c == '(' && (paren_count == 0 || paren_count == -1) {
+ end = i;
+ first_paren = true;
+ } else if c == ')' {
+ paren_count -= 1;
+ } else if c == '(' {
+ paren_count += 1;
+ } else if c == ' ' && end != 0 {
+ start = i + 1;
+ break;
+ } else
+ //not good enough if you want multi function signature help
+ if c == '\n' || c == '\r' {
+ start = i + 1;
+ break;
+ }
+
+ i -= 1;
+ }
- if !first_paren {
- return;
- }
+ if !first_paren {
+ return;
+ }
- begin_offset := max(0, start);
- end_offset := max(start, end+1);
+ begin_offset := max(0, start);
+ end_offset := max(start, end + 1);
- str := position_context.file.src[0:end_offset];
+ str := position_context.file.src[0:end_offset];
- p := parser.Parser {
- err = parser_warning_handler, //empty
+ p := parser.Parser {
+ err = parser_warning_handler, //empty
warn = parser_warning_handler, //empty
- file = &position_context.file,
+ file = &position_context.file,
};
- tokenizer.init(&p.tok, str, position_context.file.fullpath, parser_warning_handler);
+ tokenizer.init(&p.tok, str, position_context.file.fullpath, parser_warning_handler);
- p.tok.ch = ' ';
- p.tok.line_count = position.line;
- p.tok.offset = begin_offset;
- p.tok.read_offset = begin_offset;
+ p.tok.ch = ' ';
+ p.tok.line_count = position.line;
+ p.tok.offset = begin_offset;
+ p.tok.read_offset = begin_offset;
- tokenizer.advance_rune(&p.tok);
+ tokenizer.advance_rune(&p.tok);
if p.tok.ch == utf8.RUNE_BOM {
tokenizer.advance_rune(&p.tok);
}
- parser.advance_token(&p);
+ parser.advance_token(&p);
- context.allocator = context.temp_allocator;
+ context.allocator = context.temp_allocator;
- e := parser.parse_expr(&p, true);
+ e := parser.parse_expr(&p, true);
- position_context.call = e;
+ position_context.call = e;
}
+get_document_position :: proc {
+get_document_position_array,
+get_document_position_dynamic_array,
+get_document_position_node};
-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);
+ }
+}
- for elem, i in array {
- get_document_position(elem, position_context);
- }
+get_document_position_dynamic_array :: proc (array: $A/[dynamic]^$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) {
+position_in_node :: proc (node: ^ast.Node, position: common.AbsolutePosition) -> bool {
+ return node != nil && node.pos.offset <= position && position <= node.end.offset;
+}
- for elem, i in array {
- get_document_position(elem, position_context);
- }
+get_document_position_node :: proc (node: ^ast.Node, position_context: ^DocumentPositionContext) {
-}
+ using ast;
-position_in_node :: proc(node: ^ast.Node, position: common.AbsolutePosition) -> bool {
- return node != nil && node.pos.offset <= position && position <= node.end.offset;
-}
+ if node == nil {
+ return;
+ }
-get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentPositionContext) {
-
- using ast;
-
- if node == nil {
- return;
- }
-
- if !position_in_node(node, position_context.position) {
- return;
- }
-
- switch n in node.derived {
- case Bad_Expr:
- case Ident:
- position_context.identifier = node;
- case Implicit:
- case Undef:
- case Basic_Lit:
- case Ellipsis:
- get_document_position(n.expr, position_context);
- case Proc_Lit:
- get_document_position(n.type, position_context);
-
- 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 {
- position_context.parent_comp_lit = cast(^Comp_Lit)node;
- }
-
- position_context.comp_lit = cast(^Comp_Lit)node;
-
- get_document_position(n.type, position_context);
- get_document_position(n.elems, position_context);
- case Tag_Expr:
- get_document_position(n.expr, position_context);
- case Unary_Expr:
- get_document_position(n.expr, position_context);
- case Binary_Expr:
- position_context.binary = cast(^Binary_Expr)node;
- get_document_position(n.left, position_context);
- get_document_position(n.right, position_context);
- case Paren_Expr:
- get_document_position(n.expr, position_context);
- case Call_Expr:
- if position_context.hint == .SignatureHelp {
- 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 == position_context.line {
- position_context.selector = n.expr;
- position_context.field = n.field;
- }
- }
-
- else if (position_context.hint == .Definition || position_context.hint == .Hover) && n.field != nil {
- position_context.selector = n.expr;
- position_context.field = n.field;
- get_document_position(n.expr, position_context);
- get_document_position(n.field, position_context);
- }
-
- else {
- get_document_position(n.expr, position_context);
- get_document_position(n.field, position_context);
- }
- case Index_Expr:
- get_document_position(n.expr, position_context);
- get_document_position(n.index, position_context);
- case Deref_Expr:
- get_document_position(n.expr, position_context);
- case Slice_Expr:
- get_document_position(n.expr, position_context);
- get_document_position(n.low, position_context);
- get_document_position(n.high, position_context);
- case Field_Value:
- get_document_position(n.field, position_context);
- get_document_position(n.value, position_context);
- case Ternary_Expr:
- get_document_position(n.cond, position_context);
- get_document_position(n.x, position_context);
- get_document_position(n.y, position_context);
- case Ternary_If_Expr:
- get_document_position(n.x, position_context);
- get_document_position(n.cond, position_context);
- get_document_position(n.y, position_context);
- case Ternary_When_Expr:
- get_document_position(n.x, position_context);
- get_document_position(n.cond, position_context);
- get_document_position(n.y, position_context);
- case Type_Assertion:
- get_document_position(n.expr, position_context);
- get_document_position(n.type, position_context);
- case Type_Cast:
- get_document_position(n.type, position_context);
- get_document_position(n.expr, position_context);
- case Auto_Cast:
- get_document_position(n.expr, position_context);
- case Bad_Stmt:
- case Empty_Stmt:
- case Expr_Stmt:
- get_document_position(n.expr, position_context);
- case Tag_Stmt:
- r := cast(^Tag_Stmt)node;
- get_document_position(r.stmt, position_context);
- case Assign_Stmt:
- position_context.assign = cast(^Assign_Stmt)node;
- get_document_position(n.lhs, position_context);
- get_document_position(n.rhs, position_context);
- case Block_Stmt:
- get_document_position(n.label, position_context);
- get_document_position(n.stmts, position_context);
- case If_Stmt:
- get_document_position(n.label, position_context);
- get_document_position(n.init, position_context);
- get_document_position(n.cond, position_context);
- get_document_position(n.body, position_context);
- get_document_position(n.else_stmt, position_context);
- case When_Stmt:
- get_document_position(n.cond, position_context);
- get_document_position(n.body, position_context);
- get_document_position(n.else_stmt, position_context);
- case Return_Stmt:
- position_context.returns = cast(^Return_Stmt)node;
- get_document_position(n.results, position_context);
- case Defer_Stmt:
- get_document_position(n.stmt, position_context);
- case For_Stmt:
- get_document_position(n.label, position_context);
- get_document_position(n.init, position_context);
- get_document_position(n.cond, position_context);
- get_document_position(n.post, position_context);
- get_document_position(n.body, position_context);
- case Range_Stmt:
- get_document_position(n.label, position_context);
- get_document_position(n.val0, position_context);
- get_document_position(n.val1, position_context);
- get_document_position(n.expr, position_context);
- get_document_position(n.body, position_context);
- case Case_Clause:
- position_context.case_clause = cast(^Case_Clause)node;
- get_document_position(n.list, position_context);
- get_document_position(n.body, position_context);
- case Switch_Stmt:
- position_context.switch_stmt = cast(^Switch_Stmt)node;
- get_document_position(n.label, position_context);
- get_document_position(n.init, position_context);
- get_document_position(n.cond, position_context);
- get_document_position(n.body, position_context);
- case Type_Switch_Stmt:
- position_context.switch_type_stmt = cast(^Type_Switch_Stmt)node;
- get_document_position(n.label, position_context);
- get_document_position(n.tag, position_context);
- get_document_position(n.expr, position_context);
- get_document_position(n.body, position_context);
- case Branch_Stmt:
- get_document_position(n.label, position_context);
- case Using_Stmt:
- get_document_position(n.list, position_context);
- case Bad_Decl:
- case Value_Decl:
- position_context.value_decl = cast(^Value_Decl)node;
- get_document_position(n.attributes, position_context);
- get_document_position(n.names, position_context);
- get_document_position(n.type, position_context);
- get_document_position(n.values, position_context);
- case Package_Decl:
- case Import_Decl:
- case Foreign_Block_Decl:
- get_document_position(n.attributes, position_context);
- get_document_position(n.foreign_library, position_context);
- get_document_position(n.body, position_context);
- case Foreign_Import_Decl:
- get_document_position(n.name, position_context);
- case Proc_Group:
- get_document_position(n.args, position_context);
- case Attribute:
- get_document_position(n.elems, position_context);
- case Field:
- get_document_position(n.names, position_context);
- get_document_position(n.type, position_context);
- get_document_position(n.default_value, position_context);
- case Field_List:
- get_document_position(n.list, position_context);
- case Typeid_Type:
- get_document_position(n.specialization, position_context);
- case Helper_Type:
- get_document_position(n.type, position_context);
- case Distinct_Type:
- get_document_position(n.type, position_context);
- case Poly_Type:
- get_document_position(n.type, position_context);
- get_document_position(n.specialization, position_context);
- case Proc_Type:
- get_document_position(n.params, position_context);
- get_document_position(n.results, position_context);
- case Pointer_Type:
- get_document_position(n.elem, position_context);
- case Array_Type:
- get_document_position(n.len, position_context);
- get_document_position(n.elem, position_context);
- case Dynamic_Array_Type:
- get_document_position(n.elem, position_context);
- case Struct_Type:
- get_document_position(n.poly_params, position_context);
- get_document_position(n.align, position_context);
- get_document_position(n.fields, position_context);
- case Union_Type:
- get_document_position(n.poly_params, position_context);
- get_document_position(n.align, position_context);
- get_document_position(n.variants, position_context);
- case Enum_Type:
- get_document_position(n.base_type, position_context);
- get_document_position(n.fields, position_context);
- case Bit_Set_Type:
- get_document_position(n.elem, position_context);
- get_document_position(n.underlying, position_context);
- case Map_Type:
- get_document_position(n.key, position_context);
- get_document_position(n.value, position_context);
- case Implicit_Selector_Expr:
- position_context.implicit = true;
- get_document_position(n.field, position_context);
- case:
- log.errorf("Unhandled node kind: %T", n);
- }
+ if !position_in_node(node, position_context.position) {
+ return;
+ }
+ switch n in node.derived {
+ case Bad_Expr:
+ case Ident:
+ position_context.identifier = node;
+ case Implicit:
+ case Undef:
+ case Basic_Lit:
+ case Ellipsis:
+ get_document_position(n.expr, position_context);
+ case Proc_Lit:
+ get_document_position(n.type, position_context);
+
+ 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 {
+ position_context.parent_comp_lit = cast(^Comp_Lit)node;
+ }
+
+ position_context.comp_lit = cast(^Comp_Lit)node;
+
+ get_document_position(n.type, position_context);
+ get_document_position(n.elems, position_context);
+ case Tag_Expr:
+ get_document_position(n.expr, position_context);
+ case Unary_Expr:
+ get_document_position(n.expr, position_context);
+ case Binary_Expr:
+ position_context.binary = cast(^Binary_Expr)node;
+ get_document_position(n.left, position_context);
+ get_document_position(n.right, position_context);
+ case Paren_Expr:
+ get_document_position(n.expr, position_context);
+ case Call_Expr:
+ if position_context.hint == .SignatureHelp {
+ 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 == position_context.line {
+ position_context.selector = n.expr;
+ position_context.field = n.field;
+ }
+ } else if (position_context.hint == .Definition || position_context.hint == .Hover) && n.field != nil {
+ position_context.selector = n.expr;
+ position_context.field = n.field;
+ get_document_position(n.expr, position_context);
+ get_document_position(n.field, position_context);
+ } else {
+ get_document_position(n.expr, position_context);
+ get_document_position(n.field, position_context);
+ }
+ case Index_Expr:
+ get_document_position(n.expr, position_context);
+ get_document_position(n.index, position_context);
+ case Deref_Expr:
+ get_document_position(n.expr, position_context);
+ case Slice_Expr:
+ get_document_position(n.expr, position_context);
+ get_document_position(n.low, position_context);
+ get_document_position(n.high, position_context);
+ case Field_Value:
+ get_document_position(n.field, position_context);
+ get_document_position(n.value, position_context);
+ case Ternary_Expr:
+ get_document_position(n.cond, position_context);
+ get_document_position(n.x, position_context);
+ get_document_position(n.y, position_context);
+ case Ternary_If_Expr:
+ get_document_position(n.x, position_context);
+ get_document_position(n.cond, position_context);
+ get_document_position(n.y, position_context);
+ case Ternary_When_Expr:
+ get_document_position(n.x, position_context);
+ get_document_position(n.cond, position_context);
+ get_document_position(n.y, position_context);
+ case Type_Assertion:
+ get_document_position(n.expr, position_context);
+ get_document_position(n.type, position_context);
+ case Type_Cast:
+ get_document_position(n.type, position_context);
+ get_document_position(n.expr, position_context);
+ case Auto_Cast:
+ get_document_position(n.expr, position_context);
+ case Bad_Stmt:
+ case Empty_Stmt:
+ case Expr_Stmt:
+ get_document_position(n.expr, position_context);
+ case Tag_Stmt:
+ r := cast(^Tag_Stmt)node;
+ get_document_position(r.stmt, position_context);
+ case Assign_Stmt:
+ position_context.assign = cast(^Assign_Stmt)node;
+ get_document_position(n.lhs, position_context);
+ get_document_position(n.rhs, position_context);
+ case Block_Stmt:
+ get_document_position(n.label, position_context);
+ get_document_position(n.stmts, position_context);
+ case If_Stmt:
+ get_document_position(n.label, position_context);
+ get_document_position(n.init, position_context);
+ get_document_position(n.cond, position_context);
+ get_document_position(n.body, position_context);
+ get_document_position(n.else_stmt, position_context);
+ case When_Stmt:
+ get_document_position(n.cond, position_context);
+ get_document_position(n.body, position_context);
+ get_document_position(n.else_stmt, position_context);
+ case Return_Stmt:
+ position_context.returns = cast(^Return_Stmt)node;
+ get_document_position(n.results, position_context);
+ case Defer_Stmt:
+ get_document_position(n.stmt, position_context);
+ case For_Stmt:
+ get_document_position(n.label, position_context);
+ get_document_position(n.init, position_context);
+ get_document_position(n.cond, position_context);
+ get_document_position(n.post, position_context);
+ get_document_position(n.body, position_context);
+ case Range_Stmt:
+ get_document_position(n.label, position_context);
+ get_document_position(n.val0, position_context);
+ get_document_position(n.val1, position_context);
+ get_document_position(n.expr, position_context);
+ get_document_position(n.body, position_context);
+ case Case_Clause:
+ position_context.case_clause = cast(^Case_Clause)node;
+ get_document_position(n.list, position_context);
+ get_document_position(n.body, position_context);
+ case Switch_Stmt:
+ position_context.switch_stmt = cast(^Switch_Stmt)node;
+ get_document_position(n.label, position_context);
+ get_document_position(n.init, position_context);
+ get_document_position(n.cond, position_context);
+ get_document_position(n.body, position_context);
+ case Type_Switch_Stmt:
+ position_context.switch_type_stmt = cast(^Type_Switch_Stmt)node;
+ get_document_position(n.label, position_context);
+ get_document_position(n.tag, position_context);
+ get_document_position(n.expr, position_context);
+ get_document_position(n.body, position_context);
+ case Branch_Stmt:
+ get_document_position(n.label, position_context);
+ case Using_Stmt:
+ get_document_position(n.list, position_context);
+ case Bad_Decl:
+ case Value_Decl:
+ position_context.value_decl = cast(^Value_Decl)node;
+ get_document_position(n.attributes, position_context);
+ get_document_position(n.names, position_context);
+ get_document_position(n.type, position_context);
+ get_document_position(n.values, position_context);
+ case Package_Decl:
+ case Import_Decl:
+ case Foreign_Block_Decl:
+ get_document_position(n.attributes, position_context);
+ get_document_position(n.foreign_library, position_context);
+ get_document_position(n.body, position_context);
+ case Foreign_Import_Decl:
+ get_document_position(n.name, position_context);
+ case Proc_Group:
+ get_document_position(n.args, position_context);
+ case Attribute:
+ get_document_position(n.elems, position_context);
+ case Field:
+ get_document_position(n.names, position_context);
+ get_document_position(n.type, position_context);
+ get_document_position(n.default_value, position_context);
+ case Field_List:
+ get_document_position(n.list, position_context);
+ case Typeid_Type:
+ get_document_position(n.specialization, position_context);
+ case Helper_Type:
+ get_document_position(n.type, position_context);
+ case Distinct_Type:
+ get_document_position(n.type, position_context);
+ case Poly_Type:
+ get_document_position(n.type, position_context);
+ get_document_position(n.specialization, position_context);
+ case Proc_Type:
+ get_document_position(n.params, position_context);
+ get_document_position(n.results, position_context);
+ case Pointer_Type:
+ get_document_position(n.elem, position_context);
+ case Array_Type:
+ get_document_position(n.len, position_context);
+ get_document_position(n.elem, position_context);
+ case Dynamic_Array_Type:
+ get_document_position(n.elem, position_context);
+ case Struct_Type:
+ get_document_position(n.poly_params, position_context);
+ get_document_position(n.align, position_context);
+ get_document_position(n.fields, position_context);
+ case Union_Type:
+ get_document_position(n.poly_params, position_context);
+ get_document_position(n.align, position_context);
+ get_document_position(n.variants, position_context);
+ case Enum_Type:
+ get_document_position(n.base_type, position_context);
+ get_document_position(n.fields, position_context);
+ case Bit_Set_Type:
+ get_document_position(n.elem, position_context);
+ get_document_position(n.underlying, position_context);
+ case Map_Type:
+ get_document_position(n.key, position_context);
+ get_document_position(n.value, position_context);
+ case Implicit_Selector_Expr:
+ position_context.implicit = true;
+ get_document_position(n.field, position_context);
+ case:
+ log.errorf("Unhandled node kind: %T", n);
+ }
} \ No newline at end of file
diff --git a/src/server/background.odin b/src/server/background.odin
index d184a55..359e7d7 100644
--- a/src/server/background.odin
+++ b/src/server/background.odin
@@ -1,14 +1,10 @@
package server
/*
- Background thread that runs and ensures that the dynamic indexer is not stale
+ Background thread that runs and ensures that the dynamic indexer is not stale
*/
import "shared:index"
-background_main :: proc() {
-
-
-
-
+background_main :: proc () {
} \ No newline at end of file
diff --git a/src/server/completion.odin b/src/server/completion.odin
index 85c8c98..54c8b26 100644
--- a/src/server/completion.odin
+++ b/src/server/completion.odin
@@ -16,884 +16,781 @@ import "core:slice"
import "shared:common"
import "shared:index"
-get_completion_list :: proc(document: ^Document, position: common.Position) -> (CompletionList, bool) {
+get_completion_list :: proc (document: ^Document, position: common.Position) -> (CompletionList, bool) {
- list: CompletionList;
+ list: CompletionList;
- position_context, ok := get_document_position_context(document, position, .Completion);
+ position_context, ok := get_document_position_context(document, position, .Completion);
- ast_context := make_ast_context(document.ast, document.imports, document.package_name);
+ ast_context := make_ast_context(document.ast, document.imports, document.package_name);
- get_globals(document.ast, &ast_context);
+ get_globals(document.ast, &ast_context);
- ast_context.current_package = ast_context.document_package;
- ast_context.value_decl = position_context.value_decl;
+ ast_context.current_package = ast_context.document_package;
+ ast_context.value_decl = position_context.value_decl;
- if position_context.function != nil {
- get_locals(document.ast, position_context.function, &ast_context, &position_context);
- }
+ if position_context.function != nil {
+ get_locals(document.ast, position_context.function, &ast_context, &position_context);
+ }
- if position_context.implicit {
- get_implicit_completion(&ast_context, &position_context, &list);
- }
+ if position_context.implicit {
+ get_implicit_completion(&ast_context, &position_context, &list);
+ } else if position_context.switch_type_stmt != nil && position_context.case_clause != nil && position_context.identifier != nil {
+ get_type_switch_Completion(&ast_context, &position_context, &list);
+ } else if position_context.comp_lit != nil && is_lhs_comp_lit(&position_context) {
+ get_comp_lit_completion(&ast_context, &position_context, &list);
+ } else if position_context.selector != nil {
+ get_selector_completion(&ast_context, &position_context, &list);
+ } else if position_context.identifier != nil {
+ get_identifier_completion(&ast_context, &position_context, &list);
+ }
- else if position_context.switch_type_stmt != nil && position_context.case_clause != nil && position_context.identifier != nil {
- get_type_switch_Completion(&ast_context, &position_context, &list);
- }
-
- else if position_context.comp_lit != nil && is_lhs_comp_lit(&position_context) {
- get_comp_lit_completion(&ast_context, &position_context, &list);
- }
-
- else if position_context.selector != nil {
- get_selector_completion(&ast_context, &position_context, &list);
- }
-
- else if position_context.identifier != nil {
- get_identifier_completion(&ast_context, &position_context, &list);
- }
-
- return list, true;
+ return list, true;
}
-is_lhs_comp_lit :: proc(position_context: ^DocumentPositionContext) -> bool {
-
- if len(position_context.comp_lit.elems) == 0 {
- return true;
- }
-
- for elem in position_context.comp_lit.elems {
-
- if position_in_node(elem, position_context.position) {
+is_lhs_comp_lit :: proc (position_context: ^DocumentPositionContext) -> bool {
- log.infof("in %v", elem.derived);
+ if len(position_context.comp_lit.elems) == 0 {
+ return true;
+ }
- if ident, ok := elem.derived.(ast.Ident); ok {
- return true;
- }
+ for elem in position_context.comp_lit.elems {
- else if field, ok := elem.derived.(ast.Field_Value); ok {
+ if position_in_node(elem, position_context.position) {
- if position_in_node(field.value, position_context.position) {
- return false;
- }
+ log.infof("in %v", elem.derived);
- }
+ if ident, ok := elem.derived.(ast.Ident); ok {
+ return true;
+ } else if field, ok := elem.derived.(ast.Field_Value); ok {
- }
+ if position_in_node(field.value, position_context.position) {
+ return false;
+ }
+ }
+ } else {
+ log.infof("not in %v", elem.derived);
+ }
+ }
- else {
- log.infof("not in %v", elem.derived);
- }
-
- }
-
- return true;
+ return true;
}
-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 {
-
- if ident, ok := field.field.derived.(ast.Ident); ok {
+field_exists_in_comp_lit :: proc (comp_lit: ^ast.Comp_Lit, name: string) -> bool {
- if ident.name == name {
- return true;
- }
+ for elem in comp_lit.elems {
- }
+ if field, ok := elem.derived.(ast.Field_Value); ok {
+ if field.field != nil {
- }
+ if ident, ok := field.field.derived.(ast.Ident); ok {
- }
+ if ident.name == name {
+ return true;
+ }
+ }
+ }
+ }
+ }
- }
-
- return false;
+ return false;
}
-get_directive_completion :: proc(ast_context: ^AstContext, postition_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 {
- "file",
- "line",
- "packed",
- "raw_union",
- "align",
- "no_nil",
- "complete",
- "no_alias",
- "caller_location",
- "require_results",
- "type",
- "bounds_check",
- "no_bounds_check",
- "assert",
- "defined",
- "procedure",
- "load",
- "partial",
- };
-
- for elem in directive_list {
-
- item := CompletionItem {
- detail = elem,
- label = elem,
- kind = .EnumMember,
- };
-
- append(&items, item);
-
- }
-
-
+get_directive_completion :: proc (ast_context: ^AstContext, postition_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 {
+ "file",
+ "line",
+ "packed",
+ "raw_union",
+ "align",
+ "no_nil",
+ "complete",
+ "no_alias",
+ "caller_location",
+ "require_results",
+ "type",
+ "bounds_check",
+ "no_bounds_check",
+ "assert",
+ "defined",
+ "procedure",
+ "load",
+ "partial",
+ };
+
+ for elem in directive_list {
+
+ item := CompletionItem {
+ detail = elem,
+ label = elem,
+ kind = .EnumMember,
+ };
+
+ append(&items, item);
+ }
}
-get_comp_lit_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) {
-
- items := make([dynamic] CompletionItem, context.temp_allocator);
+get_comp_lit_completion :: proc (ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) {
- if position_context.parent_comp_lit.type == nil {
- return;
- }
+ items := make([dynamic]CompletionItem, context.temp_allocator);
- if symbol, ok := resolve_type_expression(ast_context, position_context.parent_comp_lit.type); ok {
+ if position_context.parent_comp_lit.type == nil {
+ return;
+ }
- if comp_symbol, 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 {
- #partial switch v in comp_symbol.value {
- case index.SymbolStructValue:
- for name, i in v.names {
+ if comp_symbol, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok {
- //ERROR no completion on name and hover
- if resolved, ok := resolve_type_expression(ast_context, v.types[i]); ok {
+ #partial switch v in comp_symbol.value {
+ case index.SymbolStructValue:
+ for name, i in v.names {
- if field_exists_in_comp_lit(position_context.comp_lit, name) {
- continue;
- }
+ //ERROR no completion on name and hover
+ if resolved, ok := resolve_type_expression(ast_context, v.types[i]); ok {
- resolved.signature = index.node_to_string(v.types[i]);
- resolved.pkg = comp_symbol.name;
- resolved.name = name;
- resolved.type = .Field;
+ if field_exists_in_comp_lit(position_context.comp_lit, name) {
+ continue;
+ }
- item := CompletionItem {
- label = resolved.name,
- kind = cast(CompletionItemKind) resolved.type,
- detail = concatenate_symbols_information(ast_context, resolved),
- documentation = resolved.doc,
- };
+ resolved.signature = index.node_to_string(v.types[i]);
+ resolved.pkg = comp_symbol.name;
+ resolved.name = name;
+ resolved.type = .Field;
- append(&items, item);
- }
- }
- }
- }
- }
+ item := CompletionItem {
+ label = resolved.name,
+ kind = cast(CompletionItemKind)resolved.type,
+ detail = concatenate_symbols_information(ast_context, resolved),
+ documentation = resolved.doc,
+ };
+ append(&items, item);
+ }
+ }
+ }
+ }
+ }
- list.items = items[:];
+ 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);
+ items := make([dynamic]CompletionItem, context.temp_allocator);
- ast_context.current_package = ast_context.document_package;
+ ast_context.current_package = ast_context.document_package;
- if ident, ok := position_context.selector.derived.(ast.Ident); ok {
+ if ident, ok := position_context.selector.derived.(ast.Ident); ok {
- if !resolve_ident_is_variable(ast_context, ident) && !resolve_ident_is_package(ast_context, ident) && ident.name != "" {
- return;
- }
+ if !resolve_ident_is_variable(ast_context, ident) && !resolve_ident_is_package(ast_context, ident) && ident.name != "" {
+ return;
+ }
+ }
- }
+ symbols := make([dynamic]index.Symbol, context.temp_allocator);
- symbols := make([dynamic] index.Symbol, context.temp_allocator);
+ selector: index.Symbol;
+ ok: bool;
- selector: index.Symbol;
- ok: bool;
+ ast_context.use_locals = true;
+ ast_context.use_globals = true;
- 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 !ok {
- return;
- }
+ if selector.pkg != "" {
+ ast_context.current_package = selector.pkg;
+ } else {
+ ast_context.current_package = ast_context.document_package;
+ }
- if selector.pkg != "" {
- ast_context.current_package = selector.pkg;
- }
+ field: string;
+
+ if position_context.field != nil {
- else {
- ast_context.current_package = ast_context.document_package;
- }
+ switch v in position_context.field.derived {
+ case ast.Ident:
+ field = v.name;
+ }
+ }
- field: string;
+ if s, ok := selector.value.(index.SymbolProcedureValue); ok {
+ if len(s.return_types) == 1 {
+ if selector, ok = resolve_type_expression(ast_context, s.return_types[0].type); !ok {
+ return;
+ }
+ }
+ }
- if position_context.field != nil {
+ #partial switch v in selector.value {
+ case index.SymbolUnionValue:
+ list.isIncomplete = false;
- switch v in position_context.field.derived {
- case ast.Ident:
- field = v.name;
- }
+ for name in v.names {
+ symbol: index.Symbol;
+ symbol.name = fmt.aprintf("(%v)", name);
+ symbol.pkg = selector.name;
+ symbol.type = .EnumMember;
+ append(&symbols, symbol);
+ }
- }
+ case index.SymbolEnumValue:
+ list.isIncomplete = false;
+ for name in v.names {
+ symbol: index.Symbol;
+ symbol.name = name;
+ symbol.pkg = selector.name;
+ symbol.type = .EnumMember;
+ append(&symbols, symbol);
+ }
- if s, ok := selector.value.(index.SymbolProcedureValue); ok {
- if len(s.return_types) == 1 {
- if selector, ok = resolve_type_expression(ast_context, s.return_types[0].type); !ok {
- return;
- }
- }
- }
+ case index.SymbolStructValue:
+ list.isIncomplete = false;
+ for name, i in v.names {
- #partial switch v in selector.value {
- case index.SymbolUnionValue:
- list.isIncomplete = false;
+ if selector.pkg != "" {
+ ast_context.current_package = selector.pkg;
+ } else {
+ ast_context.current_package = ast_context.document_package;
+ }
- for name in v.names {
- symbol: index.Symbol;
- symbol.name = fmt.aprintf("(%v)", name);
- symbol.pkg = selector.name;
- symbol.type = .EnumMember;
- append(&symbols, symbol);
- }
+ if symbol, ok := resolve_type_expression(ast_context, v.types[i]); ok {
- case index.SymbolEnumValue:
- list.isIncomplete = false;
+ if expr, ok := position_context.selector.derived.(ast.Selector_Expr); ok {
- for name in v.names {
- symbol: index.Symbol;
- symbol.name = name;
- symbol.pkg = selector.name;
- symbol.type = .EnumMember;
- append(&symbols, symbol);
- }
+ if expr.op.text == "->" && symbol.type != .Function {
+ continue;
+ }
+ }
- case index.SymbolStructValue:
- list.isIncomplete = false;
+ if position_context.arrow && symbol.type != .Function {
+ continue;
+ }
- for name, i in v.names {
-
- if selector.pkg != "" {
- ast_context.current_package = selector.pkg;
- }
-
- else {
- 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 expr.op.text == "->" && symbol.type != .Function {
- continue;
- }
-
- }
-
- if position_context.arrow && symbol.type != .Function {
- continue;
- }
-
- symbol.name = name;
- symbol.type = .Field;
- symbol.pkg = selector.name;
- symbol.signature = index.node_to_string(v.types[i]);
- append(&symbols, symbol);
- }
-
- else {
- //just give some generic symbol with name.
- symbol: index.Symbol;
- symbol.name = name;
- symbol.type = .Field;
- append(&symbols, symbol);
- }
-
- }
-
-
- case index.SymbolPackageValue:
-
- list.isIncomplete = true;
-
- if searched, ok := index.fuzzy_search(field, {selector.pkg}); ok {
-
- for search in searched {
- append(&symbols, search.symbol);
- }
-
- }
-
- else {
- log.errorf("Failed to fuzzy search, field: %v, package: %v", field, selector.pkg);
- return;
- }
-
- }
-
- for symbol, i in symbols {
-
- item := CompletionItem {
- label = symbol.name,
- kind = cast(CompletionItemKind) symbol.type,
- detail = concatenate_symbols_information(ast_context, symbol),
- documentation = symbol.doc,
- };
-
- append(&items, item);
- }
-
- list.items = items[:];
+ symbol.name = name;
+ symbol.type = .Field;
+ symbol.pkg = selector.name;
+ symbol.signature = index.node_to_string(v.types[i]);
+ append(&symbols, symbol);
+ } else {
+ //just give some generic symbol with name.
+ symbol: index.Symbol;
+ symbol.name = name;
+ symbol.type = .Field;
+ append(&symbols, symbol);
+ }
+ }
+
+ case index.SymbolPackageValue:
+
+ list.isIncomplete = true;
+
+ if searched, ok := index.fuzzy_search(field, {selector.pkg}); ok {
+
+ for search in searched {
+ append(&symbols, search.symbol);
+ }
+ } else {
+ log.errorf("Failed to fuzzy search, field: %v, package: %v", field, selector.pkg);
+ return;
+ }
+ }
+
+ for symbol, i in symbols {
+
+ item := CompletionItem {
+ label = symbol.name,
+ kind = cast(CompletionItemKind)symbol.type,
+ detail = concatenate_symbols_information(ast_context, symbol),
+ documentation = symbol.doc,
+ };
+
+ append(&items, item);
+ }
+
+ list.items = items[:];
}
-unwrap_enum :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (index.SymbolEnumValue, bool) {
-
- if enum_symbol, ok := resolve_type_expression(ast_context, node); ok {
+unwrap_enum :: proc (ast_context: ^AstContext, node: ^ast.Expr) -> (index.SymbolEnumValue, bool) {
- if enum_value, ok := enum_symbol.value.(index.SymbolEnumValue); ok {
- return enum_value, true;
- }
+ if enum_symbol, ok := resolve_type_expression(ast_context, node); ok {
- }
+ if enum_value, ok := enum_symbol.value.(index.SymbolEnumValue); ok {
+ return enum_value, true;
+ }
+ }
- return {}, false;
+ return {}, false;
}
-unwrap_union :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (index.SymbolUnionValue, bool) {
-
- if union_symbol, ok := resolve_type_expression(ast_context, node); ok {
+unwrap_union :: proc (ast_context: ^AstContext, node: ^ast.Expr) -> (index.SymbolUnionValue, bool) {
- if union_value, ok := union_symbol.value.(index.SymbolUnionValue); ok {
- return union_value, true;
- }
+ if union_symbol, ok := resolve_type_expression(ast_context, node); ok {
- }
-
- return {}, false;
+ if union_value, ok := union_symbol.value.(index.SymbolUnionValue); ok {
+ return union_value, true;
+ }
+ }
+ return {}, false;
}
-unwrap_bitset :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (index.SymbolEnumValue, bool) {
-
- if bitset_symbol, ok := resolve_type_expression(ast_context, node); ok {
+unwrap_bitset :: proc (ast_context: ^AstContext, node: ^ast.Expr) -> (index.SymbolEnumValue, bool) {
- if bitset_value, ok := bitset_symbol.value.(index.SymbolBitSetValue); ok {
+ if bitset_symbol, ok := resolve_type_expression(ast_context, node); ok {
- if enum_symbol, ok := resolve_type_expression(ast_context, bitset_value.expr); ok {
+ if bitset_value, ok := bitset_symbol.value.(index.SymbolBitSetValue); ok {
- if enum_value, ok := enum_symbol.value.(index.SymbolEnumValue); ok {
- return enum_value, true;
- }
- }
+ if enum_symbol, ok := resolve_type_expression(ast_context, bitset_value.expr); ok {
- }
+ if enum_value, ok := enum_symbol.value.(index.SymbolEnumValue); ok {
+ return enum_value, true;
+ }
+ }
+ }
+ }
- }
-
- return {}, false;
+ return {}, false;
}
-get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) {
-
- items := make([dynamic] CompletionItem, context.temp_allocator);
-
- list.isIncomplete = false;
-
- selector: index.Symbol;
-
- ast_context.use_locals = true;
- ast_context.use_globals = true;
-
- if selector.pkg != "" {
- ast_context.current_package = selector.pkg;
- }
-
- else {
- ast_context.current_package = ast_context.document_package;
- }
-
- //enum switch infer
- 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 {
-
- 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 {
- used_enums[implicit.field.name] = true;
- }
- }
- }
- }
- }
-
- 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,
- detail = name,
- };
-
- append(&items, item);
-
- }
-
- }
-
- }
-
- else if position_context.comp_lit != nil && position_context.binary != nil && (position_context.binary.op.text == "&" ) {
- //bitsets
- context_node: ^ast.Expr;
- bitset_node: ^ast.Expr;
+get_implicit_completion :: proc (ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) {
- if position_in_node(position_context.binary.right, position_context.position) {
- context_node = position_context.binary.right;
- bitset_node = position_context.binary.left;
- }
+ items := make([dynamic]CompletionItem, context.temp_allocator);
- else if position_in_node(position_context.binary.left, position_context.position) {
- context_node = position_context.binary.left;
- bitset_node = position_context.binary.right;
- }
+ list.isIncomplete = false;
- if context_node != nil && bitset_node != nil {
+ selector: index.Symbol;
- if _, ok := context_node.derived.(ast.Comp_Lit); ok {
+ ast_context.use_locals = true;
+ ast_context.use_globals = true;
- if value, ok := unwrap_bitset(ast_context, bitset_node); ok {
+ if selector.pkg != "" {
+ ast_context.current_package = selector.pkg;
+ } else {
+ ast_context.current_package = ast_context.document_package;
+ }
- for name in value.names {
+ //enum switch infer
+ if position_context.switch_stmt != nil && position_context.case_clause != nil && position_context.switch_stmt.cond != nil {
- item := CompletionItem {
- label = name,
- kind = .EnumMember,
- detail = name,
- };
+ used_enums := make(map[string]bool, 5, context.temp_allocator);
- append(&items, item);
- }
- }
- }
- }
- }
+ if block, ok := position_context.switch_stmt.body.derived.(ast.Block_Stmt); ok {
- else if position_context.comp_lit != nil {
+ for stmt in block.stmts {
- if position_context.parent_comp_lit.type == nil {
- return;
- }
+ if case_clause, ok := stmt.derived.(ast.Case_Clause); ok {
- field_name: string;
+ for name in case_clause.list {
- for elem in position_context.comp_lit.elems {
+ if implicit, ok := name.derived.(ast.Implicit_Selector_Expr); ok {
+ used_enums[implicit.field.name] = true;
+ }
+ }
+ }
+ }
+ }
- if position_in_node(elem, position_context.position) {
+ if enum_value, ok := unwrap_enum(ast_context, position_context.switch_stmt.cond); ok {
- if field, ok := elem.derived.(ast.Field_Value); ok {
- field_name = field.field.derived.(ast.Ident).name;
- }
+ for name in enum_value.names {
- }
+ if name in used_enums {
+ continue;
+ }
- }
+ item := CompletionItem {
+ label = name,
+ kind = .EnumMember,
+ detail = name,
+ };
- if field_name == "" {
- return;
- }
+ append(&items, item);
+ }
+ }
+ } else if position_context.comp_lit != nil && position_context.binary != nil && (position_context.binary.op.text == "&") {
+ //bitsets
+ context_node: ^ast.Expr;
+ bitset_node: ^ast.Expr;
- if symbol, ok := resolve_type_expression(ast_context, position_context.parent_comp_lit.type); ok {
+ if position_in_node(position_context.binary.right, position_context.position) {
+ context_node = position_context.binary.right;
+ bitset_node = position_context.binary.left;
+ } else if position_in_node(position_context.binary.left, position_context.position) {
+ context_node = position_context.binary.left;
+ bitset_node = position_context.binary.right;
+ }
- if comp_symbol, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok {
+ if context_node != nil && bitset_node != nil {
- if s, ok := comp_symbol.value.(index.SymbolStructValue); ok {
+ if _, ok := context_node.derived.(ast.Comp_Lit); ok {
- for name, i in s.names {
+ if value, ok := unwrap_bitset(ast_context, bitset_node); ok {
- if name != field_name {
- continue;
- }
+ for name in value.names {
- if enum_value, ok := unwrap_enum(ast_context, s.types[i]); ok {
- for enum_name in enum_value.names {
- item := CompletionItem {
- label = enum_name,
- kind = .EnumMember,
- detail = enum_name,
- };
+ item := CompletionItem {
+ label = name,
+ kind = .EnumMember,
+ detail = name,
+ };
- append(&items, item);
- }
- }
- }
- }
- }
- }
- }
+ append(&items, item);
+ }
+ }
+ }
+ }
+ } else if position_context.comp_lit != nil {
- else if position_context.binary != nil && (position_context.binary.op.text == "==" || position_context.binary.op.text == "!=") {
+ if position_context.parent_comp_lit.type == nil {
+ return;
+ }
- context_node: ^ast.Expr;
- enum_node: ^ast.Expr;
+ field_name: string;
- if position_in_node(position_context.binary.right, position_context.position) {
- context_node = position_context.binary.right;
- enum_node = position_context.binary.left;
- }
+ for elem in position_context.comp_lit.elems {
- else if position_in_node(position_context.binary.left, position_context.position) {
- context_node = position_context.binary.left;
- enum_node = position_context.binary.right;
- }
+ if position_in_node(elem, position_context.position) {
- if context_node != nil && enum_node != nil {
+ if field, ok := elem.derived.(ast.Field_Value); ok {
+ field_name = field.field.derived.(ast.Ident).name;
+ }
+ }
+ }
- if enum_value, ok := unwrap_enum(ast_context, enum_node); ok {
+ if field_name == "" {
+ return;
+ }
- for name in enum_value.names {
+ if symbol, ok := resolve_type_expression(ast_context, position_context.parent_comp_lit.type); ok {
- item := CompletionItem {
- label = name,
- kind = .EnumMember,
- detail = name,
- };
+ if comp_symbol, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok {
- append(&items, item);
- }
- }
- }
- }
+ if s, ok := comp_symbol.value.(index.SymbolStructValue); ok {
- else if position_context.assign != nil && position_context.assign.rhs != nil && position_context.assign.lhs != nil {
+ for name, i in s.names {
- rhs_index: int;
+ if name != field_name {
+ continue;
+ }
- for elem in position_context.assign.rhs {
+ if enum_value, ok := unwrap_enum(ast_context, s.types[i]); ok {
+ for enum_name in enum_value.names {
+ item := CompletionItem {
+ label = enum_name,
+ kind = .EnumMember,
+ detail = enum_name,
+ };
- if position_in_node(elem, position_context.position) {
- break;
- }
+ append(&items, item);
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if position_context.binary != nil && (position_context.binary.op.text == "==" || position_context.binary.op.text == "!=") {
- else {
+ context_node: ^ast.Expr;
+ enum_node: ^ast.Expr;
- //procedures are the only types that can return more than one value
- if symbol, ok := resolve_type_expression(ast_context, elem); ok {
+ 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) {
+ context_node = position_context.binary.left;
+ enum_node = position_context.binary.right;
+ }
- if procedure, ok := symbol.value.(index.SymbolProcedureValue); ok {
+ if context_node != nil && enum_node != nil {
- if procedure.return_types == nil {
- return;
- }
+ if enum_value, ok := unwrap_enum(ast_context, enum_node); ok {
- rhs_index += len(procedure.return_types);
- }
+ for name in enum_value.names {
- else {
- rhs_index += 1;
- }
+ item := CompletionItem {
+ label = name,
+ kind = .EnumMember,
+ detail = name,
+ };
- }
+ append(&items, item);
+ }
+ }
+ }
+ } else 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 {
- if len(position_context.assign.lhs) > rhs_index {
+ if position_in_node(elem, position_context.position) {
+ break;
+ } else {
- if enum_value, ok := unwrap_enum(ast_context, position_context.assign.lhs[rhs_index]); ok {
+ //procedures are the only types that can return more than one value
+ if symbol, ok := resolve_type_expression(ast_context, elem); ok {
- for name in enum_value.names {
+ if procedure, ok := symbol.value.(index.SymbolProcedureValue); ok {
- item := CompletionItem {
- label = name,
- kind = .EnumMember,
- detail = name,
- };
+ if procedure.return_types == nil {
+ return;
+ }
- append(&items, item);
+ rhs_index += len(procedure.return_types);
+ } else {
+ rhs_index += 1;
+ }
+ }
+ }
+ }
- }
+ if len(position_context.assign.lhs) > rhs_index {
- }
+ 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,
+ kind = .EnumMember,
+ detail = name,
+ };
- else if position_context.returns != nil && position_context.function != nil {
+ append(&items, item);
+ }
+ }
+ }
+ } else if position_context.returns != nil && position_context.function != nil {
- return_index: int;
+ return_index: int;
- if position_context.returns.results == nil {
- return;
- }
+ if position_context.returns.results == nil {
+ return;
+ }
- for result, i in position_context.returns.results {
+ for result, i in position_context.returns.results {
+
+ if position_in_node(result, position_context.position) {
+ return_index = i;
+ break;
+ }
+ }
- if position_in_node(result, position_context.position) {
- return_index = i;
- break;
- }
+ if position_context.function.type == nil {
+ return;
+ }
- }
+ if position_context.function.type.results == nil {
+ return;
+ }
- if position_context.function.type == nil {
- return;
- }
+ if len(position_context.function.type.results.list) > return_index {
- if position_context.function.type.results == nil {
- return;
- }
+ if return_symbol, ok := resolve_type_expression(ast_context, position_context.function.type.results.list[return_index].type); ok {
- if len(position_context.function.type.results.list) > return_index {
+ #partial switch v in return_symbol.value {
+ case index.SymbolEnumValue:
+ for name in v.names {
- if return_symbol, ok := resolve_type_expression(ast_context, position_context.function.type.results.list[return_index].type); ok {
+ item := CompletionItem {
+ label = name,
+ kind = .EnumMember,
+ detail = name,
+ };
- #partial switch v in return_symbol.value {
- case index.SymbolEnumValue:
- for name in v.names {
+ append(&items, item);
+ }
+ }
+ }
+ }
+ }
- item := CompletionItem {
- label = name,
- kind = .EnumMember,
- detail = name,
- };
-
- append(&items, item);
-
- }
-
- }
-
- }
-
- }
-
-
-
-
- }
-
-
- list.items = items[:];
+ list.items = items[:];
}
-get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) {
-
- items := make([dynamic] CompletionItem, context.temp_allocator);
+get_identifier_completion :: proc (ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) {
- list.isIncomplete = true;
+ items := make([dynamic]CompletionItem, context.temp_allocator);
- CombinedResult :: struct {
- score: f32,
- symbol: index.Symbol,
- variable: ^ast.Ident,
- };
+ list.isIncomplete = true;
- combined_sort_interface :: proc(s: ^[dynamic] CombinedResult) -> sort.Interface {
- return sort.Interface{
- collection = rawptr(s),
- len = proc(it: sort.Interface) -> int {
- s := (^[dynamic] CombinedResult)(it.collection);
- return len(s^);
- },
- less = proc(it: sort.Interface, i, j: int) -> bool {
- s := (^[dynamic] CombinedResult)(it.collection);
- return s[i].score > s[j].score;
- },
- swap = proc(it: sort.Interface, i, j: int) {
- s := (^[dynamic] CombinedResult)(it.collection);
- s[i], s[j] = s[j], s[i];
- },
- };
- }
+ CombinedResult :: struct {
+ score: f32,
+ symbol: index.Symbol,
+ variable: ^ast.Ident,
+ };
- combined := make([dynamic] CombinedResult);
+ combined_sort_interface :: proc (s: ^[dynamic]CombinedResult) -> sort.Interface {
+ return sort.Interface {
+ collection = rawptr(s),
+ len = proc (it: sort.Interface) -> int {
+ s := (^[dynamic]CombinedResult)(it.collection);
+ return len(s^);
+ },
+ less = proc (it: sort.Interface, i, j: int) -> bool {
+ s := (^[dynamic]CombinedResult)(it.collection);
+ return s[i].score > s[j].score;
+ },
+ swap = proc (it: sort.Interface, i, j: int) {
+ s := (^[dynamic]CombinedResult)(it.collection);
+ s[i], s[j] = s[j], s[i];
+ },
+ };
+ };
- lookup := "";
+ combined := make([dynamic]CombinedResult);
- if ident, ok := position_context.identifier.derived.(ast.Ident); ok {
- lookup = ident.name;
- }
+ lookup := "";
- pkgs := make([dynamic] string, context.temp_allocator);
+ if ident, ok := position_context.identifier.derived.(ast.Ident); ok {
+ lookup = ident.name;
+ }
- usings := get_using_packages(ast_context);
+ pkgs := make([dynamic]string, context.temp_allocator);
- for u in usings {
- append(&pkgs, u);
- }
+ usings := get_using_packages(ast_context);
- append(&pkgs, ast_context.document_package);
+ for u in usings {
+ append(&pkgs, u);
+ }
- if results, ok := index.fuzzy_search(lookup, pkgs[:]); ok {
+ append(&pkgs, ast_context.document_package);
- for r in results {
- append(&combined, CombinedResult { score = r.score, symbol = r.symbol});
- }
+ if results, ok := index.fuzzy_search(lookup, pkgs[:]); ok {
- }
+ for r in results {
+ append(&combined, CombinedResult {score = r.score, symbol = r.symbol});
+ }
+ }
- matcher := common.make_fuzzy_matcher(lookup);
+ matcher := common.make_fuzzy_matcher(lookup);
- global: for k, v in ast_context.globals {
+ global: for k, v in ast_context.globals {
- //combined is sorted and should do binary search instead.
- for result in combined {
- if result.symbol.name == k {
- continue global;
- }
- }
+ //combined is sorted and should do binary search instead.
+ for result in combined {
+ if result.symbol.name == k {
+ continue global;
+ }
+ }
- ast_context.use_locals = true;
- ast_context.use_globals = true;
- ast_context.current_package = ast_context.document_package;
+ ast_context.use_locals = true;
+ ast_context.use_globals = true;
+ ast_context.current_package = ast_context.document_package;
- ident := index.new_type(ast.Ident, v.pos, v.end, context.temp_allocator);
- ident.name = k;
+ ident := index.new_type(ast.Ident, v.pos, v.end, context.temp_allocator);
+ ident.name = k;
- if symbol, ok := resolve_type_identifier(ast_context, ident^); ok {
- symbol.name = ident.name;
- symbol.signature = get_signature(ast_context, ident^, symbol);
+ if symbol, ok := resolve_type_identifier(ast_context, ident^); ok {
+ symbol.name = ident.name;
+ symbol.signature = get_signature(ast_context, ident^, symbol);
- if score, ok := common.fuzzy_match(matcher, symbol.name); ok {
- append(&combined, CombinedResult { score = score * 1.1, symbol = symbol, variable = ident });
- }
+ if score, ok := common.fuzzy_match(matcher, symbol.name); ok {
+ append(&combined, CombinedResult {score = score * 1.1, symbol = symbol, variable = ident});
+ }
+ }
+ }
- }
- }
+ for k, v in ast_context.locals {
+ ast_context.use_locals = true;
+ ast_context.use_globals = true;
+ ast_context.current_package = ast_context.document_package;
+ ident := index.new_type(ast.Ident, {offset = position_context.position}, {offset = position_context.position}, context.temp_allocator);
+ ident.name = k;
- for k, v in ast_context.locals {
+ if symbol, ok := resolve_type_identifier(ast_context, ident^); ok {
+ symbol.name = ident.name;
+ symbol.signature = get_signature(ast_context, ident^, symbol);
- ast_context.use_locals = true;
- ast_context.use_globals = true;
- ast_context.current_package = ast_context.document_package;
+ if score, ok := common.fuzzy_match(matcher, symbol.name); ok {
+ append(&combined, CombinedResult {score = score * 1.1, symbol = symbol, variable = ident});
+ }
+ }
+ }
+ for pkg in ast_context.imports {
- ident := index.new_type(ast.Ident, { offset = position_context.position }, { offset = position_context.position }, context.temp_allocator);
- ident.name = k;
+ symbol: index.Symbol;
- if symbol, ok := resolve_type_identifier(ast_context, ident^); ok {
- symbol.name = ident.name;
- symbol.signature = get_signature(ast_context, ident^, symbol);
+ symbol.name = pkg.base;
+ symbol.type = .Package;
- if score, ok := common.fuzzy_match(matcher, symbol.name); ok {
- append(&combined, CombinedResult { score = score * 1.1, symbol = symbol, variable = ident });
- }
+ if score, ok := common.fuzzy_match(matcher, symbol.name); ok {
+ append(&combined, CombinedResult {score = score * 1.1, symbol = symbol});
+ }
+ }
- }
- }
+ sort.sort(combined_sort_interface(&combined));
- for pkg in ast_context.imports {
+ //hard code for now
+ top_results := combined[0:(min(20, len(combined)))];
- symbol: index.Symbol;
+ for result in top_results {
- symbol.name = pkg.base;
- symbol.type = .Package;
+ item := CompletionItem {
+ label = result.symbol.name,
+ detail = concatenate_symbols_information(ast_context, result.symbol),
+ };
- if score, ok := common.fuzzy_match(matcher, symbol.name); ok {
- append(&combined, CombinedResult { score = score * 1.1, symbol = symbol });
- }
- }
+ if result.variable != nil {
+ if ok := resolve_ident_is_variable(ast_context, result.variable^); ok {
+ item.kind = .Variable;
+ } else {
+ item.kind = cast(CompletionItemKind)result.symbol.type;
+ }
+ } else {
+ item.kind = cast(CompletionItemKind)result.symbol.type;
+ }
- sort.sort(combined_sort_interface(&combined));
+ append(&items, item);
+ }
- //hard code for now
- top_results := combined[0:(min(20, len(combined)))];
-
- for result in top_results {
-
- item := CompletionItem {
- label = result.symbol.name,
- detail = concatenate_symbols_information(ast_context, result.symbol),
- };
-
- if result.variable != nil {
- if ok := resolve_ident_is_variable(ast_context, result.variable^); ok {
- item.kind = .Variable;
- }
-
- else {
- item.kind = cast(CompletionItemKind)result.symbol.type;
- }
- }
-
- else {
- item.kind = cast(CompletionItemKind)result.symbol.type;
- }
-
- append(&items, item);
- }
-
- list.items = items[:];
+ 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) {
}
-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;
+ items := make([dynamic]CompletionItem, context.temp_allocator);
+ list.isIncomplete = false;
- 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 {
+ if union_value, ok := unwrap_union(ast_context, assign.rhs[0]); ok {
- for name in union_value.names {
+ for name in union_value.names {
- item := CompletionItem {
- label = name,
- kind = .EnumMember,
- detail = name,
- };
+ item := CompletionItem {
+ label = name,
+ kind = .EnumMember,
+ detail = name,
+ };
- append(&items, item);
- }
- }
- }
+ append(&items, item);
+ }
+ }
+ }
- list.items = items[:];
+ list.items = items[:];
} \ No newline at end of file
diff --git a/src/server/documents.odin b/src/server/documents.odin
index dd4ef85..ab8b54d 100644
--- a/src/server/documents.odin
+++ b/src/server/documents.odin
@@ -15,454 +15,424 @@ import "intrinsics"
import "shared:common"
ParserError :: struct {
- message: string,
- line: int,
- column: int,
- file: string,
- offset: int,
-};
-
+ message: string,
+ line: int,
+ column: int,
+ file: string,
+ offset: int,
+}
Package :: struct {
- name: string, //the entire absolute path to the directory
- base: string,
-};
+ name: string, //the entire absolute path to the directory
+ base: string,
+}
Document :: struct {
- uri: common.Uri,
- text: [] u8,
- used_text: int, //allow for the text to be reallocated with more data than needed
- client_owned: bool,
- diagnosed_errors: bool,
- ast: ast.File,
- imports: [] Package,
- package_name: string,
- allocator: ^common.Scratch_Allocator, //because does not support freeing I use arena allocators for each document
- operating_on: int, //atomic
-};
+ uri: common.Uri,
+ text: []u8,
+ used_text: int, //allow for the text to be reallocated with more data than needed
+ client_owned: bool,
+ diagnosed_errors: bool,
+ ast: ast.File,
+ imports: []Package,
+ package_name: string,
+ allocator: ^common.Scratch_Allocator, //because does not support freeing I use arena allocators for each document
+ operating_on: int, //atomic
+}
DocumentStorage :: struct {
- documents: map [string] Document,
- free_allocators: [dynamic] ^common.Scratch_Allocator,
-};
+ documents: map[string]Document,
+ free_allocators: [dynamic]^common.Scratch_Allocator,
+}
document_storage: DocumentStorage;
-document_storage_shutdown :: proc() {
+document_storage_shutdown :: proc () {
- for k, v in document_storage.documents {
- delete(k);
- }
+ for k, v in document_storage.documents {
+ delete(k);
+ }
- for alloc in document_storage.free_allocators {
- common.scratch_allocator_destroy(alloc);
- free(alloc);
- }
+ for alloc in document_storage.free_allocators {
+ common.scratch_allocator_destroy(alloc);
+ free(alloc);
+ }
- delete(document_storage.free_allocators);
- delete(document_storage.documents);
+ delete(document_storage.free_allocators);
+ delete(document_storage.documents);
}
-document_get_allocator :: proc() -> ^common.Scratch_Allocator {
-
- if len(document_storage.free_allocators) > 0 {
- return pop(&document_storage.free_allocators);
- }
-
- else {
- allocator := new(common.Scratch_Allocator);
- common.scratch_allocator_init(allocator, mem.megabytes(1));
- return allocator;
- }
+document_get_allocator :: proc () -> ^common.Scratch_Allocator {
+ if len(document_storage.free_allocators) > 0 {
+ return pop(&document_storage.free_allocators);
+ } else {
+ allocator := new(common.Scratch_Allocator);
+ common.scratch_allocator_init(allocator, mem.megabytes(1));
+ return allocator;
+ }
}
-document_free_allocator :: proc(allocator: ^common.Scratch_Allocator) {
- append(&document_storage.free_allocators, allocator);
+document_free_allocator :: proc (allocator: ^common.Scratch_Allocator) {
+ append(&document_storage.free_allocators, allocator);
}
-document_get :: proc(uri_string: string) -> ^Document {
+document_get :: proc (uri_string: string) -> ^Document {
- uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator);
+ uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator);
- if !parsed_ok {
- return nil;
- }
+ if !parsed_ok {
+ return nil;
+ }
- document := &document_storage.documents[uri.path];
+ document := &document_storage.documents[uri.path];
- if document == nil {
- return nil;
- }
+ if document == nil {
+ return nil;
+ }
- intrinsics.atomic_add(&document.operating_on, 1);
+ intrinsics.atomic_add(&document.operating_on, 1);
- return document;
+ return document;
}
-document_release :: proc(document: ^Document) {
-
- if document != nil {
- intrinsics.atomic_sub(&document.operating_on, 1);
- }
+document_release :: proc (document: ^Document) {
+ if document != nil {
+ intrinsics.atomic_sub(&document.operating_on, 1);
+ }
}
/*
- Client opens a document with transferred text
+ Client opens a document with transferred text
*/
-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);
-
- log.infof("document_open: %v", uri_string);
-
- if !parsed_ok {
- log.error("Failed to parse uri");
- return .ParseError;
- }
-
- if document := &document_storage.documents[uri.path]; document != nil {
+document_open :: proc (uri_string: string, text: string, config: ^common.Config, writer: ^Writer) -> common.Error {
- if document.client_owned {
- log.errorf("Client called open on an already open document: %v ", document.uri.path);
- return .InvalidRequest;
- }
+ uri, parsed_ok := common.parse_uri(uri_string, context.allocator);
- document.uri = uri;
- document.client_owned = true;
- document.text = transmute([] u8)text;
- document.used_text = len(document.text);
- document.allocator = document_get_allocator();
+ log.infof("document_open: %v", uri_string);
- if err := document_refresh(document, config, writer); err != .None {
- return err;
- }
+ if !parsed_ok {
+ log.error("Failed to parse uri");
+ return .ParseError;
+ }
- }
+ if document := &document_storage.documents[uri.path]; document != nil {
- else {
+ if document.client_owned {
+ log.errorf("Client called open on an already open document: %v ", document.uri.path);
+ return .InvalidRequest;
+ }
- document := Document {
- uri = uri,
- text = transmute([] u8)text,
- client_owned = true,
- used_text = len(text),
- allocator = document_get_allocator(),
- };
+ document.uri = uri;
+ document.client_owned = true;
+ document.text = transmute([]u8)text;
+ document.used_text = len(document.text);
+ document.allocator = document_get_allocator();
- if err := document_refresh(&document, config, writer); err != .None {
- return err;
- }
+ if err := document_refresh(document, config, writer); err != .None {
+ return err;
+ }
+ } else {
- document_storage.documents[strings.clone(uri.path)] = document;
- }
+ document := Document {
+ uri = uri,
+ text = transmute([]u8)text,
+ client_owned = true,
+ used_text = len(text),
+ allocator = document_get_allocator(),
+ };
+ if err := document_refresh(&document, config, writer); err != .None {
+ return err;
+ }
+ document_storage.documents[strings.clone(uri.path)] = document;
+ }
- //hmm feels like odin needs some ownership semantic
- delete(uri_string);
+ //hmm feels like odin needs some ownership semantic
+ delete(uri_string);
- return .None;
+ return .None;
}
/*
- Function that applies changes to the given document through incremental syncronization
- */
-document_apply_changes :: proc(uri_string: string, changes: [dynamic] TextDocumentContentChangeEvent, config: ^common.Config, writer: ^Writer) -> common.Error {
-
- uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator);
-
- if !parsed_ok {
- return .ParseError;
- }
-
- document := &document_storage.documents[uri.path];
-
- if !document.client_owned {
- 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]);
+ Function that applies changes to the given document through incremental syncronization
+*/
+document_apply_changes :: proc (uri_string: string, changes: [dynamic]TextDocumentContentChangeEvent, config: ^common.Config, writer: ^Writer) -> common.Error {
- if !ok {
- return .ParseError;
- }
+ uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator);
- //lower bound is before the change
- lower := document.text[:absolute_range.start];
+ if !parsed_ok {
+ return .ParseError;
+ }
- //new change between lower and upper
- middle := change.text;
+ document := &document_storage.documents[uri.path];
- //upper bound is after the change
- upper := document.text[absolute_range.end:document.used_text];
+ if !document.client_owned {
+ log.errorf("Client called change on an document not opened: %v ", document.uri.path);
+ return .InvalidRequest;
+ }
- //total new size needed
- document.used_text = len(lower) + len(change.text) + len(upper);
+ for change in changes {
- //Reduce the amount of allocation by allocating more memory than needed
- if document.used_text > len(document.text) {
- new_text := make([]u8, document.used_text * 2);
+ //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 {
- //join the 3 splices into the text
- copy(new_text, lower);
- copy(new_text[len(lower):], middle);
- copy(new_text[len(lower)+len(middle):], upper);
+ absolute_range, ok := common.get_absolute_range(range, document.text[:document.used_text]);
- delete(document.text);
+ if !ok {
+ return .ParseError;
+ }
- document.text = new_text;
- }
+ //lower bound is before the change
+ lower := document.text[:absolute_range.start];
- else {
- //order matters here, we need to make sure we swap the data already in the text before the middle
- copy(document.text, lower);
- copy(document.text[len(lower)+len(middle):], upper);
- copy(document.text[len(lower):], middle);
- }
+ //new change between lower and upper
+ middle := change.text;
- }
+ //upper bound is after the change
+ upper := document.text[absolute_range.end:document.used_text];
- else {
+ //total new size needed
+ document.used_text = len(lower) + len(change.text) + len(upper);
- document.used_text = len(change.text);
+ //Reduce the amount of allocation by allocating more memory than needed
+ if document.used_text > len(document.text) {
+ new_text := make([]u8, document.used_text * 2);
- if document.used_text > len(document.text) {
- new_text := make([]u8, document.used_text * 2);
- copy(new_text, change.text);
- delete(document.text);
- document.text = new_text;
- }
+ //join the 3 splices into the text
+ copy(new_text, lower);
+ copy(new_text[len(lower):], middle);
+ copy(new_text[len(lower) + len(middle):], upper);
- else {
- copy(document.text, change.text);
- }
+ delete(document.text);
- }
+ document.text = new_text;
+ } else {
+ //order matters here, we need to make sure we swap the data already in the text before the middle
+ copy(document.text, lower);
+ copy(document.text[len(lower) + len(middle):], upper);
+ copy(document.text[len(lower):], middle);
+ }
+ } else {
+ document.used_text = len(change.text);
- }
+ if document.used_text > len(document.text) {
+ new_text := make([]u8, document.used_text * 2);
+ copy(new_text, change.text);
+ delete(document.text);
+ document.text = new_text;
+ } else {
+ copy(document.text, change.text);
+ }
+ }
+ }
- //log.info(string(document.text[:document.used_text]));
+ //log.info(string(document.text[:document.used_text]));
- return document_refresh(document, config, writer);
+ return document_refresh(document, config, writer);
}
-document_close :: proc(uri_string: string) -> common.Error {
+document_close :: proc (uri_string: string) -> common.Error {
- log.infof("document_close: %v", uri_string);
+ log.infof("document_close: %v", uri_string);
- uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator);
+ uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator);
- if !parsed_ok {
- return .ParseError;
- }
+ if !parsed_ok {
+ return .ParseError;
+ }
- document := &document_storage.documents[uri.path];
+ 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);
- return .InvalidRequest;
- }
+ if document == nil || !document.client_owned {
+ log.errorf("Client called close on a document that was never opened: %v ", document.uri.path);
+ return .InvalidRequest;
+ }
- free_all(common.scratch_allocator(document.allocator));
- document_free_allocator(document.allocator);
- document.allocator = nil;
+ free_all(common.scratch_allocator(document.allocator));
+ document_free_allocator(document.allocator);
+ document.allocator = nil;
- document.client_owned = false;
+ document.client_owned = false;
- common.delete_uri(document.uri);
+ common.delete_uri(document.uri);
- delete(document.text);
+ delete(document.text);
- document.used_text = 0;
+ document.used_text = 0;
- return .None;
+ return .None;
}
-
-
-document_refresh :: proc(document: ^Document, config: ^common.Config, writer: ^Writer) -> common.Error {
-
- errors, ok := parse_document(document, config);
-
- if !ok {
- return .ParseError;
- }
-
- if writer != nil && len(errors) > 0 {
- document.diagnosed_errors = true;
-
- params := NotificationPublishDiagnosticsParams {
- 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 {
- line = error.line - 1,
- character = 0,
- },
- end = common.Position {
- line = error.line,
- character = 0,
- },
- },
- severity = DiagnosticSeverity.Error,
- code = "test",
- message = error.message,
- };
-
- }
-
- notifaction := Notification {
- jsonrpc = "2.0",
- method = "textDocument/publishDiagnostics",
- params = params,
- };
-
- send_notification(notifaction, writer);
-
- }
-
- if writer != nil && len(errors) == 0 {
-
- //send empty diagnosis to remove the clients errors
- if document.diagnosed_errors {
-
- notifaction := Notification {
- jsonrpc = "2.0",
- method = "textDocument/publishDiagnostics",
-
- params = NotificationPublishDiagnosticsParams {
- uri = document.uri.uri,
- diagnostics = make([] Diagnostic, len(errors), context.temp_allocator),
- },
- };
-
- document.diagnosed_errors = false;
-
- send_notification(notifaction, writer);
- }
-
- }
-
- return .None;
+document_refresh :: proc (document: ^Document, config: ^common.Config, writer: ^Writer) -> common.Error {
+
+ errors, ok := parse_document(document, config);
+
+ if !ok {
+ return .ParseError;
+ }
+
+ if writer != nil && len(errors) > 0 {
+ document.diagnosed_errors = true;
+
+ params := NotificationPublishDiagnosticsParams {
+ 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 {
+ line = error.line - 1,
+ character = 0,
+ },
+ end = common.Position {
+ line = error.line,
+ character = 0,
+ },
+ },
+ severity = DiagnosticSeverity.Error,
+ code = "test",
+ message = error.message,
+ };
+ }
+
+ notifaction := Notification {
+ jsonrpc = "2.0",
+ method = "textDocument/publishDiagnostics",
+ params = params,
+ };
+
+ send_notification(notifaction, writer);
+ }
+
+ if writer != nil && len(errors) == 0 {
+
+ //send empty diagnosis to remove the clients errors
+ if document.diagnosed_errors {
+
+ notifaction := Notification {
+ jsonrpc = "2.0",
+ method = "textDocument/publishDiagnostics",
+ params = NotificationPublishDiagnosticsParams {
+ uri = document.uri.uri,
+ diagnostics = make([]Diagnostic, len(errors), context.temp_allocator),
+ },
+ };
+
+ document.diagnosed_errors = false;
+
+ send_notification(notifaction, writer);
+ }
+ }
+
+ return .None;
}
-current_errors: [dynamic] ParserError;
+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) };
- append(&current_errors, error);
+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),
+ };
+ append(&current_errors, error);
}
-parser_warning_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) {
-
+parser_warning_handler :: proc (pos: tokenizer.Pos, msg: string, args: ..any) {
}
-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,
+ p := parser.Parser {
+ err = parser_error_handler,
warn = parser_warning_handler,
};
- current_errors = make([dynamic] ParserError, context.temp_allocator);
-
- free_all(common.scratch_allocator(document.allocator));
-
- context.allocator = common.scratch_allocator(document.allocator);
+ current_errors = make([dynamic]ParserError, context.temp_allocator);
- //have to cheat the parser since it really wants to parse an entire package with the new changes...
- pkg := new(ast.Package);
- pkg.kind = .Normal;
- pkg.fullpath = document.uri.path;
+ free_all(common.scratch_allocator(document.allocator));
- document.ast = ast.File {
- fullpath = document.uri.path,
- src = document.text[:document.used_text],
- pkg = pkg,
- };
+ context.allocator = common.scratch_allocator(document.allocator);
- parser.parse_file(&p, &document.ast);
+ //have to cheat the parser since it really wants to parse an entire package with the new changes...
+ pkg := new(ast.Package);
+ pkg.kind = .Normal;
+ pkg.fullpath = document.uri.path;
- imports := make([dynamic]Package);
- document.package_name = strings.to_lower(path.dir(document.uri.path, context.temp_allocator));
+ document.ast = ast.File {
+ fullpath = document.uri.path,
+ src = document.text[:document.used_text],
+ pkg = pkg,
+ };
- for imp, index in document.ast.imports {
+ parser.parse_file(&p, &document.ast);
- if i := strings.index(imp.fullpath, "\""); i == -1 {
- continue;
- }
+ imports := make([dynamic]Package);
+ document.package_name = strings.to_lower(path.dir(document.uri.path, context.temp_allocator));
- //collection specified
- if i := strings.index(imp.fullpath, ":"); i != -1 && i > 1 && i < len(imp.fullpath) - 1 {
+ for imp, index in document.ast.imports {
- if len(imp.fullpath) < 2 {
- continue;
- }
+ if i := strings.index(imp.fullpath, "\""); i == -1 {
+ continue;
+ }
- collection := imp.fullpath[1:i];
- p := imp.fullpath[i+1:len(imp.fullpath)-1];
+ //collection specified
+ if i := strings.index(imp.fullpath, ":"); i != -1 && i > 1 && i < len(imp.fullpath) - 1 {
- dir, ok := config.collections[collection];
+ if len(imp.fullpath) < 2 {
+ continue;
+ }
- if !ok {
- continue;
- }
+ collection := imp.fullpath[1:i];
+ p := imp.fullpath[i + 1:len(imp.fullpath) - 1];
- import_: Package;
- import_.name = strings.clone(path.join(elems = {strings.to_lower(dir, context.temp_allocator), p}, allocator = context.temp_allocator));
+ dir, ok := config.collections[collection];
- if imp.name.text != "" {
- import_.base = imp.name.text;
- }
+ if !ok {
+ continue;
+ }
- else {
- import_.base = path.base(import_.name, false);
- }
+ import_: Package;
+ import_.name = strings.clone(path.join(elems = {strings.to_lower(dir, context.temp_allocator), p}, allocator = context.temp_allocator));
- append(&imports, import_);
- }
+ if imp.name.text != "" {
+ import_.base = imp.name.text;
+ } else {
+ import_.base = path.base(import_.name, false);
+ }
- //relative
- else {
+ append(&imports, import_);
+ } else
- if len(imp.fullpath) < 2 {
- continue;
- }
+ //relative
+ {
- import_: Package;
- 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 len(imp.fullpath) < 2 {
+ continue;
+ }
- if imp.name.text != "" {
- import_.base = imp.name.text;
- }
+ import_: Package;
+ 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);
- else {
- import_.base = path.base(import_.name, false);
- }
+ if imp.name.text != "" {
+ import_.base = imp.name.text;
+ } else {
+ import_.base = path.base(import_.name, false);
+ }
- append(&imports, import_);
- }
+ append(&imports, import_);
+ }
+ }
- }
+ document.imports = imports[:];
- document.imports = imports[:];
-
- return current_errors[:], true;
-}
+ return current_errors[:], true;
+} \ No newline at end of file
diff --git a/src/server/format.odin b/src/server/format.odin
index 46d21e2..3ad492c 100644
--- a/src/server/format.odin
+++ b/src/server/format.odin
@@ -5,51 +5,51 @@ import "shared:common"
import "core:odin/printer"
FormattingOptions :: struct {
- tabSize: uint,
- insertSpaces: bool, //tabs or spaces
+ tabSize: uint,
+ insertSpaces: bool, //tabs or spaces
trimTrailingWhitespace: bool,
- insertFinalNewline: bool,
- trimFinalNewlines: bool,
+ insertFinalNewline: bool,
+ trimFinalNewlines: bool,
}
DocumentFormattingParams :: struct {
textDocument: TextDocumentIdentifier,
- options: FormattingOptions,
+ options: FormattingOptions,
}
TextEdit :: struct {
- range: common.Range,
+ range: common.Range,
newText: string,
}
-get_complete_format :: proc(document: ^Document) -> ([] TextEdit, bool) {
+get_complete_format :: proc (document: ^Document) -> ([]TextEdit, bool) {
/*
- prnt := printer.make_printer(printer.default_style, context.temp_allocator);
+ prnt := printer.make_printer(printer.default_style, context.temp_allocator);
- printer.print_file(&prnt, &document.ast);
+ printer.print_file(&prnt, &document.ast);
- end_line := document.ast.decls[len(document.ast.decls)-1].end.line;
+ end_line := document.ast.decls[len(document.ast.decls)-1].end.line;
- edit := TextEdit {
+ edit := TextEdit {
newText = printer.to_string(prnt),
range = {
- start = {
- character = 0,
- line = 0,
- },
- end = {
- character = 1,
- line = end_line + 1,
- }
+ start = {
+ character = 0,
+ line = 0,
+ },
+ end = {
+ character = 1,
+ line = end_line + 1,
}
- };
+ }
+ };
- edits := make([dynamic] TextEdit, context.temp_allocator);
+ edits := make([dynamic] TextEdit, context.temp_allocator);
- append(&edits, edit);
+ append(&edits, edit);
- return edits[:], true;
+ return edits[:], true;
*/
return {}, false;
diff --git a/src/server/hover.odin b/src/server/hover.odin
index cd09f01..08d49ca 100644
--- a/src/server/hover.odin
+++ b/src/server/hover.odin
@@ -16,131 +16,123 @@ import "core:slice"
import "shared:common"
import "shared:index"
-get_hover_information :: proc(document: ^Document, position: common.Position) -> (Hover, bool) {
+get_hover_information :: proc (document: ^Document, position: common.Position) -> (Hover, bool) {
+
+ hover := Hover {
+ contents = {
+ kind = "plaintext"
+ }
+ };
+
+ ast_context := make_ast_context(document.ast, document.imports, document.package_name);
- hover := Hover {
- contents = {
- kind = "plaintext",
- }
- };
+ position_context, ok := get_document_position_context(document, position, .Hover);
+
+ get_globals(document.ast, &ast_context);
- ast_context := make_ast_context(document.ast, document.imports, document.package_name);
-
- 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);
- }
-
- 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);
- return hover, true;
- }
- }
- }
-
- if position_context.selector != nil && position_context.identifier != nil {
-
- 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 {
-
- ident := position_context.identifier.derived.(ast.Ident);
-
- if ident.name == base.name {
-
- if resolved, ok := resolve_type_identifier(&ast_context, ident); ok {
- resolved.name = ident.name;
- resolved.signature = get_signature(&ast_context, ident, resolved);
-
- if is_variable, ok := ast_context.variables[ident.name]; ok && is_variable {
- resolved.pkg = ast_context.document_package;
- }
-
- hover.contents = write_hover_content(&ast_context, resolved);
- return hover, true;
- }
-
- }
-
- }
-
- selector: index.Symbol;
- selector, ok = resolve_type_expression(&ast_context, position_context.selector);
-
- if !ok {
- return hover, true;
- }
-
- field: string;
-
- if position_context.field != nil {
-
- switch v in position_context.field.derived {
- case ast.Ident:
- field = v.name;
- }
-
- }
-
- hover.range = common.get_token_range(position_context.identifier^, document.ast.src);
-
- #partial switch v in selector.value {
- case index.SymbolStructValue:
- for name, i in v.names {
- if strings.compare(name, field) == 0 {
- if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok {
- symbol.name = name;
- symbol.pkg = selector.name;
- symbol.signature = index.node_to_string(v.types[i]);
- hover.contents = write_hover_content(&ast_context, symbol);
- return hover, true;
- }
- }
- }
- case index.SymbolPackageValue:
- if symbol, ok := index.lookup(field, selector.pkg); ok {
- hover.contents = write_hover_content(&ast_context, symbol);
- return hover, true;
- }
- }
-
- }
-
- else if position_context.identifier != nil {
-
- ast_context.use_locals = true;
- ast_context.use_globals = true;
- ast_context.current_package = ast_context.document_package;
-
- ident := position_context.identifier.derived.(ast.Ident);
-
- hover.range = common.get_token_range(position_context.identifier^, document.ast.src);
-
- if resolved, ok := resolve_type_identifier(&ast_context, ident); ok {
- resolved.name = ident.name;
- resolved.signature = get_signature(&ast_context, ident, resolved);
-
- if is_variable, ok := ast_context.variables[ident.name]; ok && is_variable {
- resolved.pkg = ast_context.document_package;
- }
-
- hover.contents = write_hover_content(&ast_context, resolved);
- return hover, true;
- }
-
- }
-
- return hover, true;
-}
+ if position_context.function != nil {
+ 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);
+ return hover, true;
+ }
+ }
+ }
+
+ if position_context.selector != nil && position_context.identifier != nil {
+
+ 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 {
+
+ ident := position_context.identifier.derived.(ast.Ident);
+
+ if ident.name == base.name {
+
+ if resolved, ok := resolve_type_identifier(&ast_context, ident); ok {
+ resolved.name = ident.name;
+ resolved.signature = get_signature(&ast_context, ident, resolved);
+
+ if is_variable, ok := ast_context.variables[ident.name]; ok && is_variable {
+ resolved.pkg = ast_context.document_package;
+ }
+
+ hover.contents = write_hover_content(&ast_context, resolved);
+ return hover, true;
+ }
+ }
+ }
+
+ selector: index.Symbol;
+ selector, ok = resolve_type_expression(&ast_context, position_context.selector);
+
+ if !ok {
+ return hover, true;
+ }
+
+ field: string;
+
+ if position_context.field != nil {
+
+ switch v in position_context.field.derived {
+ case ast.Ident:
+ field = v.name;
+ }
+ }
+
+ hover.range = common.get_token_range(position_context.identifier^, document.ast.src);
+
+ #partial switch v in selector.value {
+ case index.SymbolStructValue:
+ for name, i in v.names {
+ if strings.compare(name, field) == 0 {
+ if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok {
+ symbol.name = name;
+ symbol.pkg = selector.name;
+ symbol.signature = index.node_to_string(v.types[i]);
+ hover.contents = write_hover_content(&ast_context, symbol);
+ return hover, true;
+ }
+ }
+ }
+ case index.SymbolPackageValue:
+ if symbol, ok := index.lookup(field, selector.pkg); ok {
+ hover.contents = write_hover_content(&ast_context, symbol);
+ return hover, true;
+ }
+ }
+ } else if position_context.identifier != nil {
+
+ ast_context.use_locals = true;
+ ast_context.use_globals = true;
+ ast_context.current_package = ast_context.document_package;
+
+ ident := position_context.identifier.derived.(ast.Ident);
+
+ hover.range = common.get_token_range(position_context.identifier^, document.ast.src);
+
+ if resolved, ok := resolve_type_identifier(&ast_context, ident); ok {
+ resolved.name = ident.name;
+ resolved.signature = get_signature(&ast_context, ident, resolved);
+
+ if is_variable, ok := ast_context.variables[ident.name]; ok && is_variable {
+ resolved.pkg = ast_context.document_package;
+ }
+
+ hover.contents = write_hover_content(&ast_context, resolved);
+ return hover, true;
+ }
+ }
+
+ return hover, true;
+} \ No newline at end of file
diff --git a/src/server/log.odin b/src/server/log.odin
index d84a38d..77816a1 100644
--- a/src/server/log.odin
+++ b/src/server/log.odin
@@ -1,49 +1,47 @@
package server
-import "core:fmt";
-import "core:strings";
-import "core:os";
-import "core:time";
-import "core:log";
-
-Default_Console_Logger_Opts :: log.Options{
- .Level,
- .Terminal_Color,
- .Short_File_Path,
- .Line,
- .Procedure,
+import "core:fmt"
+import "core:strings"
+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;
-
Lsp_Logger_Data :: struct {
- writer: ^Writer,
+ writer: ^Writer,
}
-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};
+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};
}
-destroy_lsp_logger :: proc(log: ^log.Logger) {
- free(log.data);
+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) {
-
- data := cast(^Lsp_Logger_Data)logger_data;
+lsp_logger_proc :: proc (logger_data: rawptr, level: log.Level, text: string, options: log.Options, location := #caller_location) {
- message := fmt.tprintf("%s", text);
+ data := cast(^Lsp_Logger_Data)logger_data;
- notification := Notification {
- jsonrpc = "2.0",
- method = "window/logMessage",
- params = NotificationLoggingParams {
- type = 1,
- message = message,
- }
- };
+ message := fmt.tprintf("%s", text);
- send_notification(notification, data.writer);
-}
+ notification := Notification {
+ jsonrpc = "2.0",
+ method = "window/logMessage",
+ params = NotificationLoggingParams {
+ type = 1,
+ message = message,
+ },
+ };
+ send_notification(notification, data.writer);
+} \ No newline at end of file
diff --git a/src/server/reader.odin b/src/server/reader.odin
index f421d67..a3d5937 100644
--- a/src/server/reader.odin
+++ b/src/server/reader.odin
@@ -4,61 +4,57 @@ import "core:os"
import "core:mem"
import "core:strings"
-ReaderFn :: proc(rawptr, [] byte) -> (int, int);
+ReaderFn :: proc (_: rawptr, _: []byte) -> (int, int);
Reader :: struct {
- reader_fn: ReaderFn,
- reader_context: rawptr,
-};
-
-make_reader :: proc(reader_fn: ReaderFn, reader_context: rawptr) -> Reader {
- return Reader { reader_context = reader_context, reader_fn = reader_fn };
+ reader_fn: ReaderFn,
+ reader_context: rawptr,
}
+make_reader :: proc (reader_fn: ReaderFn, reader_context: rawptr) -> Reader {
+ return Reader {reader_context = reader_context, reader_fn = reader_fn};
+}
-read_u8 :: proc(reader: ^Reader) -> (u8, bool) {
+read_u8 :: proc (reader: ^Reader) -> (u8, bool) {
- value : [1] byte;
+ value: [1]byte;
- read, err := reader.reader_fn(reader.reader_context, value[:]);
+ read, err := reader.reader_fn(reader.reader_context, value[:]);
- if(err != 0 || read != 1) {
- return 0, false;
- }
+ if (err != 0 || read != 1) {
+ return 0, false;
+ }
- return value[0], true;
+ 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 {
+ for true {
- value, success := read_u8(reader);
+ value, success := read_u8(reader);
- if(!success) {
- return false;
- }
+ if (!success) {
+ return false;
+ }
- strings.write_byte(builder, value);
+ strings.write_byte(builder, value);
- if(value == delimiter) {
- break;
- }
- }
+ if (value == delimiter) {
+ break;
+ }
+ }
- return true;
+ return true;
}
-read_sized :: proc(reader: ^Reader, data: []u8) -> bool {
-
- read, err := reader.reader_fn(reader.reader_context, data);
-
- if(err != 0 || read != len(data)) {
- return false;
- }
-
- return true;
-}
+read_sized :: proc (reader: ^Reader, data: []u8) -> bool {
+ read, err := reader.reader_fn(reader.reader_context, data);
+ if (err != 0 || read != len(data)) {
+ return false;
+ }
+ return true;
+} \ No newline at end of file
diff --git a/src/server/requests.odin b/src/server/requests.odin
index 71dba0c..5a02fb3 100644
--- a/src/server/requests.odin
+++ b/src/server/requests.odin
@@ -21,1064 +21,1013 @@ import "shared:common"
import "shared:index"
Header :: struct {
- content_length: int,
- content_type: string,
-};
+ content_length: int,
+ content_type: string,
+}
RequestType :: enum {
- Initialize,
- Initialized,
- Shutdown,
- Exit,
- DidOpen,
- DidChange,
- DidClose,
- DidSave,
- Definition,
- Completion,
- SignatureHelp,
- DocumentSymbol,
- SemanticTokensFull,
- SemanticTokensRange,
- FormatDocument,
- Hover,
- CancelRequest,
-};
+ Initialize,
+ Initialized,
+ Shutdown,
+ Exit,
+ DidOpen,
+ DidChange,
+ DidClose,
+ DidSave,
+ Definition,
+ Completion,
+ SignatureHelp,
+ DocumentSymbol,
+ SemanticTokensFull,
+ SemanticTokensRange,
+ FormatDocument,
+ Hover,
+ CancelRequest,
+}
RequestInfo :: struct {
- root: json.Value,
- params: json.Value,
- document: ^Document,
- id: RequestId,
- config: ^common.Config,
- writer: ^Writer,
- result: common.Error,
-};
-
+ root: json.Value,
+ params: json.Value,
+ document: ^Document,
+ id: RequestId,
+ config: ^common.Config,
+ writer: ^Writer,
+ result: common.Error,
+}
pool: common.Pool;
-
-get_request_info :: proc(task: ^common.Task) -> ^RequestInfo {
- return cast(^RequestInfo)task.data;
+get_request_info :: proc (task: ^common.Task) -> ^RequestInfo {
+ return cast(^RequestInfo)task.data;
}
-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,
+ };
}
-read_and_parse_header :: proc(reader: ^Reader) -> (Header, bool) {
-
- header: Header;
-
- builder := strings.make_builder(context.temp_allocator);
+read_and_parse_header :: proc (reader: ^Reader) -> (Header, bool) {
- found_content_length := false;
+ header: Header;
- for true {
+ builder := strings.make_builder(context.temp_allocator);
- strings.reset_builder(&builder);
+ found_content_length := false;
- if !read_until_delimiter(reader, '\n', &builder) {
- log.error("Failed to read with delimiter");
- return header, false;
- }
+ for true {
- message := strings.to_string(builder);
+ strings.reset_builder(&builder);
- if len(message) == 0 || message[len(message)-2] != '\r' {
- log.error("No carriage return");
- return header, false;
- }
+ if !read_until_delimiter(reader, '\n', &builder) {
+ log.error("Failed to read with delimiter");
+ return header, false;
+ }
- if len(message)==2 {
- break;
- }
+ message := strings.to_string(builder);
- index := strings.last_index_byte(message, ':');
+ if len(message) == 0 || message[len(message) - 2] != '\r' {
+ log.error("No carriage return");
+ return header, false;
+ }
- if index == -1 {
- log.error("Failed to find semicolon");
- return header, false;
- }
+ if len(message) == 2 {
+ break;
+ }
- header_name := message[0:index];
- header_value := message[len(header_name) + 2 : len(message)-2];
+ index := strings.last_index_byte(message, ':');
- if strings.compare(header_name, "Content-Length") == 0 {
+ if index == -1 {
+ log.error("Failed to find semicolon");
+ return header, false;
+ }
- if len(header_value) == 0 {
- log.error("Header value has no length");
- return header, false;
- }
+ header_name := message[0:index];
+ header_value := message[len(header_name) + 2:len(message) - 2];
- value, ok := strconv.parse_int(header_value);
+ if strings.compare(header_name, "Content-Length") == 0 {
- if !ok {
- log.error("Failed to parse content length value");
- return header, false;
- }
+ if len(header_value) == 0 {
+ log.error("Header value has no length");
+ return header, false;
+ }
- header.content_length = value;
+ value, ok := strconv.parse_int(header_value);
- found_content_length = true;
+ if !ok {
+ log.error("Failed to parse content length value");
+ return header, false;
+ }
- }
+ header.content_length = value;
- else if strings.compare(header_name, "Content-Type") == 0 {
- if len(header_value) == 0 {
- log.error("Header value has no length");
- return header, false;
- }
- }
+ found_content_length = true;
+ } else if strings.compare(header_name, "Content-Type") == 0 {
+ if len(header_value) == 0 {
+ log.error("Header value has no length");
+ return header, false;
+ }
+ }
+ }
- }
-
- return header, found_content_length;
+ return header, found_content_length;
}
-read_and_parse_body :: proc(reader: ^Reader, header: Header) -> (json.Value, bool) {
-
- value: json.Value;
-
- data := make([]u8, header.content_length, context.temp_allocator);
+read_and_parse_body :: proc (reader: ^Reader, header: Header) -> (json.Value, bool) {
- if !read_sized(reader, data) {
- log.error("Failed to read body");
- return value, false;
- }
+ value: json.Value;
- err: json.Error;
+ data := make([]u8, header.content_length, context.temp_allocator);
- value, err = json.parse(data = data, allocator = context.allocator, parse_integers = true);
+ if !read_sized(reader, data) {
+ log.error("Failed to read body");
+ return value, false;
+ }
- if(err != json.Error.None) {
- log.error("Failed to parse body");
- return value, false;
- }
+ err: json.Error;
- return value, true;
-}
+ value, err = json.parse(data = data, allocator = context.allocator, parse_integers = true);
-request_map : map [string] RequestType =
- {"initialize" = .Initialize,
- "initialized" = .Initialized,
- "shutdown" = .Shutdown,
- "exit" = .Exit,
- "textDocument/didOpen" = .DidOpen,
- "textDocument/didChange" = .DidChange,
- "textDocument/didClose" = .DidClose,
- "textDocument/didSave" = .DidSave,
- "textDocument/definition" = .Definition,
- "textDocument/completion" = .Completion,
- "textDocument/signatureHelp" = .SignatureHelp,
- "textDocument/documentSymbol" = .DocumentSymbol,
- "textDocument/semanticTokens/full" = .SemanticTokensFull,
- "textDocument/semanticTokens/range" = .SemanticTokensRange,
- "textDocument/hover" = .Hover,
- "$/cancelRequest" = .CancelRequest,
- "textDocument/formatting" = .FormatDocument };
-
-handle_error :: proc(err: common.Error, id: RequestId, writer: ^Writer) {
-
- if err != .None {
-
- response := make_response_message_error(
- id = id,
- error = ResponseError {code = err, message = ""}
- );
-
- send_error(response, writer);
- }
+ if (err != json.Error.None) {
+ log.error("Failed to parse body");
+ return value, false;
+ }
+ return value, true;
}
-handle_request :: proc(request: json.Value, config: ^common.Config, writer: ^Writer) -> bool {
-
- root, ok := request.value.(json.Object);
-
- if !ok {
- log.error("No root object");
- return false;
- }
-
- id: RequestId;
- id_value: json.Value;
- id_value, ok = root["id"];
-
- if ok {
- #partial
- switch v in id_value.value {
- case json.String:
- id = v;
- case json.Integer:
- id = v;
- case:
- id = 0;
- }
- }
-
- method := root["method"].value.(json.String);
-
- request_type: RequestType;
- request_type, ok = request_map[method];
-
- if !ok {
- response := make_response_message_error(
- id = id,
- error = ResponseError {code = .MethodNotFound, message = ""}
- );
-
- send_error(response, writer);
- }
-
- else {
-
- info := new(RequestInfo);
-
- info.root = request;
- info.params = root["params"];
- info.id = id;
- info.config = config;
- info.writer = writer;
-
- task_proc: common.Task_Proc;
-
- switch request_type {
- case .Initialize:
- task_proc = request_initialize;
- case .Initialized:
- task_proc = request_initialized;
- case .Shutdown:
- task_proc = request_shutdown;
- case .Exit:
- task_proc = notification_exit;
- case .DidOpen:
- task_proc = notification_did_open;
- case .DidChange:
- task_proc = notification_did_change;
- case .DidClose:
- task_proc = notification_did_close;
- case .DidSave:
- task_proc = notification_did_save;
- case .Definition:
- task_proc = request_definition;
- case .Completion:
- task_proc = request_completion;
- case .SignatureHelp:
- task_proc = request_signature_help;
- case .DocumentSymbol:
- task_proc = request_document_symbols;
- case .SemanticTokensFull:
- task_proc = request_semantic_token_full;
- case .SemanticTokensRange:
- task_proc = request_semantic_token_range;
- case .Hover:
- task_proc = request_hover;
- case .CancelRequest:
- case .FormatDocument:
- task_proc = request_format_document;
- }
-
- task := common.Task {
- data = info,
- procedure = task_proc,
- };
-
- #partial switch request_type {
- case .CancelRequest:
- for {
- if task, ok := common.pool_try_and_pop_task(&pool); ok {
- common.pool_do_work(&pool, &task);
- }
-
- else {
- break;
- }
- }
- case .Initialize, .Initialized:
- task_proc(&task);
- case .Completion, .Definition, .Hover, .FormatDocument:
-
- uri := root["params"].value.(json.Object)["textDocument"].value.(json.Object)["uri"].value.(json.String);
-
- document := document_get(uri);
-
- if document == nil {
- handle_error(.InternalError, id, writer);
- return false;
- }
-
- info.document = document;
-
- task_proc(&task);
-
- case .DidClose, .DidChange, .DidOpen, .DidSave:
-
- uri := root["params"].value.(json.Object)["textDocument"].value.(json.Object)["uri"].value.(json.String);
-
- document := document_get(uri);
-
- if document != nil {
-
- for intrinsics.atomic_load(&document.operating_on) > 1 {
- if task, ok := common.pool_try_and_pop_task(&pool); ok {
- common.pool_do_work(&pool, &task);
- }
- }
-
- }
-
- task_proc(&task);
-
- document_release(document);
- case .Shutdown, .Exit:
- task_proc(&task);
- case .SignatureHelp, .SemanticTokensFull, .SemanticTokensRange, .DocumentSymbol:
-
- uri := root["params"].value.(json.Object)["textDocument"].value.(json.Object)["uri"].value.(json.String);
-
- document := document_get(uri);
-
- if document == nil {
- handle_error(.InternalError, id, writer);
- return false;
- }
-
- info.document = document;
-
- if !config.debug_single_thread {
- common.pool_add_task(&pool, task_proc, info);
- }
-
- else{
- task_proc(&task);
- }
- case:
-
- if !config.debug_single_thread {
- common.pool_add_task(&pool, task_proc, info);
- }
+request_map: map[string]RequestType = {
+ "initialize" = .Initialize,
+ "initialized" = .Initialized,
+ "shutdown" = .Shutdown,
+ "exit" = .Exit,
+ "textDocument/didOpen" = .DidOpen,
+ "textDocument/didChange" = .DidChange,
+ "textDocument/didClose" = .DidClose,
+ "textDocument/didSave" = .DidSave,
+ "textDocument/definition" = .Definition,
+ "textDocument/completion" = .Completion,
+ "textDocument/signatureHelp" = .SignatureHelp,
+ "textDocument/documentSymbol" = .DocumentSymbol,
+ "textDocument/semanticTokens/full" = .SemanticTokensFull,
+ "textDocument/semanticTokens/range" = .SemanticTokensRange,
+ "textDocument/hover" = .Hover,
+ "$/cancelRequest" = .CancelRequest,
+ "textDocument/formatting" = .FormatDocument,
+};
- else {
- task_proc(&task);
- }
- }
+handle_error :: proc (err: common.Error, id: RequestId, writer: ^Writer) {
- }
+ if err != .None {
+ response := make_response_message_error(
+ id = id,
+ error = ResponseError {code = err, message = ""});
- return true;
+ send_error(response, writer);
+ }
}
-request_initialize :: proc(task: ^common.Task) {
- info := get_request_info(task);
-
- using info;
-
- defer json.destroy_value(root);
- defer free(info);
-
- params_object, ok := params.value.(json.Object);
-
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
-
- initialize_params: RequestInitializeParams;
-
- if unmarshal(params, initialize_params, context.temp_allocator) != .None {
- handle_error(.ParseError, id, writer);
- return;
- }
-
- config.workspace_folders = make([dynamic]common.WorkspaceFolder);
-
- for s in initialize_params.workspaceFolders {
- append(&config.workspace_folders, s);
- }
-
- thread_count := 2;
-
- enable_document_symbols: bool;
- enable_hover: bool;
- enable_format: bool;
-
- if len(config.workspace_folders) > 0 {
-
- //right now just look at the first workspace - TODO(daniel, add multiple workspace support)
- if uri, ok := common.parse_uri(config.workspace_folders[0].uri, context.temp_allocator); ok {
-
- ols_config_path := path.join(elems = {uri.path, "ols.json"}, allocator = context.temp_allocator);
-
- if data, ok := os.read_entire_file(ols_config_path, 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) == .None {
-
- thread_count = ols_config.thread_pool_count;
- enable_document_symbols = ols_config.enable_document_symbols;
- enable_hover = ols_config.enable_hover;
- enable_format = ols_config.enable_format;
- config.enable_semantic_tokens = ols_config.enable_semantic_tokens;
- config.verbose = ols_config.verbose;
-
- for p in ols_config.collections {
-
- forward_path, _ := filepath.to_slash(p.path, context.temp_allocator);
-
- if filepath.is_abs(p.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);
- }
-
- }
-
- }
-
- }
-
- }
-
- }
-
- }
-
- common.pool_init(&pool, thread_count);
- common.pool_start(&pool);
-
- for format in initialize_params.capabilities.textDocument.hover.contentFormat {
- if format == "markdown" {
- config.hover_support_md = true;
- }
- }
-
-
- for format in initialize_params.capabilities.textDocument.completion.documentationFormat {
- if format == "markdown" {
- config.completion_support_md = true;
- }
- }
+handle_request :: proc (request: json.Value, config: ^common.Config, writer: ^Writer) -> bool {
+
+ root, ok := request.value.(json.Object);
+
+ if !ok {
+ log.error("No root object");
+ return false;
+ }
+
+ id: RequestId;
+ id_value: json.Value;
+ id_value, ok = root["id"];
+
+ if ok {
+
+ #partial switch v in id_value.value {
+ case json.String:
+ id = v;
+ case json.Integer:
+ id = v;
+ case:
+ id = 0;
+ }
+ }
+
+ method := root["method"].value.(json.String);
+
+ request_type: RequestType;
+ request_type, ok = request_map[method];
+
+ if !ok {
+ response := make_response_message_error(
+ id = id,
+ error = ResponseError {code = .MethodNotFound, message = ""});
+
+ send_error(response, writer);
+ } else {
+
+ info := new(RequestInfo);
+
+ info.root = request;
+ info.params = root["params"];
+ info.id = id;
+ info.config = config;
+ info.writer = writer;
+
+ task_proc: common.Task_Proc;
+
+ switch request_type {
+ case .Initialize:
+ task_proc = request_initialize;
+ case .Initialized:
+ task_proc = request_initialized;
+ case .Shutdown:
+ task_proc = request_shutdown;
+ case .Exit:
+ task_proc = notification_exit;
+ case .DidOpen:
+ task_proc = notification_did_open;
+ case .DidChange:
+ task_proc = notification_did_change;
+ case .DidClose:
+ task_proc = notification_did_close;
+ case .DidSave:
+ task_proc = notification_did_save;
+ case .Definition:
+ task_proc = request_definition;
+ case .Completion:
+ task_proc = request_completion;
+ case .SignatureHelp:
+ task_proc = request_signature_help;
+ case .DocumentSymbol:
+ task_proc = request_document_symbols;
+ case .SemanticTokensFull:
+ task_proc = request_semantic_token_full;
+ case .SemanticTokensRange:
+ task_proc = request_semantic_token_range;
+ case .Hover:
+ task_proc = request_hover;
+ case .CancelRequest:
+ case .FormatDocument:
+ task_proc = request_format_document;
+ }
+
+ task := common.Task {
+ data = info,
+ procedure = task_proc,
+ };
+
+ #partial switch request_type {
+ case .CancelRequest:
+ for {
+ if task, ok := common.pool_try_and_pop_task(&pool); ok {
+ common.pool_do_work(&pool, &task);
+ } else {
+ break;
+ }
+ }
+ case .Initialize,.Initialized:
+ task_proc(&task);
+ case .Completion,.Definition,.Hover,.FormatDocument:
+
+ uri := root["params"].value.(json.Object)["textDocument"].value.(json.Object)["uri"].value.(json.String);
+
+ document := document_get(uri);
+
+ if document == nil {
+ handle_error(.InternalError, id, writer);
+ return false;
+ }
+
+ info.document = document;
+
+ task_proc(&task);
+
+ case .DidClose,.DidChange,.DidOpen,.DidSave:
+
+ uri := root["params"].value.(json.Object)["textDocument"].value.(json.Object)["uri"].value.(json.String);
+
+ document := document_get(uri);
+
+ if document != nil {
+
+ for intrinsics.atomic_load(&document.operating_on) > 1 {
+ if task, ok := common.pool_try_and_pop_task(&pool); ok {
+ common.pool_do_work(&pool, &task);
+ }
+ }
+ }
+
+ task_proc(&task);
+
+ document_release(document);
+ case .Shutdown,.Exit:
+ task_proc(&task);
+ case .SignatureHelp,.SemanticTokensFull,.SemanticTokensRange,.DocumentSymbol:
+
+ uri := root["params"].value.(json.Object)["textDocument"].value.(json.Object)["uri"].value.(json.String);
+
+ document := document_get(uri);
+
+ if document == nil {
+ handle_error(.InternalError, id, writer);
+ return false;
+ }
+
+ info.document = document;
+
+ if !config.debug_single_thread {
+ common.pool_add_task(&pool, task_proc, info);
+ } else {
+ task_proc(&task);
+ }
+ case:
+
+ if !config.debug_single_thread {
+ common.pool_add_task(&pool, task_proc, info);
+ } else {
+ task_proc(&task);
+ }
+ }
+ }
+
+ return true;
+}
+request_initialize :: proc (task: ^common.Task) {
+ info := get_request_info(task);
- config.signature_offset_support = initialize_params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport;
+ using info;
- completionTriggerCharacters := [] string { ".", ">", "#" };
- signatureTriggerCharacters := [] string { "(" };
+ defer json.destroy_value(root);
+ defer free(info);
- 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);
+ params_object, ok := params.value.(json.Object);
- token_types := make([] string, len(token_type.names), context.temp_allocator);
- token_modifiers := make([] string, len(token_modifier.names), context.temp_allocator);
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- for name, i in token_type.names {
- token_types[i] = strings.to_lower(name, context.temp_allocator);
- }
+ initialize_params: RequestInitializeParams;
- for name, i in token_modifier.names {
- token_modifiers[i] = strings.to_lower(name, context.temp_allocator);
- }
+ if unmarshal(params, initialize_params, context.temp_allocator) != .None {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- response := make_response_message(
- params = ResponseInitializeParams {
- capabilities = ServerCapabilities {
- textDocumentSync = TextDocumentSyncOptions {
- openClose = true,
- change = 2, //incremental
- save = {
- includeText = true,
- }
- },
- definitionProvider = true,
- completionProvider = CompletionOptions {
- resolveProvider = false,
- triggerCharacters = completionTriggerCharacters,
- },
- signatureHelpProvider = SignatureHelpOptions {
- triggerCharacters = signatureTriggerCharacters,
- },
- semanticTokensProvider = SemanticTokensOptions {
- range = false,
- full = config.enable_semantic_tokens,
- legend = SemanticTokensLegend {
- tokenTypes = token_types,
- tokenModifiers = token_modifiers,
- },
- },
- documentSymbolProvider = enable_document_symbols,
- hoverProvider = enable_hover,
- documentFormattingProvider = enable_format,
- },
- },
- id = id,
- );
-
- send_response(response, writer);
+ config.workspace_folders = make([dynamic]common.WorkspaceFolder);
- /*
- Temp index here, but should be some background thread that starts the indexing
- */
+ for s in initialize_params.workspaceFolders {
+ append(&config.workspace_folders, s);
+ }
- index.indexer.dynamic_index = index.make_memory_index(index.make_symbol_collection(context.allocator, config));
+ thread_count := 2;
- index.build_static_index(context.allocator, config);
+ enable_document_symbols: bool;
+ enable_hover: bool;
+ enable_format: bool;
+
+ if len(config.workspace_folders) > 0 {
+
+ //right now just look at the first workspace - TODO(daniel, add multiple workspace support)
+ if uri, ok := common.parse_uri(config.workspace_folders[0].uri, context.temp_allocator); ok {
+
+ ols_config_path := path.join(elems = {uri.path, "ols.json"}, allocator = context.temp_allocator);
+
+ if data, ok := os.read_entire_file(ols_config_path, 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) == .None {
- /*
- Add the builtin and runtime package
- */
+ thread_count = ols_config.thread_pool_count;
+ enable_document_symbols = ols_config.enable_document_symbols;
+ enable_hover = ols_config.enable_hover;
+ enable_format = ols_config.enable_format;
+ config.enable_semantic_tokens = ols_config.enable_semantic_tokens;
+ config.verbose = ols_config.verbose;
+
+ for p in ols_config.collections {
- if core, ok := config.collections["core"]; ok {
- append(&index.indexer.built_in_packages, path.join(strings.to_lower(core, context.temp_allocator), "builtin"));
- append(&index.indexer.built_in_packages, path.join(strings.to_lower(core, context.temp_allocator), "runtime"));
- }
-
- log.info("Finished indexing");
+ forward_path, _ := filepath.to_slash(p.path, context.temp_allocator);
+
+ if filepath.is_abs(p.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);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ common.pool_init(&pool, thread_count);
+ common.pool_start(&pool);
+
+ for format in initialize_params.capabilities.textDocument.hover.contentFormat {
+ if format == "markdown" {
+ config.hover_support_md = true;
+ }
+ }
+
+ for format in initialize_params.capabilities.textDocument.completion.documentationFormat {
+ if format == "markdown" {
+ config.completion_support_md = true;
+ }
+ }
+
+ config.signature_offset_support = initialize_params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport;
+
+ completionTriggerCharacters := []string {".", ">", "#"};
+ signatureTriggerCharacters := []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_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 {
+ token_types[i] = strings.to_lower(name, context.temp_allocator);
+ }
+
+ for name, i in token_modifier.names {
+ token_modifiers[i] = strings.to_lower(name, context.temp_allocator);
+ }
+
+ response := make_response_message(
+ params = ResponseInitializeParams {
+ capabilities = ServerCapabilities {
+ textDocumentSync = TextDocumentSyncOptions {
+ openClose = true,
+ change = 2, //incremental
+ save = {
+ includeText = true
+ },
+ },
+ definitionProvider = true,
+ completionProvider = CompletionOptions {
+ resolveProvider = false,
+ triggerCharacters = completionTriggerCharacters,
+ },
+ signatureHelpProvider = SignatureHelpOptions {
+ triggerCharacters = signatureTriggerCharacters
+ },
+ semanticTokensProvider = SemanticTokensOptions {
+ range = false,
+ full = config.enable_semantic_tokens,
+ legend = SemanticTokensLegend {
+ tokenTypes = token_types,
+ tokenModifiers = token_modifiers,
+ },
+ },
+ documentSymbolProvider = enable_document_symbols,
+ hoverProvider = enable_hover,
+ documentFormattingProvider = enable_format,
+ }
+ },
+ id = id);
+
+ send_response(response, writer);
+
+ /*
+ Temp index here, but should be some background thread that starts the indexing
+ */
+
+ index.indexer.dynamic_index = index.make_memory_index(index.make_symbol_collection(context.allocator, config));
+
+ index.build_static_index(context.allocator, config);
+
+ /*
+ Add the builtin and runtime package
+ */
+
+ if core, ok := config.collections["core"]; ok {
+ append(&index.indexer.built_in_packages, path.join(strings.to_lower(core, context.temp_allocator), "builtin"));
+ append(&index.indexer.built_in_packages, path.join(strings.to_lower(core, context.temp_allocator), "runtime"));
+ }
+
+ log.info("Finished indexing");
}
-request_initialized :: proc(task: ^common.Task) {
- info := get_request_info(task);
+request_initialized :: proc (task: ^common.Task) {
+ info := get_request_info(task);
- using info;
+ using info;
- json.destroy_value(root);
- free(info);
+ json.destroy_value(root);
+ free(info);
}
-request_shutdown :: proc(task: ^common.Task) {
-
- info := get_request_info(task);
+request_shutdown :: proc (task: ^common.Task) {
- using info;
+ info := get_request_info(task);
- defer json.destroy_value(root);
- defer free(info);
+ using info;
- response := make_response_message(
- params = nil,
- id = id,
- );
-
- send_response(response, writer);
+ defer json.destroy_value(root);
+ defer free(info);
+ response := make_response_message(
+ params = nil,
+ id = id);
+ send_response(response, writer);
}
-request_definition :: proc(task: ^common.Task) {
+request_definition :: proc (task: ^common.Task) {
- info := get_request_info(task);
+ info := get_request_info(task);
- using info;
+ using info;
- defer document_release(document);
- defer free(info);
- defer json.destroy_value(root);
+ defer document_release(document);
+ defer free(info);
+ defer json.destroy_value(root);
- params_object, ok := params.value.(json.Object);
+ params_object, ok := params.value.(json.Object);
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- definition_params: TextDocumentPositionParams;
+ definition_params: TextDocumentPositionParams;
- if unmarshal(params, definition_params, context.temp_allocator) != .None {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if unmarshal(params, definition_params, context.temp_allocator) != .None {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- location, ok2 := get_definition_location(document, definition_params.position);
+ location, ok2 := get_definition_location(document, definition_params.position);
- if !ok2 {
- log.warn("Failed to get definition location");
- }
+ if !ok2 {
+ log.warn("Failed to get definition location");
+ }
- response := make_response_message(
- params = location,
- id = id,
- );
+ response := make_response_message(
+ params = location,
+ id = id);
- send_response(response, writer);
+ send_response(response, writer);
}
+request_completion :: proc (task: ^common.Task) {
-request_completion :: proc(task: ^common.Task) {
-
- info := get_request_info(task);
+ info := get_request_info(task);
- using info;
+ using info;
- defer document_release(document);
- defer json.destroy_value(root);
- defer free(info);
+ defer document_release(document);
+ defer json.destroy_value(root);
+ defer free(info);
- params_object, ok := params.value.(json.Object);
+ params_object, ok := params.value.(json.Object);
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- completition_params: CompletionParams;
+ completition_params: CompletionParams;
+ if unmarshal(params, completition_params, context.temp_allocator) != .None {
+ log.error("Failed to unmarshal completion request");
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- if unmarshal(params, completition_params, context.temp_allocator) != .None {
- log.error("Failed to unmarshal completion request");
- handle_error(.ParseError, id, writer);
- return;
- }
+ list: CompletionList;
+ list, ok = get_completion_list(document, completition_params.position);
- list: CompletionList;
- list, ok = get_completion_list(document, completition_params.position);
+ if !ok {
+ handle_error(.InternalError, id, writer);
+ return;
+ }
- if !ok {
- handle_error(.InternalError, id, writer);
- return;
- }
+ response := make_response_message(
+ params = list,
+ id = id);
- response := make_response_message(
- params = list,
- id = id,
- );
-
- send_response(response, writer);
+ send_response(response, writer);
}
-request_signature_help :: proc(task: ^common.Task) {
+request_signature_help :: proc (task: ^common.Task) {
- info := get_request_info(task);
+ info := get_request_info(task);
- using info;
+ using info;
- defer document_release(document);
- defer json.destroy_value(root);
- defer free(info);
+ defer document_release(document);
+ defer json.destroy_value(root);
+ defer free(info);
- params_object, ok := params.value.(json.Object);
+ params_object, ok := params.value.(json.Object);
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- signature_params: SignatureHelpParams;
+ signature_params: SignatureHelpParams;
- if unmarshal(params, signature_params, context.temp_allocator) != .None {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if unmarshal(params, signature_params, context.temp_allocator) != .None {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- help: SignatureHelp;
- help, ok = get_signature_information(document, signature_params.position);
+ help: SignatureHelp;
+ help, ok = get_signature_information(document, signature_params.position);
- if !ok {
- handle_error(.InternalError, id, writer);
- return;
- }
+ if !ok {
+ handle_error(.InternalError, id, writer);
+ return;
+ }
- response := make_response_message(
- params = help,
- id = id,
- );
+ response := make_response_message(
+ params = help,
+ id = id);
- send_response(response, writer);
+ send_response(response, writer);
}
-request_format_document :: proc(task: ^common.Task) {
-
- info := get_request_info(task);
+request_format_document :: proc (task: ^common.Task) {
- using info;
+ info := get_request_info(task);
- defer document_release(document);
- defer json.destroy_value(root);
- defer free(info);
+ using info;
- params_object, ok := params.value.(json.Object);
+ defer document_release(document);
+ defer json.destroy_value(root);
+ defer free(info);
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ params_object, ok := params.value.(json.Object);
- format_params: DocumentFormattingParams;
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- if unmarshal(params, format_params, context.temp_allocator) != .None {
- handle_error(.ParseError, id, writer);
- return;
- }
+ format_params: DocumentFormattingParams;
- edit: [] TextEdit;
- edit, ok = get_complete_format(document);
+ if unmarshal(params, format_params, context.temp_allocator) != .None {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- if !ok {
- handle_error(.InternalError, id, writer);
- return;
- }
+ edit: []TextEdit;
+ edit, ok = get_complete_format(document);
- response := make_response_message(
- params = edit,
- id = id,
- );
+ if !ok {
+ handle_error(.InternalError, id, writer);
+ return;
+ }
- send_response(response, writer);
+ response := make_response_message(
+ params = edit,
+ id = id);
+ send_response(response, writer);
}
-notification_exit :: proc(task: ^common.Task) {
- info := get_request_info(task);
- using info;
+notification_exit :: proc (task: ^common.Task) {
+ info := get_request_info(task);
+ using info;
- defer json.destroy_value(root);
- defer free(info);
+ defer json.destroy_value(root);
+ defer free(info);
- config.running = false;
+ config.running = false;
}
-notification_did_open :: proc(task: ^common.Task) {
+notification_did_open :: proc (task: ^common.Task) {
- info := get_request_info(task);
+ info := get_request_info(task);
- using info;
+ using info;
- defer json.destroy_value(root);
- defer free(info);
+ defer json.destroy_value(root);
+ defer free(info);
- params_object, ok := params.value.(json.Object);
+ params_object, ok := params.value.(json.Object);
- if !ok {
- log.error("Failed to parse open document notification");
- handle_error(.ParseError, id, writer);
- return;
- }
+ if !ok {
+ log.error("Failed to parse open document notification");
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- open_params: DidOpenTextDocumentParams;
+ open_params: DidOpenTextDocumentParams;
- if unmarshal(params, open_params, context.allocator) != .None {
- log.error("Failed to parse open document notification");
- handle_error(.ParseError, id, writer);
- return;
- }
+ if unmarshal(params, open_params, context.allocator) != .None {
+ log.error("Failed to parse open document notification");
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- if n := document_open(open_params.textDocument.uri, open_params.textDocument.text, config, writer); n != .None {
- handle_error(n, id, writer);
- }
+ if n := document_open(open_params.textDocument.uri, open_params.textDocument.text, config, writer); n != .None {
+ handle_error(n, id, writer);
+ }
}
-notification_did_change :: proc(task: ^common.Task) {
+notification_did_change :: proc (task: ^common.Task) {
- info := get_request_info(task);
+ info := get_request_info(task);
- using info;
+ using info;
- defer json.destroy_value(root);
- defer free(info);
+ defer json.destroy_value(root);
+ defer free(info);
- params_object, ok := params.value.(json.Object);
+ params_object, ok := params.value.(json.Object);
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- change_params: DidChangeTextDocumentParams;
+ change_params: DidChangeTextDocumentParams;
- if unmarshal(params, change_params, context.temp_allocator) != .None {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if unmarshal(params, change_params, context.temp_allocator) != .None {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
-
- document_apply_changes(change_params.textDocument.uri, change_params.contentChanges, config, writer);
+ document_apply_changes(change_params.textDocument.uri, change_params.contentChanges, config, writer);
}
-notification_did_close :: proc(task: ^common.Task) {
+notification_did_close :: proc (task: ^common.Task) {
- info := get_request_info(task);
+ info := get_request_info(task);
- using info;
+ using info;
- defer json.destroy_value(root);
- defer free(info);
+ defer json.destroy_value(root);
+ defer free(info);
- params_object, ok := params.value.(json.Object);
+ params_object, ok := params.value.(json.Object);
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- close_params: DidCloseTextDocumentParams;
+ close_params: DidCloseTextDocumentParams;
- if unmarshal(params, close_params, context.temp_allocator) != .None {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if unmarshal(params, close_params, context.temp_allocator) != .None {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- if n := document_close(close_params.textDocument.uri); n != .None {
- handle_error(n, id, writer);
- return;
- }
+ if n := document_close(close_params.textDocument.uri); n != .None {
+ handle_error(n, id, writer);
+ return;
+ }
}
-notification_did_save :: proc(task: ^common.Task) {
- info := get_request_info(task);
-
- using info;
+notification_did_save :: proc (task: ^common.Task) {
+ info := get_request_info(task);
+ using info;
- defer json.destroy_value(root);
- defer free(info);
+ defer json.destroy_value(root);
+ defer free(info);
- //this is temporary, but will provide dynamic indexing and is syncronized
+ //this is temporary, but will provide dynamic indexing and is syncronized
- params_object, ok := params.value.(json.Object);
+ params_object, ok := params.value.(json.Object);
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- save_params: DidSaveTextDocumentParams;
+ save_params: DidSaveTextDocumentParams;
- if unmarshal(params, save_params, context.temp_allocator) != .None {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if unmarshal(params, save_params, context.temp_allocator) != .None {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- uri: common.Uri;
+ uri: common.Uri;
- if uri, ok = common.parse_uri(save_params.textDocument.uri, context.temp_allocator); !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if uri, ok = common.parse_uri(save_params.textDocument.uri, context.temp_allocator); !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- fullpath := uri.path;
+ fullpath := uri.path;
- p := parser.Parser {
- err = index.log_error_handler,
- warn = index.log_warning_handler,
- };
+ p := parser.Parser {
+ err = index.log_error_handler,
+ warn = index.log_warning_handler,
+ };
- //have to cheat the parser since it really wants to parse an entire package with the new changes...
- dir := filepath.base(filepath.dir(fullpath, context.temp_allocator));
+ //have to cheat the parser since it really wants to parse an entire package with the new changes...
+ dir := filepath.base(filepath.dir(fullpath, context.temp_allocator));
- pkg := new(ast.Package);
- pkg.kind = .Normal;
- pkg.fullpath = fullpath;
- pkg.name = dir;
+ pkg := new(ast.Package);
+ pkg.kind = .Normal;
+ pkg.fullpath = fullpath;
+ pkg.name = dir;
- if dir == "runtime" {
- pkg.kind = .Runtime;
- }
+ if dir == "runtime" {
+ pkg.kind = .Runtime;
+ }
- file := ast.File {
- fullpath = fullpath,
- src = transmute([]u8)save_params.text,
- pkg = pkg,
- };
+ file := ast.File {
+ fullpath = fullpath,
+ src = transmute([]u8)save_params.text,
+ pkg = pkg,
+ };
- ok = parser.parse_file(&p, &file);
+ ok = parser.parse_file(&p, &file);
- if !ok {
- log.errorf("error in parse file for indexing %v", fullpath);
- }
+ if !ok {
+ log.errorf("error in parse file for indexing %v", fullpath);
+ }
- for key, value in index.indexer.dynamic_index.collection.symbols {
+ for key, value in index.indexer.dynamic_index.collection.symbols {
- if value.uri == save_params.textDocument.uri {
- index.free_symbol(value, context.allocator);
- index.indexer.dynamic_index.collection.symbols[key] = {};
- }
-
- }
-
- if ret := index.collect_symbols(&index.indexer.dynamic_index.collection, file, uri.uri); ret != .None {
- log.errorf("failed to collect symbols on save %v", ret);
- }
+ if value.uri == save_params.textDocument.uri {
+ index.free_symbol(value, context.allocator);
+ index.indexer.dynamic_index.collection.symbols[key] = {};
+ }
+ }
+ if ret := index.collect_symbols(&index.indexer.dynamic_index.collection, file, uri.uri); ret != .None {
+ log.errorf("failed to collect symbols on save %v", ret);
+ }
}
-request_semantic_token_full :: proc(task: ^common.Task) {
-
- info := get_request_info(task);
+request_semantic_token_full :: proc (task: ^common.Task) {
- using info;
+ info := get_request_info(task);
- defer document_release(document);
- defer json.destroy_value(root);
- defer free(info);
+ using info;
- params_object, ok := params.value.(json.Object);
+ defer document_release(document);
+ defer json.destroy_value(root);
+ defer free(info);
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ params_object, ok := params.value.(json.Object);
- semantic_params: SemanticTokensParams;
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- if unmarshal(params, semantic_params, context.temp_allocator) != .None {
- handle_error(.ParseError, id, writer);
- return;
- }
+ semantic_params: SemanticTokensParams;
- range := common.Range {
- start = common.Position {
- line = 0,
- },
+ if unmarshal(params, semantic_params, context.temp_allocator) != .None {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- end = common.Position {
- line = 9000000, //should be enough
- }
- };
+ range := common.Range {
+ start = common.Position {
+ line = 0
+ },
+ end = common.Position {
+ line = 9000000 //should be enough
+ },
+ };
- symbols: SemanticTokens;
+ symbols: SemanticTokens;
- if config.enable_semantic_tokens {
- symbols = get_semantic_tokens(document, range);
- }
+ if config.enable_semantic_tokens {
+ symbols = get_semantic_tokens(document, range);
+ }
- response := make_response_message(
- params = symbols,
- id = id,
- );
+ response := make_response_message(
+ params = symbols,
+ id = id);
- send_response(response, writer);
+ send_response(response, writer);
}
-request_semantic_token_range :: proc(task: ^common.Task) {
+request_semantic_token_range :: proc (task: ^common.Task) {
- info := get_request_info(task);
+ info := get_request_info(task);
- using info;
+ using info;
- params_object, ok := params.value.(json.Object);
+ params_object, ok := params.value.(json.Object);
- defer document_release(document);
- defer json.destroy_value(root);
- defer free(info);
+ defer document_release(document);
+ defer json.destroy_value(root);
+ defer free(info);
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- semantic_params: SemanticTokensRangeParams;
+ semantic_params: SemanticTokensRangeParams;
- if unmarshal(params, semantic_params, context.temp_allocator) != .None {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if unmarshal(params, semantic_params, context.temp_allocator) != .None {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- symbols: SemanticTokens;
+ symbols: SemanticTokens;
- if config.enable_semantic_tokens {
- symbols = get_semantic_tokens(document, semantic_params.range);
- }
+ if config.enable_semantic_tokens {
+ symbols = get_semantic_tokens(document, semantic_params.range);
+ }
- response := make_response_message(
- params = symbols,
- id = id,
- );
+ response := make_response_message(
+ params = symbols,
+ id = id);
- send_response(response, writer);
+ send_response(response, writer);
}
-request_document_symbols :: proc(task: ^common.Task) {
+request_document_symbols :: proc (task: ^common.Task) {
- info := get_request_info(task);
+ info := get_request_info(task);
- using info;
+ using info;
- defer document_release(document);
- defer json.destroy_value(root);
- defer free(info);
+ defer document_release(document);
+ defer json.destroy_value(root);
+ defer free(info);
- params_object, ok := params.value.(json.Object);
+ params_object, ok := params.value.(json.Object);
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- symbol_params: DocumentSymbolParams;
+ symbol_params: DocumentSymbolParams;
- if unmarshal(params, symbol_params, context.temp_allocator) != .None {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if unmarshal(params, symbol_params, context.temp_allocator) != .None {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- symbols := get_document_symbols(document);
+ symbols := get_document_symbols(document);
- response := make_response_message(
- params = symbols,
- id = id,
- );
+ response := make_response_message(
+ params = symbols,
+ id = id);
- send_response(response, writer);
+ send_response(response, writer);
}
-request_hover :: proc(task: ^common.Task) {
+request_hover :: proc (task: ^common.Task) {
- info := get_request_info(task);
+ info := get_request_info(task);
- using info;
+ using info;
- defer document_release(document);
- defer json.destroy_value(root);
- defer free(info);
+ defer document_release(document);
+ defer json.destroy_value(root);
+ defer free(info);
- params_object, ok := params.value.(json.Object);
+ params_object, ok := params.value.(json.Object);
- if !ok {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if !ok {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- hover_params: HoverParams;
+ hover_params: HoverParams;
- if unmarshal(params, hover_params, context.temp_allocator) != .None {
- handle_error(.ParseError, id, writer);
- return;
- }
+ if unmarshal(params, hover_params, context.temp_allocator) != .None {
+ handle_error(.ParseError, id, writer);
+ return;
+ }
- hover: Hover;
- hover, ok = get_hover_information(document, hover_params.position);
+ hover: Hover;
+ hover, ok = get_hover_information(document, hover_params.position);
- if !ok {
- handle_error(.InternalError, id, writer);
- return;
- }
+ if !ok {
+ handle_error(.InternalError, id, writer);
+ return;
+ }
- response := make_response_message(
- params = hover,
- id = id,
- );
+ response := make_response_message(
+ params = hover,
+ id = id);
- send_response(response, writer);
+ send_response(response, writer);
} \ No newline at end of file
diff --git a/src/server/response.odin b/src/server/response.odin
index bd7a77e..1ef7484 100644
--- a/src/server/response.odin
+++ b/src/server/response.odin
@@ -1,68 +1,67 @@
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);
+ data, error := json.marshal(notification, context.temp_allocator);
- header := fmt.tprintf("Content-Length: {}\r\n\r\n", len(data));
+ header := fmt.tprintf("Content-Length: {}\r\n\r\n", len(data));
- if error != json.Marshal_Error.None {
- return false;
- }
+ if error != json.Marshal_Error.None {
+ return false;
+ }
- if(!write_sized(writer, transmute([]u8)header)) {
- return false;
- }
+ if (!write_sized(writer, transmute([]u8)header)) {
+ return false;
+ }
- if(!write_sized(writer, data)) {
- return false;
- }
+ if (!write_sized(writer, data)) {
+ return false;
+ }
- return true;
+ 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);
+ data, error := json.marshal(response, context.temp_allocator);
- header := fmt.tprintf("Content-Length: {}\r\n\r\n", len(data));
+ header := fmt.tprintf("Content-Length: {}\r\n\r\n", len(data));
- if error != json.Marshal_Error.None {
- return false;
- }
+ if error != json.Marshal_Error.None {
+ return false;
+ }
- if(!write_sized(writer, transmute([]u8)header)) {
- return false;
- }
+ if (!write_sized(writer, transmute([]u8)header)) {
+ return false;
+ }
- if(!write_sized(writer, data)) {
- return false;
- }
+ if (!write_sized(writer, data)) {
+ return false;
+ }
- return true;
+ 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);
+ data, error := json.marshal(response, context.temp_allocator);
- header := fmt.tprintf("Content-Length: {}\r\n\r\n", len(data));
+ header := fmt.tprintf("Content-Length: {}\r\n\r\n", len(data));
- if error != json.Marshal_Error.None {
- return false;
- }
+ if error != json.Marshal_Error.None {
+ return false;
+ }
- if(!write_sized(writer, transmute([]u8)header)) {
- return false;
- }
+ if (!write_sized(writer, transmute([]u8)header)) {
+ return false;
+ }
- if(!write_sized(writer, data)) {
- return false;
- }
+ if (!write_sized(writer, data)) {
+ return false;
+ }
- return true;
-}
+ return true;
+} \ No newline at end of file
diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin
index 229ae7e..7f238d3 100644
--- a/src/server/semantic_tokens.odin
+++ b/src/server/semantic_tokens.odin
@@ -8,628 +8,572 @@ import "shared:common"
import "shared:index"
/*
- Right now I might be setting the wrong types, since there is no documentation as to what should be what, and looking at other LSP there is no consistancy.
+ Right now I might be setting the wrong types, since there is no documentation as to what should be what, and looking at other LSP there is no consistancy.
*/
SemanticTokenTypes :: enum {
- Namespace,
- Type,
- Enum,
- Struct,
- Parameter,
- Variable,
- EnumMember,
- Function,
- Member,
- Keyword,
- Modifier,
- Comment,
- String,
- Number,
- Operator,
- Property,
-};
+ Namespace,
+ Type,
+ Enum,
+ Struct,
+ Parameter,
+ Variable,
+ EnumMember,
+ Function,
+ Member,
+ Keyword,
+ Modifier,
+ Comment,
+ String,
+ Number,
+ Operator,
+ Property,
+}
SemanticTokenModifiers :: enum {
- None,
- Declaration,
- Definition,
- Deprecated,
-};
+ None,
+ Declaration,
+ Definition,
+ Deprecated,
+}
SemanticTokensClientCapabilities :: struct {
-
- requests: struct {
- range: bool,
- },
-
- tokenTypes: [] string,
- tokenModifiers: [] string,
- formats: [] string,
- overlappingTokenSupport: bool,
- multilineTokenSupport: bool,
-};
+ requests: struct {
+ range: bool,
+ },
+ tokenTypes: []string,
+ tokenModifiers: []string,
+ formats: []string,
+ overlappingTokenSupport: bool,
+ multilineTokenSupport: bool,
+}
SemanticTokensLegend :: struct {
- tokenTypes: [] string,
- tokenModifiers: [] string,
-};
+ tokenTypes: []string,
+ tokenModifiers: []string,
+}
SemanticTokensOptions :: struct {
- legend: SemanticTokensLegend,
- range: bool,
- full: bool,
-};
+ legend: SemanticTokensLegend,
+ range: bool,
+ full: bool,
+}
SemanticTokensParams :: struct {
- textDocument: TextDocumentIdentifier,
-};
+ textDocument: TextDocumentIdentifier,
+}
SemanticTokensRangeParams :: struct {
- textDocument: TextDocumentIdentifier,
- range: common.Range,
-};
+ textDocument: TextDocumentIdentifier,
+ range: common.Range,
+}
SemanticTokens :: struct {
- data: [] u32,
-};
+ data: []u32,
+}
SemanticTokenBuilder :: struct {
- current_function: ^ast.Node,
- current_start: int,
- selector_member: bool,
- selector_package: bool,
- tokens: [dynamic] u32,
-};
-
-make_token_builder :: proc(allocator := context.temp_allocator) -> SemanticTokenBuilder {
+ current_function: ^ast.Node,
+ current_start: int,
+ selector_member: bool,
+ selector_package: bool,
+ tokens: [dynamic]u32,
+}
- return {
- tokens = make([dynamic]u32, context.temp_allocator),
- };
+make_token_builder :: proc (allocator := context.temp_allocator) -> SemanticTokenBuilder {
+ return {
+ tokens = make([dynamic]u32, context.temp_allocator)
+ };
}
-get_tokens :: proc(builder: SemanticTokenBuilder) -> SemanticTokens {
- return {
- data = builder.tokens[:],
- };
+get_tokens :: proc (builder: SemanticTokenBuilder) -> SemanticTokens {
+ return {
+ data = builder.tokens[:]
+ };
}
-get_semantic_tokens :: proc(document: ^Document, range: common.Range) -> SemanticTokens {
+get_semantic_tokens :: proc (document: ^Document, range: common.Range) -> SemanticTokens {
- ast_context := make_ast_context(document.ast, document.imports, document.package_name, context.temp_allocator);
- builder := make_token_builder();
+ ast_context := make_ast_context(document.ast, document.imports, document.package_name, context.temp_allocator);
+ builder := make_token_builder();
- get_globals(document.ast, &ast_context);
+ get_globals(document.ast, &ast_context);
- for decl in document.ast.decls {
- if range.start.line <= decl.pos.line && decl.end.line <= range.end.line {
- write_semantic_tokens(decl, &builder, &ast_context);
- }
- }
+ for decl in document.ast.decls {
+ if range.start.line <= decl.pos.line && decl.end.line <= range.end.line {
+ write_semantic_tokens(decl, &builder, &ast_context);
+ }
+ }
- return get_tokens(builder);
+ return get_tokens(builder);
}
-write_semantic_node :: proc(builder: ^SemanticTokenBuilder, node: ^ast.Node, src: []byte, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) {
+write_semantic_node :: proc (builder: ^SemanticTokenBuilder, node: ^ast.Node, src: []byte, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) {
- position := common.get_relative_token_position(node.pos.offset, src, builder.current_start);
+ position := common.get_relative_token_position(node.pos.offset, src, builder.current_start);
- name := common.get_ast_node_string(node, src);
+ 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, 0);
+ append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, 0);
- builder.current_start = node.pos.offset;
+ builder.current_start = node.pos.offset;
}
-write_semantic_token :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: []byte, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) {
+write_semantic_token :: proc (builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: []byte, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) {
- position := common.get_relative_token_position(token.pos.offset, src, builder.current_start);
+ position := common.get_relative_token_position(token.pos.offset, src, builder.current_start);
- append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(token.text), cast(u32)type, 0);
+ append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(token.text), cast(u32)type, 0);
- builder.current_start = token.pos.offset;
+ builder.current_start = token.pos.offset;
}
+write_semantic_token_pos :: proc (builder: ^SemanticTokenBuilder, pos: tokenizer.Pos, name: string, src: []byte, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) {
-write_semantic_token_pos :: proc(builder: ^SemanticTokenBuilder, pos: tokenizer.Pos, name: string, src: []byte, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) {
-
- position := common.get_relative_token_position(pos.offset, src, builder.current_start);
+ position := common.get_relative_token_position(pos.offset, src, builder.current_start);
- append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, 0);
+ append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, 0);
- builder.current_start = pos.offset;
+ builder.current_start = pos.offset;
}
-
-resolve_and_write_ident :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) -> (is_member: bool, is_package: bool) {
-
- n := node.derived.(ast.Ident);
-
- ast_context.current_package = ast_context.document_package;
- ast_context.use_globals = true;
- ast_context.use_locals = true;
-
- if resolve_ident_is_variable(ast_context, n) {
- write_semantic_node(builder, node, ast_context.file.src, .Variable, .None);
- is_member = true;
- }
-
- else if symbol, ok := resolve_type_identifier(ast_context, n); ok {
-
- #partial switch v in symbol.value {
- case index.SymbolPackageValue:
- write_semantic_node(builder, node, ast_context.file.src, .Namespace, .None);
- is_package = true;
- case index.SymbolStructValue:
- write_semantic_node(builder, node, ast_context.file.src, .Struct, .None);
- case index.SymbolEnumValue:
- write_semantic_node(builder, node, ast_context.file.src, .Enum, .None);
- case index.SymbolUnionValue:
- write_semantic_node(builder, node, ast_context.file.src, .Enum, .None);
- case index.SymbolProcedureValue:
- write_semantic_node(builder, node, ast_context.file.src, .Function, .None);
- case index.SymbolProcedureGroupValue:
- write_semantic_node(builder, node, ast_context.file.src, .Function, .None);
- case index.SymbolGenericValue:
- #partial switch symbol.type {
- case .Keyword:
- write_semantic_node(builder, node, ast_context.file.src, .Keyword, .None);
- }
- }
-
- }
-
- return;
+resolve_and_write_ident :: proc (node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) -> (is_member: bool, is_package: bool) {
+
+ n := node.derived.(ast.Ident);
+
+ ast_context.current_package = ast_context.document_package;
+ ast_context.use_globals = true;
+ ast_context.use_locals = true;
+
+ if resolve_ident_is_variable(ast_context, n) {
+ write_semantic_node(builder, node, ast_context.file.src, .Variable, .None);
+ is_member = true;
+ } else if symbol, ok := resolve_type_identifier(ast_context, n); ok {
+
+ #partial switch v in symbol.value {
+ case index.SymbolPackageValue:
+ write_semantic_node(builder, node, ast_context.file.src, .Namespace, .None);
+ is_package = true;
+ case index.SymbolStructValue:
+ write_semantic_node(builder, node, ast_context.file.src, .Struct, .None);
+ case index.SymbolEnumValue:
+ write_semantic_node(builder, node, ast_context.file.src, .Enum, .None);
+ case index.SymbolUnionValue:
+ write_semantic_node(builder, node, ast_context.file.src, .Enum, .None);
+ case index.SymbolProcedureValue:
+ write_semantic_node(builder, node, ast_context.file.src, .Function, .None);
+ case index.SymbolProcedureGroupValue:
+ write_semantic_node(builder, node, ast_context.file.src, .Function, .None);
+ case index.SymbolGenericValue:
+ #partial switch symbol.type {
+ case .Keyword:
+ write_semantic_node(builder, node, ast_context.file.src, .Keyword, .None);
+ }
+ }
+ }
+
+ return;
}
-
write_semantic_tokens :: proc {
- write_semantic_tokens_node,
- write_semantic_tokens_dynamic_array,
- write_semantic_tokens_array,
- write_semantic_tokens_stmt,
-};
+write_semantic_tokens_node,
+write_semantic_tokens_dynamic_array,
+write_semantic_tokens_array,
+write_semantic_tokens_stmt};
-write_semantic_tokens_array :: proc(array: $A/[]^$T, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
-
- for elem, i in array {
- write_semantic_tokens(elem, builder, ast_context);
- }
+write_semantic_tokens_array :: proc (array: $A/[]^$T, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
+ for elem, i in array {
+ write_semantic_tokens(elem, builder, ast_context);
+ }
}
-write_semantic_tokens_dynamic_array :: proc(array: $A/[dynamic]^$T, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
-
- for elem, i in array {
- write_semantic_tokens(elem, builder, ast_context);
- }
+write_semantic_tokens_dynamic_array :: proc (array: $A/[dynamic]^$T, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
+ for elem, i in array {
+ write_semantic_tokens(elem, builder, ast_context);
+ }
}
-write_semantic_tokens_stmt :: proc(node: ^ast.Stmt, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
- ast_context.current_package = ast_context.document_package;
- ast_context.use_globals = true;
- ast_context.use_locals = true;
- builder.selector_member = false;
- builder.selector_package = false;
- write_semantic_tokens_node(node, builder, ast_context);
+write_semantic_tokens_stmt :: proc (node: ^ast.Stmt, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
+ ast_context.current_package = ast_context.document_package;
+ ast_context.use_globals = true;
+ ast_context.use_locals = true;
+ builder.selector_member = false;
+ builder.selector_package = false;
+ write_semantic_tokens_node(node, builder, ast_context);
}
-write_semantic_tokens_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
-
- using ast;
-
- if node == nil {
- return;
- }
-
- switch n in node.derived {
- case Ident:
- /*EXPENSIVE!! But alas i can't just get locals per scope, but have to the exact position, because you can do shit like this:
- log.println("hello"); //log is namespace
- log := 2; //log is now variable
- a := log + 2;
- */
-
- get_locals_at(builder.current_function, node, ast_context);
- resolve_and_write_ident(node, builder, ast_context);
- case Selector_Expr:
- write_semantic_selector(cast(^Selector_Expr)node, builder, ast_context);
- case Pointer_Type:
- write_semantic_token_pos(builder, node.pos, "^", ast_context.file.src, .Operator, .None);
- write_semantic_tokens(n.elem, builder, ast_context);
- case Value_Decl:
- write_semantic_tokens_value_decl(n, builder, ast_context);
- case Block_Stmt:
- write_semantic_tokens(n.stmts, builder, ast_context);
- case Expr_Stmt:
- write_semantic_tokens(n.expr, builder, ast_context);
- case Range_Stmt:
-
- write_semantic_token_pos(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None);
- if n.val0 != nil {
- if ident, ok := n.val0.derived.(Ident); ok {
- write_semantic_node(builder, n.val0, ast_context.file.src, .Variable, .None);
- }
- }
-
- if n.val1 != nil {
- if ident, ok := n.val1.derived.(Ident); ok {
- write_semantic_node(builder, n.val1, ast_context.file.src, .Variable, .None);
- }
- }
-
- write_semantic_token_pos(builder, n.in_pos, "in", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(n.expr, builder, ast_context);
- write_semantic_tokens(n.body, builder, ast_context);
- case If_Stmt:
- write_semantic_token_pos(builder, n.if_pos, "if", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(n.init, builder, ast_context);
- write_semantic_tokens(n.cond, builder, ast_context);
- write_semantic_tokens(n.body, builder, ast_context);
- if n.else_stmt != nil {
- write_semantic_token_pos(builder, n.else_pos, "else", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(n.else_stmt, builder, ast_context);
- }
- case For_Stmt:
- write_semantic_token_pos(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(n.init, builder, ast_context);
- write_semantic_tokens(n.cond, builder, ast_context);
- write_semantic_tokens(n.post, builder, ast_context);
- write_semantic_tokens(n.body, builder, ast_context);
- case Switch_Stmt:
- write_semantic_token_pos(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(n.init, builder, ast_context);
- write_semantic_tokens(n.cond, builder, ast_context);
- write_semantic_tokens(n.body, builder, ast_context);
- case Type_Switch_Stmt:
- write_semantic_token_pos(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(n.tag, builder, ast_context);
- write_semantic_tokens(n.expr, builder, ast_context);
- write_semantic_tokens(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);
- }
- else {
- write_semantic_tokens(l, builder, ast_context);
- }
- }
-
- write_semantic_token_op(builder, n.op, ast_context.file.src);
- write_semantic_tokens(n.rhs, builder, ast_context);
- case Case_Clause:
- write_semantic_token_pos(builder, n.case_pos, "case", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(n.list, builder, ast_context);
- write_semantic_tokens(n.body, builder, ast_context);
- case Call_Expr:
- //could there be any other type then .Function for call expr? No point of computing it if not.
- if ident, ok := n.expr.derived.(Ident); ok {
- write_semantic_node(builder, n.expr, ast_context.file.src, .Function, .None);
- }
- else {
- write_semantic_tokens(n.expr, builder, ast_context);
- }
- write_semantic_tokens(n.args, builder, ast_context);
- case Implicit_Selector_Expr:
- write_semantic_node(builder, n.field, ast_context.file.src, .Enum, .None);
- case Array_Type:
- write_semantic_tokens(n.elem, builder, ast_context);
- case Binary_Expr:
- write_semantic_tokens(n.left, builder, ast_context);
- write_semantic_token_op(builder, n.op, ast_context.file.src);
- write_semantic_tokens(n.right, builder, ast_context);
- case Comp_Lit:
- write_semantic_tokens(n.type, builder, ast_context);
- write_semantic_tokens(n.elems, builder, ast_context);
- case Struct_Type:
- write_semantic_token_pos(builder, n.pos, "struct", ast_context.file.src, .Keyword, .None);
- write_semantic_struct_fields(n, builder, ast_context);
- case Type_Assertion:
- write_semantic_tokens(n.expr, builder, ast_context);
- write_semantic_tokens(n.type, builder, ast_context);
- case Type_Cast:
- write_semantic_token_pos(builder, n.pos, "cast", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(n.type, builder, ast_context);
- write_semantic_tokens(n.expr, builder, ast_context);
- case Paren_Expr:
- write_semantic_tokens(n.expr, builder, ast_context);
- case Deref_Expr:
- write_semantic_tokens(n.expr, builder, ast_context);
- case Return_Stmt:
- write_semantic_token_pos(builder, n.pos, "return", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(n.results, builder, ast_context);
- case Dynamic_Array_Type:
- write_semantic_token_pos(builder, n.dynamic_pos, "dynamic", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(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_tokens(n.value, builder, ast_context);
- case Index_Expr:
- write_semantic_tokens(n.expr, builder, ast_context);
- write_semantic_tokens(n.index, builder, ast_context);
- case Basic_Lit:
- write_semantic_token_basic_lit(n, builder, ast_context);
- case Unary_Expr:
- write_semantic_tokens(n.expr, builder, ast_context);
- case Implicit:
- case Slice_Expr:
- write_semantic_tokens(n.expr, builder, ast_context);
- case Using_Stmt:
- write_semantic_token_pos(builder, n.pos, "using", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(n.list, builder, ast_context);
- case Map_Type:
- write_semantic_tokens(n.key, builder, ast_context);
- //write_semantic_token_pos(builder, n.tok_pos, "map", ast_context.file.src, .Keyword, .None);
- write_semantic_tokens(n.value, builder, ast_context);
- case:
- log.infof("unhandled write node %v", n);
- }
-
-
-
+write_semantic_tokens_node :: proc (node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
+
+ using ast;
+
+ if node == nil {
+ return;
+ }
+
+ switch n in node.derived {
+ case Ident:
+ /*EXPENSIVE!! But alas i can't just get locals per scope, but have to the exact position, because you can do shit like this:
+ log.println("hello"); //log is namespace
+ log := 2; //log is now variable
+ a := log + 2;
+ */
+
+ get_locals_at(builder.current_function, node, ast_context);
+ resolve_and_write_ident(node, builder, ast_context);
+ case Selector_Expr:
+ write_semantic_selector(cast(^Selector_Expr)node, builder, ast_context);
+ case Pointer_Type:
+ write_semantic_token_pos(builder, node.pos, "^", ast_context.file.src, .Operator, .None);
+ write_semantic_tokens(n.elem, builder, ast_context);
+ case Value_Decl:
+ write_semantic_tokens_value_decl(n, builder, ast_context);
+ case Block_Stmt:
+ write_semantic_tokens(n.stmts, builder, ast_context);
+ case Expr_Stmt:
+ write_semantic_tokens(n.expr, builder, ast_context);
+ case Range_Stmt:
+
+ write_semantic_token_pos(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None);
+ if n.val0 != nil {
+ if ident, ok := n.val0.derived.(Ident); ok {
+ write_semantic_node(builder, n.val0, ast_context.file.src, .Variable, .None);
+ }
+ }
+
+ if n.val1 != nil {
+ if ident, ok := n.val1.derived.(Ident); ok {
+ write_semantic_node(builder, n.val1, ast_context.file.src, .Variable, .None);
+ }
+ }
+
+ write_semantic_token_pos(builder, n.in_pos, "in", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.expr, builder, ast_context);
+ write_semantic_tokens(n.body, builder, ast_context);
+ case If_Stmt:
+ write_semantic_token_pos(builder, n.if_pos, "if", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.init, builder, ast_context);
+ write_semantic_tokens(n.cond, builder, ast_context);
+ write_semantic_tokens(n.body, builder, ast_context);
+ if n.else_stmt != nil {
+ write_semantic_token_pos(builder, n.else_pos, "else", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.else_stmt, builder, ast_context);
+ }
+ case For_Stmt:
+ write_semantic_token_pos(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.init, builder, ast_context);
+ write_semantic_tokens(n.cond, builder, ast_context);
+ write_semantic_tokens(n.post, builder, ast_context);
+ write_semantic_tokens(n.body, builder, ast_context);
+ case Switch_Stmt:
+ write_semantic_token_pos(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.init, builder, ast_context);
+ write_semantic_tokens(n.cond, builder, ast_context);
+ write_semantic_tokens(n.body, builder, ast_context);
+ case Type_Switch_Stmt:
+ write_semantic_token_pos(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.tag, builder, ast_context);
+ write_semantic_tokens(n.expr, builder, ast_context);
+ write_semantic_tokens(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);
+ } else {
+ write_semantic_tokens(l, builder, ast_context);
+ }
+ }
+
+ write_semantic_token_op(builder, n.op, ast_context.file.src);
+ write_semantic_tokens(n.rhs, builder, ast_context);
+ case Case_Clause:
+ write_semantic_token_pos(builder, n.case_pos, "case", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.list, builder, ast_context);
+ write_semantic_tokens(n.body, builder, ast_context);
+ case Call_Expr:
+ //could there be any other type then .Function for call expr? No point of computing it if not.
+ if ident, ok := n.expr.derived.(Ident); ok {
+ write_semantic_node(builder, n.expr, ast_context.file.src, .Function, .None);
+ } else {
+ write_semantic_tokens(n.expr, builder, ast_context);
+ }
+ write_semantic_tokens(n.args, builder, ast_context);
+ case Implicit_Selector_Expr:
+ write_semantic_node(builder, n.field, ast_context.file.src, .Enum, .None);
+ case Array_Type:
+ write_semantic_tokens(n.elem, builder, ast_context);
+ case Binary_Expr:
+ write_semantic_tokens(n.left, builder, ast_context);
+ write_semantic_token_op(builder, n.op, ast_context.file.src);
+ write_semantic_tokens(n.right, builder, ast_context);
+ case Comp_Lit:
+ write_semantic_tokens(n.type, builder, ast_context);
+ write_semantic_tokens(n.elems, builder, ast_context);
+ case Struct_Type:
+ write_semantic_token_pos(builder, n.pos, "struct", ast_context.file.src, .Keyword, .None);
+ write_semantic_struct_fields(n, builder, ast_context);
+ case Type_Assertion:
+ write_semantic_tokens(n.expr, builder, ast_context);
+ write_semantic_tokens(n.type, builder, ast_context);
+ case Type_Cast:
+ write_semantic_token_pos(builder, n.pos, "cast", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.type, builder, ast_context);
+ write_semantic_tokens(n.expr, builder, ast_context);
+ case Paren_Expr:
+ write_semantic_tokens(n.expr, builder, ast_context);
+ case Deref_Expr:
+ write_semantic_tokens(n.expr, builder, ast_context);
+ case Return_Stmt:
+ write_semantic_token_pos(builder, n.pos, "return", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.results, builder, ast_context);
+ case Dynamic_Array_Type:
+ write_semantic_token_pos(builder, n.dynamic_pos, "dynamic", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(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_tokens(n.value, builder, ast_context);
+ case Index_Expr:
+ write_semantic_tokens(n.expr, builder, ast_context);
+ write_semantic_tokens(n.index, builder, ast_context);
+ case Basic_Lit:
+ write_semantic_token_basic_lit(n, builder, ast_context);
+ case Unary_Expr:
+ write_semantic_tokens(n.expr, builder, ast_context);
+ case Implicit:
+ case Slice_Expr:
+ write_semantic_tokens(n.expr, builder, ast_context);
+ case Using_Stmt:
+ write_semantic_token_pos(builder, n.pos, "using", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.list, builder, ast_context);
+ case Map_Type:
+ write_semantic_tokens(n.key, builder, ast_context);
+ //write_semantic_token_pos(builder, n.tok_pos, "map", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.value, builder, ast_context);
+ case:
+ log.infof("unhandled write node %v", n);
+ }
}
-write_semantic_token_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 generic, ok := symbol.value.(index.SymbolGenericValue); ok {
+write_semantic_token_basic_lit :: proc (basic_lit: ast.Basic_Lit, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
- ident := generic.expr.derived.(ast.Ident);
+ if symbol, ok := resolve_basic_lit(ast_context, basic_lit); ok {
- if ident.name == string_lit {
- write_semantic_node(builder, generic.expr, ast_context.file.src, .String, .None);
- }
+ if generic, ok := symbol.value.(index.SymbolGenericValue); ok {
- else if ident.name == int_lit {
- write_semantic_node(builder, generic.expr, ast_context.file.src, .Number, .None);
- }
+ ident := generic.expr.derived.(ast.Ident);
- else {
-
- }
-
- }
-
- }
+ if ident.name == string_lit {
+ write_semantic_node(builder, generic.expr, ast_context.file.src, .String, .None);
+ } else if ident.name == int_lit {
+ write_semantic_node(builder, generic.expr, ast_context.file.src, .Number, .None);
+ } else {
+ }
+ }
+ }
}
-write_semantic_tokens_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_tokens(value_decl.type, builder, ast_context);
-
- return;
- }
-
- if len(value_decl.values) == 1 {
-
- switch v in value_decl.values[0].derived {
- case Struct_Type:
- write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Struct, .None);
- write_semantic_token_pos(builder, v.pos, "struct", ast_context.file.src, .Keyword, .None);
- write_semantic_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_token_pos(builder, v.pos, "enum", ast_context.file.src, .Keyword, .None);
- write_semantic_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_token_pos(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);
- }
- }
- case Proc_Lit:
- write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Function, .None);
- write_semantic_token_pos(builder, v.pos, "proc", ast_context.file.src, .Keyword, .None);
- write_semantic_proc_type(v.type, builder, ast_context);
-
- last_function := builder.current_function;
- builder.current_function = value_decl.values[0];
- write_semantic_tokens(v.body, builder, ast_context);
- builder.current_function = last_function;
- case:
- write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Variable, .None);
- write_semantic_tokens(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);
- }
-
- for value in value_decl.values {
- write_semantic_tokens(value, builder, ast_context);
- }
-
-
- }
-
-
-
-
+write_semantic_tokens_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_tokens(value_decl.type, builder, ast_context);
+
+ return;
+ }
+
+ if len(value_decl.values) == 1 {
+
+ switch v in value_decl.values[0].derived {
+ case Struct_Type:
+ write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Struct, .None);
+ write_semantic_token_pos(builder, v.pos, "struct", ast_context.file.src, .Keyword, .None);
+ write_semantic_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_token_pos(builder, v.pos, "enum", ast_context.file.src, .Keyword, .None);
+ write_semantic_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_token_pos(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);
+ }
+ }
+ case Proc_Lit:
+ write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Function, .None);
+ write_semantic_token_pos(builder, v.pos, "proc", ast_context.file.src, .Keyword, .None);
+ write_semantic_proc_type(v.type, builder, ast_context);
+
+ last_function := builder.current_function;
+ builder.current_function = value_decl.values[0];
+ write_semantic_tokens(v.body, builder, ast_context);
+ builder.current_function = last_function;
+ case:
+ write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Variable, .None);
+ write_semantic_tokens(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);
+ }
+
+ for value in value_decl.values {
+ write_semantic_tokens(value, builder, ast_context);
+ }
+ }
}
+write_semantic_token_op :: proc (builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: []byte) {
-write_semantic_token_op :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: []byte) {
-
- if token.text == "=" {
- write_semantic_token_pos(builder, token.pos, token.text, src, .Operator, .None);
- }
-
- else if token.text == "in" {
- write_semantic_token_pos(builder, token.pos, token.text, src, .Keyword, .None);
- }
-
+ if token.text == "=" {
+ write_semantic_token_pos(builder, token.pos, token.text, src, .Operator, .None);
+ } else if token.text == "in" {
+ write_semantic_token_pos(builder, token.pos, token.text, src, .Keyword, .None);
+ }
}
-write_semantic_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
-
- using ast;
-
- if node == nil {
- return;
- }
-
- if node.params != nil {
-
- for param in node.params.list {
-
- for name in param.names {
+write_semantic_proc_type :: proc (node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
- if ident, ok := name.derived.(Ident); ok {
- write_semantic_node(builder, name, ast_context.file.src, .Parameter, .None);
- }
+ using ast;
- }
+ if node == nil {
+ return;
+ }
- write_semantic_tokens(param.type, builder, ast_context);
- }
+ if node.params != nil {
- }
+ for param in node.params.list {
- if node.results != nil {
+ for name in param.names {
- for result in node.results.list {
+ if ident, ok := name.derived.(Ident); ok {
+ write_semantic_node(builder, name, ast_context.file.src, .Parameter, .None);
+ }
+ }
+ write_semantic_tokens(param.type, builder, ast_context);
+ }
+ }
- for name in result.names {
+ if node.results != nil {
- if ident, ok := name.derived.(Ident); ok {
- //write_semantic_node(builder, name, ast_context.file.src, .Parameter, .None);
- }
+ for result in node.results.list {
- }
+ for name in result.names {
- write_semantic_tokens(result.type, builder, ast_context);
-
- }
-
- }
+ if ident, ok := name.derived.(Ident); ok {
+ //write_semantic_node(builder, name, ast_context.file.src, .Parameter, .None);
+ }
+ }
+ write_semantic_tokens(result.type, builder, ast_context);
+ }
+ }
}
-write_semantic_enum_fields :: proc(node: ast.Enum_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
-
- using ast;
+write_semantic_enum_fields :: proc (node: ast.Enum_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
- if node.fields == nil {
- return;
- }
+ using ast;
- for field in node.fields {
+ if node.fields == nil {
+ return;
+ }
- if ident, ok := field.derived.(Ident); ok {
- write_semantic_node(builder, field, ast_context.file.src, .EnumMember, .None);
- }
-
- }
+ for field in node.fields {
+ if ident, ok := field.derived.(Ident); ok {
+ write_semantic_node(builder, field, ast_context.file.src, .EnumMember, .None);
+ }
+ }
}
-write_semantic_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
-
- using ast;
+write_semantic_struct_fields :: proc (node: ast.Struct_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
- if node.fields == nil {
- return;
- }
+ using ast;
- for field in node.fields.list {
+ if node.fields == nil {
+ return;
+ }
- for name in field.names {
- if ident, ok := name.derived.(Ident); ok {
- write_semantic_node(builder, name, ast_context.file.src, .Property, .None);
- }
- }
+ 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_tokens(field.type, builder, ast_context);
-
- }
-
+ write_semantic_tokens(field.type, builder, ast_context);
+ }
}
-write_semantic_selector :: proc(selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
-
- using ast;
-
-
- if ident, ok := selector.expr.derived.(Ident); ok {
- get_locals_at(builder.current_function, selector.expr, ast_context);
- builder.selector_member, builder.selector_package = resolve_and_write_ident(selector.expr, builder, ast_context); //base
-
- if builder.selector_package && selector.field != nil && resolve_ident_is_variable(ast_context, selector.field^) {
- builder.selector_member = true;
- }
- }
-
- else {
- write_semantic_tokens(selector.expr, builder, ast_context);
- }
-
- if symbol, ok := resolve_type_expression(ast_context, selector); ok && !builder.selector_member {
-
- #partial switch v in symbol.value {
- case index.SymbolPackageValue:
- write_semantic_node(builder, selector.field, ast_context.file.src, .Namespace, .None);
- case index.SymbolStructValue:
- write_semantic_node(builder, selector.field, ast_context.file.src, .Struct, .None);
- case index.SymbolEnumValue:
- write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None);
- case index.SymbolUnionValue:
- write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None);
- case index.SymbolProcedureGroupValue:
- write_semantic_node(builder, selector.field, ast_context.file.src, .Function, .None);
- case index.SymbolGenericValue:
- #partial switch symbol.type {
- case .Keyword:
- write_semantic_node(builder, selector.field, ast_context.file.src, .Keyword, .None);
- }
- }
-
- }
-
- else if (builder.selector_member) {
- write_semantic_node(builder, selector.field, ast_context.file.src, .Property, .None);
- }
-
+write_semantic_selector :: proc (selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) {
+
+ using ast;
+
+ if ident, ok := selector.expr.derived.(Ident); ok {
+ get_locals_at(builder.current_function, selector.expr, ast_context);
+ builder.selector_member, builder.selector_package = resolve_and_write_ident(selector.expr, builder, ast_context); //base
+
+ if builder.selector_package && selector.field != nil && resolve_ident_is_variable(ast_context, selector.field^) {
+ builder.selector_member = true;
+ }
+ } else {
+ write_semantic_tokens(selector.expr, builder, ast_context);
+ }
+
+ if symbol, ok := resolve_type_expression(ast_context, selector); ok && !builder.selector_member {
+
+ #partial switch v in symbol.value {
+ case index.SymbolPackageValue:
+ write_semantic_node(builder, selector.field, ast_context.file.src, .Namespace, .None);
+ case index.SymbolStructValue:
+ write_semantic_node(builder, selector.field, ast_context.file.src, .Struct, .None);
+ case index.SymbolEnumValue:
+ write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None);
+ case index.SymbolUnionValue:
+ write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None);
+ case index.SymbolProcedureGroupValue:
+ write_semantic_node(builder, selector.field, ast_context.file.src, .Function, .None);
+ case index.SymbolGenericValue:
+ #partial switch symbol.type {
+ case .Keyword:
+ write_semantic_node(builder, selector.field, ast_context.file.src, .Keyword, .None);
+ }
+ }
+ } else if (builder.selector_member) {
+ write_semantic_node(builder, selector.field, ast_context.file.src, .Property, .None);
+ }
}
-get_locals_at :: proc(function: ^ast.Node, position: ^ast.Node, ast_context: ^AstContext) {
+get_locals_at :: proc (function: ^ast.Node, position: ^ast.Node, ast_context: ^AstContext) {
- clear_locals(ast_context);
+ clear_locals(ast_context);
- if function == nil {
- return;
- }
+ if function == nil {
+ return;
+ }
- if position == nil {
- return;
- }
+ if position == nil {
+ return;
+ }
- document_position := DocumentPositionContext {
- position = position.end.offset,
- };
+ document_position := DocumentPositionContext {
+ position = position.end.offset
+ };
- get_locals(ast_context.file, function, ast_context, &document_position);
+ get_locals(ast_context.file, function, ast_context, &document_position);
} \ No newline at end of file
diff --git a/src/server/types.odin b/src/server/types.odin
index 9b8ecd3..2ee477b 100644
--- a/src/server/types.odin
+++ b/src/server/types.odin
@@ -5,347 +5,345 @@ import "core:encoding/json"
import "shared:common"
/*
- General types
+ General types
*/
//TODO(Daniel, move some of the more specific structs to their appropriate place)
RequestId :: union {
- string,
- i64,
-};
+ string,
+ i64,
+}
ResponseParams :: union {
- ResponseInitializeParams,
- rawptr,
- common.Location,
- CompletionList,
- SignatureHelp,
- [] DocumentSymbol,
- SemanticTokens,
- Hover,
- [] TextEdit,
-};
+ ResponseInitializeParams,
+ rawptr,
+ common.Location,
+ CompletionList,
+ SignatureHelp,
+ []DocumentSymbol,
+ SemanticTokens,
+ Hover,
+ []TextEdit,
+}
ResponseMessage :: struct {
- jsonrpc: string,
- id: RequestId,
- result: ResponseParams,
-};
+ jsonrpc: string,
+ id: RequestId,
+ result: ResponseParams,
+}
ResponseMessageError :: struct {
- jsonrpc: string,
- id: RequestId,
- error: ResponseError,
-};
+ jsonrpc: string,
+ id: RequestId,
+ error: ResponseError,
+}
ResponseError :: struct {
- code: common.Error,
- message: string,
-};
+ code: common.Error,
+ message: string,
+}
NotificationLoggingParams :: struct {
- type: int,
- message: string,
-};
+ type: int,
+ message: string,
+}
NotificationPublishDiagnosticsParams :: struct {
- uri: string,
- diagnostics: [] Diagnostic,
-};
+ uri: string,
+ diagnostics: []Diagnostic,
+}
NotificationParams :: union {
- NotificationLoggingParams,
- NotificationPublishDiagnosticsParams,
-};
+ NotificationLoggingParams,
+ NotificationPublishDiagnosticsParams,
+}
Notification :: struct {
- jsonrpc: string,
- method: string,
- params: NotificationParams
-};
+ jsonrpc: string,
+ method: string,
+ params: NotificationParams,
+}
ResponseInitializeParams :: struct {
- capabilities: ServerCapabilities,
-};
+ capabilities: ServerCapabilities,
+}
RequestInitializeParams :: struct {
- trace: string,
- workspaceFolders: [dynamic] common.WorkspaceFolder,
- capabilities: ClientCapabilities,
-};
+ trace: string,
+ workspaceFolders: [dynamic]common.WorkspaceFolder,
+ capabilities: ClientCapabilities,
+}
MarkupContent :: struct {
- kind: string,
+ kind: string,
value: string,
-};
+}
ServerCapabilities :: struct {
- textDocumentSync: TextDocumentSyncOptions,
- definitionProvider: bool,
- completionProvider: CompletionOptions,
- signatureHelpProvider: SignatureHelpOptions,
- semanticTokensProvider: SemanticTokensOptions,
- documentSymbolProvider: bool,
- hoverProvider: bool,
- documentFormattingProvider: bool,
-};
-
-CompletionOptions :: struct {
- resolveProvider: bool,
- triggerCharacters: [] string,
-};
+ textDocumentSync: TextDocumentSyncOptions,
+ definitionProvider: bool,
+ completionProvider: CompletionOptions,
+ signatureHelpProvider: SignatureHelpOptions,
+ semanticTokensProvider: SemanticTokensOptions,
+ documentSymbolProvider: bool,
+ hoverProvider: bool,
+ documentFormattingProvider: bool,
+}
+
+CompletionOptions :: struct {
+ resolveProvider: bool,
+ triggerCharacters: []string,
+}
SaveOptions :: struct {
includeText: bool,
}
HoverClientCapabilities :: struct {
- dynamicRegistration: bool,
- contentFormat: [dynamic] string,
-};
+ dynamicRegistration: bool,
+ contentFormat: [dynamic]string,
+}
DocumentSymbolClientCapabilities :: struct {
-
- symbolKind: struct {
- valueSet: [dynamic] SymbolKind,
- },
-
- hierarchicalDocumentSymbolSupport: bool,
-};
+ symbolKind: struct {
+ valueSet: [dynamic]SymbolKind,
+ },
+ hierarchicalDocumentSymbolSupport: bool,
+}
TextDocumentClientCapabilities :: struct {
- completion: CompletionClientCapabilities,
- hover: HoverClientCapabilities,
- signatureHelp: SignatureHelpClientCapabilities,
- documentSymbol: DocumentSymbolClientCapabilities,
-};
+ completion: CompletionClientCapabilities,
+ hover: HoverClientCapabilities,
+ signatureHelp: SignatureHelpClientCapabilities,
+ documentSymbol: DocumentSymbolClientCapabilities,
+}
CompletionClientCapabilities :: struct {
- documentationFormat: [dynamic] string,
-};
+ documentationFormat: [dynamic]string,
+}
ParameterInformationCapabilities :: struct {
- labelOffsetSupport: bool,
-};
+ labelOffsetSupport: bool,
+}
SignatureInformationCapabilities :: struct {
- parameterInformation: ParameterInformationCapabilities,
-};
+ parameterInformation: ParameterInformationCapabilities,
+}
SignatureHelpClientCapabilities :: struct {
- dynamicRegistration: bool,
- signatureInformation: SignatureInformationCapabilities,
- contextSupport: bool,
-};
+ dynamicRegistration: bool,
+ signatureInformation: SignatureInformationCapabilities,
+ contextSupport: bool,
+}
SignatureHelpOptions :: struct {
- triggerCharacters: [] string,
- retriggerCharacters: [] string,
-};
+ triggerCharacters: []string,
+ retriggerCharacters: []string,
+}
ClientCapabilities :: struct {
- textDocument: TextDocumentClientCapabilities,
-};
+ textDocument: TextDocumentClientCapabilities,
+}
RangeOptional :: union {
- common.Range,
-};
+ common.Range
+}
TextDocumentContentChangeEvent :: struct {
- range: RangeOptional,
- text: string,
-};
+ range: RangeOptional,
+ text: string,
+}
Version :: union {
- int,
- json.Null,
-};
+ int,
+ json.Null,
+}
-VersionedTextDocumentIdentifier :: struct {
- uri: string,
-};
+VersionedTextDocumentIdentifier :: struct {
+ uri: string,
+}
TextDocumentIdentifier :: struct {
- uri: string,
-};
+ uri: string,
+}
TextDocumentItem :: struct {
- uri: string,
- text: string,
-};
+ uri: string,
+ text: string,
+}
DiagnosticSeverity :: enum {
- Error = 1,
- Warning = 2,
- Information = 3,
- Hint = 4,
-};
+ Error = 1,
+ Warning = 2,
+ Information = 3,
+ Hint = 4,
+}
Diagnostic :: struct {
- range: common.Range,
- severity: DiagnosticSeverity,
- code: string,
- message: string,
-};
+ range: common.Range,
+ severity: DiagnosticSeverity,
+ code: string,
+ message: string,
+}
DidOpenTextDocumentParams :: struct {
- textDocument: TextDocumentItem,
-};
+ textDocument: TextDocumentItem,
+}
-DocumentSymbolParams :: struct {
- textDocument: TextDocumentIdentifier,
-};
+DocumentSymbolParams :: struct {
+ textDocument: TextDocumentIdentifier,
+}
DidChangeTextDocumentParams :: struct {
- textDocument: VersionedTextDocumentIdentifier,
- contentChanges: [dynamic] TextDocumentContentChangeEvent,
-};
+ textDocument: VersionedTextDocumentIdentifier,
+ contentChanges: [dynamic]TextDocumentContentChangeEvent,
+}
DidCloseTextDocumentParams :: struct {
- textDocument: TextDocumentIdentifier,
-};
+ textDocument: TextDocumentIdentifier,
+}
DidSaveTextDocumentParams :: struct {
- textDocument: TextDocumentIdentifier,
- text: string,
-};
+ textDocument: TextDocumentIdentifier,
+ text: string,
+}
TextDocumentPositionParams :: struct {
- textDocument: TextDocumentIdentifier,
- position: common.Position,
-};
+ textDocument: TextDocumentIdentifier,
+ position: common.Position,
+}
SignatureHelpParams :: struct {
- textDocument: TextDocumentIdentifier,
- position: common.Position,
-};
+ textDocument: TextDocumentIdentifier,
+ position: common.Position,
+}
CompletionParams :: struct {
- textDocument: TextDocumentIdentifier,
- position: common.Position,
-};
+ textDocument: TextDocumentIdentifier,
+ position: common.Position,
+}
CompletionItemKind :: enum {
- Text = 1,
- Method = 2,
- Function = 3,
- Constructor = 4,
- Field = 5,
- Variable = 6,
- Class = 7,
- Interface = 8,
- Module = 9,
- Property = 10,
- Unit = 11,
- Value = 12,
- Enum = 13,
- Keyword = 14,
- Snippet = 15,
- Color = 16,
- File = 17,
- Reference = 18,
- Folder = 19,
- EnumMember = 20,
- Constant = 21,
- Struct = 22,
- Event = 23,
- Operator = 24,
- TypeParameter = 25,
-};
+ Text = 1,
+ Method = 2,
+ Function = 3,
+ Constructor = 4,
+ Field = 5,
+ Variable = 6,
+ Class = 7,
+ Interface = 8,
+ Module = 9,
+ Property = 10,
+ Unit = 11,
+ Value = 12,
+ Enum = 13,
+ Keyword = 14,
+ Snippet = 15,
+ Color = 16,
+ File = 17,
+ Reference = 18,
+ Folder = 19,
+ EnumMember = 20,
+ Constant = 21,
+ Struct = 22,
+ Event = 23,
+ Operator = 24,
+ TypeParameter = 25,
+}
CompletionItem :: struct {
- label: string,
- kind: CompletionItemKind,
- detail: string,
- documentation: string,
-};
+ label: string,
+ kind: CompletionItemKind,
+ detail: string,
+ documentation: string,
+}
CompletionList :: struct {
- isIncomplete: bool,
- items: [] CompletionItem,
-};
+ isIncomplete: bool,
+ items: []CompletionItem,
+}
TextDocumentSyncOptions :: struct {
- openClose: bool,
- change: int,
- save: SaveOptions,
-};
+ openClose: bool,
+ change: int,
+ save: SaveOptions,
+}
SignatureHelp :: struct {
- signatures: [] SignatureInformation,
- activeSignature: int,
- activeParameter: int,
-};
+ signatures: []SignatureInformation,
+ activeSignature: int,
+ activeParameter: int,
+}
SignatureInformation :: struct {
- label: string,
- documentation: string,
- parameters: [] ParameterInformation,
-};
+ label: string,
+ documentation: string,
+ parameters: []ParameterInformation,
+}
ParameterInformation :: struct {
- label: [2] int,
-};
+ label: [2]int,
+}
OlsConfig :: struct {
- collections: [dynamic] OlsConfigCollection,
- thread_pool_count: int,
- enable_semantic_tokens: bool,
- enable_document_symbols: bool,
- enable_hover: bool,
- enable_format: bool,
- verbose: bool,
-};
+ collections: [dynamic]OlsConfigCollection,
+ thread_pool_count: int,
+ enable_semantic_tokens: bool,
+ enable_document_symbols: bool,
+ enable_hover: bool,
+ enable_format: bool,
+ verbose: bool,
+}
OlsConfigCollection :: struct {
- name: string,
- path: string,
-};
+ name: string,
+ path: string,
+}
SymbolKind :: enum {
- File = 1,
- Module = 2,
- Namespace = 3,
- Package = 4,
- Class = 5,
- Method = 6,
- Property = 7,
- Field = 8,
- Constructor = 9,
- Enum = 10,
- Interface = 11,
- Function = 12,
- Variable = 13,
- Constant = 14,
- String = 15,
- Number = 16,
- Boolean = 17,
- Array = 18,
- Object = 19,
- Key = 20,
- Null = 21,
- EnumMember = 22,
- Struct = 23,
- Event = 24,
- Operator = 25,
- TypeParameter = 26,
-};
+ File = 1,
+ Module = 2,
+ Namespace = 3,
+ Package = 4,
+ Class = 5,
+ Method = 6,
+ Property = 7,
+ Field = 8,
+ Constructor = 9,
+ Enum = 10,
+ Interface = 11,
+ Function = 12,
+ Variable = 13,
+ Constant = 14,
+ String = 15,
+ Number = 16,
+ Boolean = 17,
+ Array = 18,
+ Object = 19,
+ Key = 20,
+ Null = 21,
+ EnumMember = 22,
+ Struct = 23,
+ Event = 24,
+ Operator = 25,
+ TypeParameter = 26,
+}
DocumentSymbol :: struct {
- name: string,
- kind: SymbolKind,
- range: common.Range,
- selectionRange: common.Range,
- children: [] DocumentSymbol,
-};
+ name: string,
+ kind: SymbolKind,
+ range: common.Range,
+ selectionRange: common.Range,
+ children: []DocumentSymbol,
+}
HoverParams :: struct {
- textDocument: TextDocumentIdentifier,
- position: common.Position,
-};
+ textDocument: TextDocumentIdentifier,
+ position: common.Position,
+}
Hover :: struct {
- contents: MarkupContent,
- range: common.Range,
-}; \ No newline at end of file
+ contents: MarkupContent,
+ range: common.Range,
+} \ No newline at end of file
diff --git a/src/server/unmarshal.odin b/src/server/unmarshal.odin
index 908f83c..77459bf 100644
--- a/src/server/unmarshal.odin
+++ b/src/server/unmarshal.odin
@@ -9,146 +9,141 @@ import "core:fmt"
//Note(Daniel, investigate if you can use some sort of attribute not to be forced to have the same variable name as the json name)
/*
- 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 {
-
- using runtime;
-
- if v == nil {
- return .None;
- }
-
- if json_value.value == nil {
- return .None;
- }
-
- type_info := type_info_base(type_info_of(v.id));
-
- #partial
- switch j in json_value.value {
- case json.Object:
- #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};
- if ret := unmarshal(j[field], a, allocator); ret != .None {
- return ret;
- }
- }
-
- case Type_Info_Union:
-
- //Note(Daniel, THIS IS REALLY SCUFFED. Need to talk to gingerbill about unmarshalling unions)
-
- //This only works for unions with one object - made to handle optionals
- 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, &not_optional, size_of(variant.tag_type));
-
- id := variant.variants[0].id;
-
- 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.allocator = allocator;
- }
- else {
- return .Invalid_Data;
- }
-
- 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 != .None {
- return ret;
- }
- }
-
- case:
- return .Unsupported_Type;
- }
- case json.String:
- #partial switch variant in type_info.variant {
- case Type_Info_String:
- str := (^string)(v.data);
- str^ = strings.clone(j, allocator);
-
- case Type_Info_Enum:
- for name, i in variant.names {
-
- lower_name := strings.to_lower(name, 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));
- }
-
- delete(lower_name, allocator);
- delete(lower_j, allocator);
- }
- }
- case json.Integer:
- #partial switch variant in &type_info.variant {
- case Type_Info_Integer:
- switch type_info.size {
- case 8:
- tmp := i64(j);
- mem.copy(v.data, &tmp, type_info.size);
-
- case 4:
- tmp := i32(j);
- mem.copy(v.data, &tmp, type_info.size);
-
- case 2:
- tmp := i16(j);
- mem.copy(v.data, &tmp, type_info.size);
-
- case 1:
- tmp := i8(j);
- mem.copy(v.data, &tmp, type_info.size);
- case:
- return .Invalid_Data;
- }
- case Type_Info_Union:
- tag_ptr := uintptr(v.data) + variant.tag_offset;
- }
- case json.Float:
- if _, ok := type_info.variant.(Type_Info_Float); ok {
- switch type_info.size {
- case 8:
- tmp := f64(j);
- mem.copy(v.data, &tmp, type_info.size);
- case 4:
- tmp := f32(j);
- mem.copy(v.data, &tmp, type_info.size);
- case:
- return .Invalid_Data;
- }
-
- }
- case json.Null:
- case json.Boolean :
- if _, ok := type_info.variant.(Type_Info_Boolean); ok {
- tmp := bool(j);
- mem.copy(v.data, &tmp, type_info.size);
- }
- case:
- return .Unsupported_Type;
- }
-
- return .None;
-}
-
+ 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 {
+
+ using runtime;
+
+ if v == nil {
+ return .None;
+ }
+
+ if json_value.value == nil {
+ return .None;
+ }
+
+ type_info := type_info_base(type_info_of(v.id));
+
+ #partial switch j in json_value.value {
+ case json.Object:
+ #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};
+ if ret := unmarshal(j[field], a, allocator); ret != .None {
+ return ret;
+ }
+ }
+
+ case Type_Info_Union:
+
+ //Note(Daniel, THIS IS REALLY SCUFFED. Need to talk to gingerbill about unmarshalling unions)
+
+ //This only works for unions with one object - made to handle optionals
+ 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, &not_optional, size_of(variant.tag_type));
+
+ id := variant.variants[0].id;
+
+ 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.allocator = allocator;
+ } else {
+ return .Invalid_Data;
+ }
+
+ 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 != .None {
+ return ret;
+ }
+ }
+
+ case:
+ return .Unsupported_Type;
+ }
+ case json.String:
+ #partial switch variant in type_info.variant {
+ case Type_Info_String:
+ str := (^string)(v.data);
+ str^ = strings.clone(j, allocator);
+
+ case Type_Info_Enum:
+ for name, i in variant.names {
+
+ lower_name := strings.to_lower(name, 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));
+ }
+
+ delete(lower_name, allocator);
+ delete(lower_j, allocator);
+ }
+ }
+ case json.Integer:
+ #partial switch variant in &type_info.variant {
+ case Type_Info_Integer:
+ switch type_info.size {
+ case 8:
+ tmp := i64(j);
+ mem.copy(v.data, &tmp, type_info.size);
+
+ case 4:
+ tmp := i32(j);
+ mem.copy(v.data, &tmp, type_info.size);
+
+ case 2:
+ tmp := i16(j);
+ mem.copy(v.data, &tmp, type_info.size);
+
+ case 1:
+ tmp := i8(j);
+ mem.copy(v.data, &tmp, type_info.size);
+ case:
+ return .Invalid_Data;
+ }
+ case Type_Info_Union:
+ tag_ptr := uintptr(v.data) + variant.tag_offset;
+ }
+ case json.Float:
+ if _, ok := type_info.variant.(Type_Info_Float); ok {
+ switch type_info.size {
+ case 8:
+ tmp := f64(j);
+ mem.copy(v.data, &tmp, type_info.size);
+ case 4:
+ tmp := f32(j);
+ mem.copy(v.data, &tmp, type_info.size);
+ case:
+ return .Invalid_Data;
+ }
+ }
+ case json.Null:
+ case json.Boolean:
+ if _, ok := type_info.variant.(Type_Info_Boolean); ok {
+ tmp := bool(j);
+ mem.copy(v.data, &tmp, type_info.size);
+ }
+ case:
+ return .Unsupported_Type;
+ }
+
+ return .None;
+} \ No newline at end of file
diff --git a/src/server/workspace.odin b/src/server/workspace.odin
index abb4e43..f275077 100644
--- a/src/server/workspace.odin
+++ b/src/server/workspace.odin
@@ -1 +1 @@
-package server
+package server \ No newline at end of file
diff --git a/src/server/writer.odin b/src/server/writer.odin
index 3edc4ab..6a1b8ed 100644
--- a/src/server/writer.odin
+++ b/src/server/writer.odin
@@ -6,32 +6,30 @@ import "core:fmt"
import "core:strings"
import "core:sync"
-WriterFn :: proc(rawptr, [] byte) -> (int, int);
+WriterFn :: proc (_: rawptr, _: []byte) -> (int, int);
Writer :: struct {
- writer_fn: WriterFn,
- writer_context: rawptr,
- writer_mutex: sync.Mutex,
-};
-
-make_writer :: proc(writer_fn: WriterFn, writer_context: rawptr) -> Writer {
- writer := Writer { writer_context = writer_context, writer_fn = writer_fn };
- sync.mutex_init(&writer.writer_mutex);
- return writer;
+ writer_fn: WriterFn,
+ writer_context: rawptr,
+ writer_mutex: sync.Mutex,
}
-write_sized :: proc(writer: ^Writer, data: []byte) -> bool {
-
- sync.mutex_lock(&writer.writer_mutex);
- defer sync.mutex_unlock(&writer.writer_mutex);
+make_writer :: proc (writer_fn: WriterFn, writer_context: rawptr) -> Writer {
+ writer := Writer {writer_context = writer_context, writer_fn = writer_fn};
+ sync.mutex_init(&writer.writer_mutex);
+ return writer;
+}
- written, err := writer.writer_fn(writer.writer_context, data);
+write_sized :: proc (writer: ^Writer, data: []byte) -> bool {
- if(err != 0) {
- return false;
- }
+ sync.mutex_lock(&writer.writer_mutex);
+ defer sync.mutex_unlock(&writer.writer_mutex);
- return true;
-}
+ written, err := writer.writer_fn(writer.writer_context, data);
+ if (err != 0) {
+ return false;
+ }
+ return true;
+} \ No newline at end of file