aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDanielGavin <danielgavin5@hotmail.com>2021-04-25 22:33:42 +0200
committerDanielGavin <danielgavin5@hotmail.com>2021-04-25 22:33:42 +0200
commite96b24da93e22549c6f32cd9d46c28bd0b608b5a (patch)
treefc082f5bcc83ed4ed26eaa42b20edbade783bc76 /src
parent28d227ec89a4cbe15021eddeb16e356ec13bf51f (diff)
parentb43fc8881fa1e48c7e0c1af582ce499292daf436 (diff)
Merge branch 'master' of https://github.com/DanielGavin/ols
Diffstat (limited to 'src')
-rw-r--r--src/common/allocator.odin251
-rw-r--r--src/common/ast.odin26
-rw-r--r--src/common/config.odin2
-rw-r--r--src/common/position.odin30
-rw-r--r--src/common/track_allocator.odin192
-rw-r--r--src/index/build.odin2
-rw-r--r--src/index/clone.odin9
-rw-r--r--src/index/collector.odin48
-rw-r--r--src/index/symbol.odin4
-rw-r--r--src/server/analysis.odin294
-rw-r--r--src/server/completion.odin123
-rw-r--r--src/server/hover.odin5
-rw-r--r--src/server/requests.odin24
-rw-r--r--src/server/semantic_tokens.odin35
-rw-r--r--src/server/types.odin5
-rw-r--r--src/server/unmarshal.odin14
-rw-r--r--src/testing/testing.odin25
17 files changed, 561 insertions, 528 deletions
diff --git a/src/common/allocator.odin b/src/common/allocator.odin
index 4f72f81..ca0abe6 100644
--- a/src/common/allocator.odin
+++ b/src/common/allocator.odin
@@ -1,121 +1,130 @@
-package common
-
-import "core:mem"
-
-Scratch_Allocator :: struct {
- data: []byte,
- curr_offset: int,
- prev_allocation: rawptr,
- backup_allocator: mem.Allocator,
- leaked_allocations: [dynamic]rawptr,
-}
-
-scratch_allocator_init :: proc (s: ^Scratch_Allocator, size: int, backup_allocator := context.allocator) {
- s.data = mem.make_aligned([]byte, size, 2 * align_of(rawptr), backup_allocator);
- s.curr_offset = 0;
- s.prev_allocation = nil;
- s.backup_allocator = backup_allocator;
- s.leaked_allocations.allocator = backup_allocator;
-}
-
-scratch_allocator_destroy :: proc (s: ^Scratch_Allocator) {
- if s == nil {
- return;
- }
- for ptr in s.leaked_allocations {
- free(ptr, s.backup_allocator);
- }
- delete(s.leaked_allocations);
- delete(s.data, s.backup_allocator);
- s^ = {};
-}
-
-scratch_allocator_proc :: proc (allocator_data: rawptr, mode: mem.Allocator_Mode,
-size, alignment: int,
-old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
-
- s := (^Scratch_Allocator)(allocator_data);
-
- if s.data == nil {
- DEFAULT_BACKING_SIZE :: 1 << 22;
- if !(context.allocator.procedure != scratch_allocator_proc &&
- context.allocator.data != allocator_data) {
- panic("cyclic initialization of the scratch allocator with itself");
- }
- scratch_allocator_init(s, DEFAULT_BACKING_SIZE);
- }
-
- size := size;
-
- switch mode {
- case .Alloc:
- size = mem.align_forward_int(size, alignment);
-
- switch {
- case s.curr_offset + size <= len(s.data):
- start := uintptr(raw_data(s.data));
- ptr := start + uintptr(s.curr_offset);
- ptr = mem.align_forward_uintptr(ptr, uintptr(alignment));
- mem.zero(rawptr(ptr), size);
-
- s.prev_allocation = rawptr(ptr);
- offset := int(ptr - start);
- s.curr_offset = offset + size;
- return rawptr(ptr);
- }
- a := s.backup_allocator;
- if a.procedure == nil {
- a = context.allocator;
- s.backup_allocator = a;
- }
-
- ptr := mem.alloc(size, alignment, a, loc);
- if s.leaked_allocations == nil {
- s.leaked_allocations = make([dynamic]rawptr, a);
- }
- append(&s.leaked_allocations, ptr);
-
- return ptr;
-
- case .Free:
- case .Free_All:
- s.curr_offset = 0;
- s.prev_allocation = nil;
- for ptr in s.leaked_allocations {
- free(ptr, s.backup_allocator);
- }
- clear(&s.leaked_allocations);
-
- case .Resize:
- begin := uintptr(raw_data(s.data));
- end := begin + uintptr(len(s.data));
- old_ptr := uintptr(old_memory);
- //if begin <= old_ptr && old_ptr < end && old_ptr+uintptr(size) < end {
- // s.curr_offset = int(old_ptr-begin)+size;
- // return old_memory;
- //}
- ptr := scratch_allocator_proc(allocator_data, .Alloc, size, alignment, old_memory, old_size, flags, loc);
- mem.copy(ptr, old_memory, old_size);
- scratch_allocator_proc(allocator_data, .Free, 0, alignment, old_memory, old_size, flags, loc);
- return ptr;
-
- case .Query_Features:
- set := (^mem.Allocator_Mode_Set)(old_memory);
- if set != nil {
- set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features};
- }
- return set;
-
- case .Query_Info:
- return nil;
- }
-
- return nil;
-}
-
-scratch_allocator :: proc (allocator: ^Scratch_Allocator) -> mem.Allocator {
- return mem.Allocator {
- procedure = scratch_allocator_proc,
- data = allocator,
- };
-}
+package common
+
+import "core:mem"
+import "core:runtime"
+
+Scratch_Allocator :: struct {
+ data: []byte,
+ curr_offset: int,
+ prev_allocation: rawptr,
+ backup_allocator: mem.Allocator,
+ leaked_allocations: [dynamic][]byte,
+}
+
+scratch_allocator_init :: proc (s: ^Scratch_Allocator, size: int, backup_allocator := context.allocator) {
+ s.data = mem.make_aligned([]byte, size, 2 * align_of(rawptr), backup_allocator);
+ s.curr_offset = 0;
+ s.prev_allocation = nil;
+ s.backup_allocator = backup_allocator;
+ s.leaked_allocations.allocator = backup_allocator;
+}
+
+scratch_allocator_destroy :: proc (s: ^Scratch_Allocator) {
+ if s == nil {
+ return;
+ }
+ for ptr in s.leaked_allocations {
+ mem.free_bytes(ptr, s.backup_allocator);
+ }
+ delete(s.leaked_allocations);
+ delete(s.data, s.backup_allocator);
+ s^ = {};
+}
+
+scratch_allocator_proc :: proc (allocator_data: rawptr, mode: mem.Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, mem.Allocator_Error) {
+
+ s := (^Scratch_Allocator)(allocator_data);
+
+ if s.data == nil {
+ DEFAULT_BACKING_SIZE :: 1 << 22;
+ if !(context.allocator.procedure != scratch_allocator_proc &&
+ context.allocator.data != allocator_data) {
+ panic("cyclic initialization of the scratch allocator with itself");
+ }
+ scratch_allocator_init(s, DEFAULT_BACKING_SIZE);
+ }
+
+ size := size;
+
+ switch mode {
+ case .Alloc:
+ size = mem.align_forward_int(size, alignment);
+
+ switch {
+ case s.curr_offset + size <= len(s.data):
+ start := uintptr(raw_data(s.data));
+ ptr := start + uintptr(s.curr_offset);
+ ptr = mem.align_forward_uintptr(ptr, uintptr(alignment));
+ mem.zero(rawptr(ptr), size);
+
+ s.prev_allocation = rawptr(ptr);
+ offset := int(ptr - start);
+ s.curr_offset = offset + size;
+ return mem.byte_slice(rawptr(ptr), size), nil;
+ }
+
+ a := s.backup_allocator;
+ if a.procedure == nil {
+ a = context.allocator;
+ s.backup_allocator = a;
+ }
+
+ ptr, err := mem.alloc_bytes(size, alignment, a, loc);
+ if err != nil {
+ return ptr, err;
+ }
+ if s.leaked_allocations == nil {
+ s.leaked_allocations = make([dynamic][]byte, a);
+ }
+ append(&s.leaked_allocations, ptr);
+
+ if logger := context.logger; logger.lowest_level <= .Warning {
+ if logger.procedure != nil {
+ logger.procedure(logger.data, .Warning, "mem.Scratch_Allocator resorted to backup_allocator" , logger.options, loc);
+ }
+ }
+
+ return ptr, err;
+
+ case .Free:
+ case .Free_All:
+ s.curr_offset = 0;
+ s.prev_allocation = nil;
+ for ptr in s.leaked_allocations {
+ mem.free_bytes(ptr, s.backup_allocator);
+ }
+ clear(&s.leaked_allocations);
+
+ case .Resize:
+ begin := uintptr(raw_data(s.data));
+ end := begin + uintptr(len(s.data));
+ old_ptr := uintptr(old_memory);
+
+ data, err := scratch_allocator_proc(allocator_data, .Alloc, size, alignment, old_memory, old_size, loc);
+ if err != nil {
+ return data, err;
+ }
+
+ runtime.copy(data, mem.byte_slice(old_memory, old_size));
+ _, err = scratch_allocator_proc(allocator_data, .Free, 0, alignment, old_memory, old_size, loc);
+ return data, err;
+
+ case .Query_Features:
+ set := (^mem.Allocator_Mode_Set)(old_memory);
+ if set != nil {
+ set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features};
+ }
+ return nil, nil;
+ case .Query_Info:
+ return nil, nil;
+ }
+
+ return nil, nil;
+}
+
+scratch_allocator :: proc (allocator: ^Scratch_Allocator) -> mem.Allocator {
+ return mem.Allocator {
+ procedure = scratch_allocator_proc,
+ data = allocator,
+ };
+}
diff --git a/src/common/ast.odin b/src/common/ast.odin
index 9ca58ed..5f8ffd0 100644
--- a/src/common/ast.odin
+++ b/src/common/ast.odin
@@ -34,8 +34,17 @@ GlobalExpr :: struct {
docs: ^ast.Comment_Group,
}
-collect_value_decl :: proc(exprs: ^[dynamic]GlobalExpr, file: ast.File, stmt: ^ast.Node) {
+collect_value_decl :: proc(exprs: ^[dynamic]GlobalExpr, file: ast.File, stmt: ^ast.Node, skip_private: bool) {
if value_decl, ok := stmt.derived.(ast.Value_Decl); ok {
+
+ for attribute in value_decl.attributes {
+ for elem in attribute.elems {
+ if ident, ok := elem.derived.(ast.Ident); ok && ident.name == "private" && skip_private {
+ return;
+ }
+ }
+ }
+
for name, i in value_decl.names {
str := get_ast_node_string(name, file.src);
@@ -50,15 +59,14 @@ collect_value_decl :: proc(exprs: ^[dynamic]GlobalExpr, file: ast.File, stmt: ^a
}
}
-//TODO(add a sub procedure to avoid repeating the value decl work)
-collect_globals :: proc(file: ast.File) -> []GlobalExpr {
+collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr {
exprs := make([dynamic]GlobalExpr, context.temp_allocator);
for decl in file.decls {
if value_decl, ok := decl.derived.(ast.Value_Decl); ok {
- collect_value_decl(&exprs, file, decl);
+ collect_value_decl(&exprs, file, decl, skip_private);
} else if when_decl, ok := decl.derived.(ast.When_Stmt); ok {
if when_decl.cond == nil {
@@ -96,13 +104,13 @@ collect_globals :: proc(file: ast.File) -> []GlobalExpr {
if block, ok := when_decl.body.derived.(ast.Block_Stmt); ok {
for stmt in block.stmts {
- collect_value_decl(&exprs, file, stmt);
+ collect_value_decl(&exprs, file, stmt, skip_private);
}
}
} else if ident.name != "ODIN_OS" {
if block, ok := when_decl.body.derived.(ast.Block_Stmt); ok {
for stmt in block.stmts {
- collect_value_decl(&exprs, file, stmt);
+ collect_value_decl(&exprs, file, stmt, skip_private);
}
}
}
@@ -112,7 +120,7 @@ collect_globals :: proc(file: ast.File) -> []GlobalExpr {
else {
if block, ok := when_decl.body.derived.(ast.Block_Stmt); ok {
for stmt in block.stmts {
- collect_value_decl(&exprs, file, stmt);
+ collect_value_decl(&exprs, file, stmt, skip_private);
}
}
}
@@ -124,7 +132,7 @@ collect_globals :: proc(file: ast.File) -> []GlobalExpr {
if block, ok := foreign_decl.body.derived.(ast.Block_Stmt); ok {
for stmt in block.stmts {
- collect_value_decl(&exprs, file, stmt);
+ collect_value_decl(&exprs, file, stmt, skip_private);
}
}
}
@@ -373,7 +381,7 @@ free_ast_node :: proc(node: ^ast.Node, allocator: mem.Allocator) {
free_ast(n.key, allocator);
free_ast(n.value, allocator);
case:
- log.warnf("free Unhandled node kind: %T", n);
+ panic(fmt.aprintf("free Unhandled node kind: %T", n));
}
mem.free(node, allocator);
diff --git a/src/common/config.odin b/src/common/config.odin
index df6ddb1..432794f 100644
--- a/src/common/config.odin
+++ b/src/common/config.odin
@@ -11,3 +11,5 @@ Config :: struct {
debug_single_thread: bool,
enable_semantic_tokens: bool, //This will be removed when vscode client stops sending me semantic tokens after disabling it in requests initialize.
}
+
+config: Config; \ No newline at end of file
diff --git a/src/common/position.odin b/src/common/position.odin
index 865d0c8..d410ce6 100644
--- a/src/common/position.odin
+++ b/src/common/position.odin
@@ -208,7 +208,7 @@ get_character_offset_u16_to_u8 :: proc(character_offset: int, document_text: []u
r, w := utf8.decode_rune(document_text[utf8_idx:]);
- if r == '\n' {
+ if r == '\n' || r == '\r' {
return utf8_idx;
} else if w == 0 {
return utf8_idx;
@@ -233,7 +233,7 @@ get_character_offset_u8_to_u16 :: proc(character_offset: int, document_text: []u
r, w := utf8.decode_rune(document_text[utf8_idx:]);
- if r == '\n' {
+ if r == '\n' || r == '\r' {
return utf16_idx;
} else if w == 0 {
return utf16_idx;
@@ -247,28 +247,4 @@ get_character_offset_u8_to_u16 :: proc(character_offset: int, document_text: []u
}
return utf16_idx;
-}
-
-get_end_line_u16 :: proc(document_text: []u8) -> int {
-
- utf8_idx := 0;
- utf16_idx := 0;
-
- for utf8_idx < len(document_text) {
- r, w := utf8.decode_rune(document_text[utf8_idx:]);
-
- if r == '\n' {
- return utf16_idx;
- } else if w == 0 {
- return utf16_idx;
- } else if r < 0x10000 {
- utf16_idx += 1;
- } else {
- utf16_idx += 2;
- }
-
- utf8_idx += w;
- }
-
- return utf16_idx;
-}
+} \ No newline at end of file
diff --git a/src/common/track_allocator.odin b/src/common/track_allocator.odin
deleted file mode 100644
index 978a74e..0000000
--- a/src/common/track_allocator.odin
+++ /dev/null
@@ -1,192 +0,0 @@
-package common
-
-/*
- https://gist.github.com/jharler/7ee9a4d5b46e31f7f9399da49cfabe72
-*/
-
-import "core:mem"
-import "core:fmt"
-import "core:runtime"
-import "core:sync"
-import "core:log"
-
-// ----------------------------------------------------------------------------------------------------
-
-ThreadSafe_Allocator_Data :: struct {
- actual_allocator: mem.Allocator,
- mutex: sync.Mutex,
-}
-
-// ----------------------------------------------------------------------------------------------------
-
-threadsafe_allocator :: proc(allocator: mem.Allocator) -> mem.Allocator {
- data := new(ThreadSafe_Allocator_Data);
- data.actual_allocator = allocator;
- sync.mutex_init(&data.mutex);
-
- return mem.Allocator {procedure = threadsafe_allocator_proc, data = data};
-}
-
-// ----------------------------------------------------------------------------------------------------
-
-threadsafe_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, size, alignment: int,
-old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
-
- data := cast(^ThreadSafe_Allocator_Data)allocator_data;
-
- sync.mutex_lock(&data.mutex);
- defer sync.mutex_unlock(&data.mutex);
-
- return data.actual_allocator.procedure(data.actual_allocator.data, mode, size, alignment, old_memory, old_size, flags, loc);
-}
-
-// ----------------------------------------------------------------------------------------------------
-
-Memleak_Allocator_Data :: struct {
- actual_allocator: mem.Allocator,
- allocations: map[rawptr]Memleak_Entry,
- frees: map[rawptr]Memleak_Entry,
- allocation_count: u32,
- unexpected_frees: u32,
- mutex: sync.Mutex,
- track_frees: bool,
-}
-
-// ----------------------------------------------------------------------------------------------------
-
-Memleak_Entry :: struct {
- location: runtime.Source_Code_Location,
- size: int,
- index: u32,
-}
-
-// ----------------------------------------------------------------------------------------------------
-
-memleak_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, size, alignment: int,
-old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
-
- memleak := cast(^Memleak_Allocator_Data)allocator_data;
-
- sync.mutex_lock(&memleak.mutex);
- defer sync.mutex_unlock(&memleak.mutex);
-
- if mode == .Free {
- if old_memory not_in memleak.allocations {
- if memleak.track_frees {
- if old_memory in memleak.frees {
- fmt.println(fmt.tprintf("{0}({1}:{2}) {3} freed memory already freed by this memleak allocator", loc.file_path, loc.line, loc.column, loc.procedure));
- free_loc := memleak.frees[old_memory].location;
- fmt.println(fmt.tprintf("{0}({1}:{2}) {3} <<< freed here", loc.file_path, loc.line, loc.column, loc.procedure));
- } else {
- fmt.println(fmt.tprintf("{0}({1}:{2}) {3} freed memory not allocated or previously freed by this memleak allocator", loc.file_path, loc.line, loc.column, loc.procedure));
- }
- } else {
- fmt.println(fmt.tprintf("{0}({1}:{2}) {3} freed memory not allocated by this memleak allocator", loc.file_path, loc.line, loc.column, loc.procedure));
- }
- memleak.unexpected_frees += 1;
- return nil;
- } else {
- //entry := &memleak.allocations[old_memory];
- delete_key(&memleak.allocations, old_memory);
-
- if memleak.track_frees {
- memleak.frees[old_memory] = Memleak_Entry {
- location = loc,
- size = size,
- index = 0,
- };
- }
- }
- }
-
- result := memleak.actual_allocator.procedure(memleak.actual_allocator.data, mode, size, alignment, old_memory, old_size, flags, loc);
-
- if mode == .Resize && result != old_memory {
- delete_key(&memleak.allocations, old_memory);
- }
-
- if mode != .Free {
- // using a conditional breakpoint with memleak.allocation_count in the condition
- // can be very useful for inspecting the stack trace of a particular allocation
-
- memleak.allocations[result] = Memleak_Entry {
- location = loc,
- size = size,
- index = memleak.allocation_count,
- };
-
- memleak.allocation_count += 1;
-
- if memleak.track_frees {
- if result in memleak.frees {
- delete_key(&memleak.frees, result);
- }
- }
- }
-
- return result;
-}
-
-// ----------------------------------------------------------------------------------------------------
-
-memleak_allocator :: proc(track_frees: bool) -> mem.Allocator {
-
- make([]byte, 1, context.temp_allocator); // so the temp allocation doesn't clutter our results
-
- data := new(Memleak_Allocator_Data);
- data.actual_allocator = context.allocator;
- data.allocations = make(map[rawptr]Memleak_Entry);
-
- if track_frees {
- data.track_frees = true;
- data.frees = make(map[rawptr]Memleak_Entry);
- }
-
- sync.mutex_init(&data.mutex);
-
- return mem.Allocator {procedure = memleak_allocator_proc, data = data};
-}
-
-// ----------------------------------------------------------------------------------------------------
-
-memleak_detected_leaks :: proc() -> bool {
- if context.allocator.procedure == memleak_allocator_proc {
- memleak := cast(^Memleak_Allocator_Data)context.allocator.data;
- return len(memleak.allocations) > 0;
- }
-
- return false;
-}
-
-// ----------------------------------------------------------------------------------------------------
-
-memleak_dump :: proc(memleak_alloc: mem.Allocator, dump_proc: proc(message: string, user_data: rawptr), user_data: rawptr) {
- memleak := cast(^Memleak_Allocator_Data)memleak_alloc.data;
-
- context.allocator = memleak.actual_allocator;
-
- // check for an ignore default_temp_allocator_proc allocations
- tmp_check := 0;
- for _, leak in &memleak.allocations {
- if leak.location.procedure == "default_temp_allocator_proc" {
- tmp_check += 1;
- }
- }
-
- dump_proc(fmt.tprintf("{0} memory leaks detected!", len(memleak.allocations) - tmp_check), user_data);
- dump_proc(fmt.tprintf("{0} unexpected frees", memleak.unexpected_frees), user_data);
-
- for _, leak in &memleak.allocations {
- if leak.location.procedure != "default_temp_allocator_proc" {
- dump_proc(fmt.tprintf("{0}({1}:{2}) {3} allocated {4} bytes [{5}]", leak.location.file_path, leak.location.line, leak.location.column, leak.location.procedure, leak.size, leak.index), user_data);
- }
- }
-
- context.allocator = mem.Allocator {procedure = memleak_allocator_proc, data = memleak};
-}
-
-// ----------------------------------------------------------------------------------------------------
-
-log_dump :: proc(message: string, user_data: rawptr) {
- log.info(message);
-}
diff --git a/src/index/build.odin b/src/index/build.odin
index ad6ba2a..b464ce9 100644
--- a/src/index/build.odin
+++ b/src/index/build.odin
@@ -19,7 +19,7 @@ files: [dynamic]string;
platform_os: map[string]bool = {
"windows" = true,
- "linux" = true,
+ "linux" = true,
"essence" = true,
"js" = true,
"freebsd" = true,
diff --git a/src/index/clone.odin b/src/index/clone.odin
index f9a7604..0380c78 100644
--- a/src/index/clone.odin
+++ b/src/index/clone.odin
@@ -30,7 +30,7 @@ clone_array :: proc(array: $A/[]^$T, allocator: mem.Allocator, unique_strings: ^
}
res := make(A, len(array), allocator);
for elem, i in array {
- res[i] = auto_cast clone_type(elem, allocator, unique_strings);
+ res[i] = cast(^T)clone_type(elem, allocator, unique_strings);
}
return res;
}
@@ -43,7 +43,7 @@ clone_dynamic_array :: proc(array: $A/[dynamic]^$T, allocator: mem.Allocator, un
for elem, i in array {
res[i] = auto_cast clone_type(elem, allocator, unique_strings);
}
- return res;
+ return res;
}
clone_expr :: proc(node: ^ast.Expr, allocator: mem.Allocator, unique_strings: ^map[string]string) -> ^ast.Expr {
@@ -211,6 +211,8 @@ clone_node :: proc(node: ^ast.Node, allocator: mem.Allocator, unique_strings: ^m
case Proc_Lit:
r := cast(^Proc_Lit)res;
r.type = cast(^Proc_Type)clone_type(cast(^Node)r.type, allocator, unique_strings);
+ r.body = nil;
+ r.where_clauses = nil;
case Helper_Type:
r := cast(^Helper_Type)res;
r.type = clone_type(r.type, allocator, unique_strings);
@@ -218,6 +220,9 @@ clone_node :: proc(node: ^ast.Node, allocator: mem.Allocator, unique_strings: ^m
r := cast(^Type_Cast)res;
r.type = clone_type(r.type, allocator, unique_strings);
r.expr = clone_type(r.expr, allocator, unique_strings);
+ case Deref_Expr:
+ r := cast(^Deref_Expr)res;
+ r.expr = clone_type(r.expr, allocator, unique_strings);
case:
panic(fmt.aprintf("Clone type Unhandled node kind: %T", node.derived));
}
diff --git a/src/index/collector.odin b/src/index/collector.odin
index 14fc772..0125762 100644
--- a/src/index/collector.odin
+++ b/src/index/collector.odin
@@ -12,7 +12,7 @@ import "core:strconv"
import "shared:common"
-SymbolCollection :: struct {
+SymbolCollection :: struct {
allocator: mem.Allocator,
config: ^common.Config,
symbols: map[uint]Symbol,
@@ -161,7 +161,10 @@ collect_union_fields :: proc(collection: ^SymbolCollection, union_type: ast.Unio
}
}
- append(&types, clone_type(variant, collection.allocator, &collection.unique_strings));
+ cloned := clone_type(variant, collection.allocator, &collection.unique_strings);
+ replace_package_alias(cloned, package_map, collection);
+
+ append(&types, cloned);
}
value := SymbolUnionValue {
@@ -174,8 +177,11 @@ collect_union_fields :: proc(collection: ^SymbolCollection, union_type: ast.Unio
collect_bitset_field :: proc(collection: ^SymbolCollection, bitset_type: ast.Bit_Set_Type, package_map: map[string]string) -> SymbolBitSetValue {
+ cloned := clone_type(bitset_type.elem, collection.allocator, &collection.unique_strings);
+ replace_package_alias(cloned, package_map, collection);
+
value := SymbolBitSetValue {
- expr = clone_type(bitset_type.elem, collection.allocator, &collection.unique_strings),
+ expr = cloned,
};
return value;
@@ -195,8 +201,7 @@ collect_generic :: proc(collection: ^SymbolCollection, expr: ^ast.Expr, package_
collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: string) -> common.Error {
- forward, _ := filepath.to_slash(file.fullpath, context.temp_allocator);
- package_map := get_package_mapping(file, collection.config, uri);
+ forward, _ := filepath.to_slash(file.fullpath, context.temp_allocator);
when ODIN_OS == "windows" {
directory := strings.to_lower(path.dir(forward, context.temp_allocator), context.temp_allocator);
@@ -204,9 +209,9 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
directory := path.dir(forward, context.temp_allocator);
}
-
+ package_map := get_package_mapping(file, collection.config, directory);
- exprs := common.collect_globals(file);
+ exprs := common.collect_globals(file, true);
for expr in exprs {
@@ -295,13 +300,20 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
symbol.value = collect_generic(collection, col_expr, package_map);
case ast.Ident:
token = v;
- token_type = .Variable;
symbol.value = collect_generic(collection, col_expr, package_map);
+ if expr.mutable {
+ token_type = .Variable;
+ } else {
+ token_type = .Unresolved;
+ }
case: // default
symbol.value = collect_generic(collection, col_expr, package_map);
- token_type = .Variable;
- token = expr.expr;
- break;
+ if expr.mutable {
+ token_type = .Variable;
+ } else {
+ token_type = .Unresolved;
+ }
+ token = expr.expr;
}
symbol.range = common.get_token_range(token, file.src);
@@ -314,8 +326,8 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
} else {
symbol.uri = get_index_unique_string(collection, uri);
}
-
-
+
+
if expr.docs != nil {
tmp: string;
@@ -347,7 +359,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
/*
Gets the map from import alias to absolute package directory
*/
-get_package_mapping :: proc(file: ast.File, config: ^common.Config, uri: string) -> map[string]string {
+get_package_mapping :: proc(file: ast.File, config: ^common.Config, directory: string) -> map[string]string {
package_map := make(map[string]string, 0, context.temp_allocator);
@@ -389,15 +401,12 @@ get_package_mapping :: proc(file: ast.File, config: ^common.Config, uri: string)
name: string;
- base := path.base(uri, false, context.temp_allocator);
-
- full := path.join(elems = {base, imp.fullpath[1:len(imp.fullpath) - 1]}, allocator = context.temp_allocator);
+ full := path.join(elems = {directory, imp.fullpath[1:len(imp.fullpath) - 1]}, allocator = context.temp_allocator);
full = path.clean(full, context.temp_allocator);
if imp.name.text != "" {
name = imp.name.text;
- //ERROR hover is wrong on name
} else {
name = path.base(full, false, context.temp_allocator);
}
@@ -541,6 +550,9 @@ replace_package_alias_node :: proc(node: ^ast.Node, package_map: map[string]stri
case Comp_Lit:
replace_package_alias(n.type, package_map, collection);
replace_package_alias(n.elems, package_map, collection);
+ case Helper_Type:
+ replace_package_alias(n.type, package_map, collection);
+ case Proc_Lit:
case:
log.warnf("Replace Unhandled node kind: %T", n);
}
diff --git a/src/index/symbol.odin b/src/index/symbol.odin
index 9fd656d..0f9069a 100644
--- a/src/index/symbol.odin
+++ b/src/index/symbol.odin
@@ -4,7 +4,6 @@ import "core:odin/ast"
import "core:hash"
import "core:strings"
import "core:mem"
-import "core:fmt"
import "core:path/filepath"
import "core:path"
import "core:slice"
@@ -88,13 +87,14 @@ SymbolType :: enum {
Keyword = 14,
EnumMember = 20,
Struct = 22,
+ Unresolved = 9999,
}
free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) {
if symbol.signature != "" && symbol.signature != "struct" &&
symbol.signature != "union" && symbol.signature != "enum" &&
- symbol.signature != "bitset" && symbol.signature != "bitfield" {
+ symbol.signature != "bitset" {
delete(symbol.signature, allocator);
}
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index 87fb54e..7f108e2 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -39,26 +39,27 @@ DocumentPositionContext :: struct {
position: common.AbsolutePosition,
line: int,
function: ^ast.Proc_Lit, //used to help with type resolving in function scope
- selector: ^ast.Expr, //used for completion
+ selector: ^ast.Expr, //used for completion
identifier: ^ast.Node,
tag: ^ast.Node,
- field: ^ast.Expr, //used for completion
- call: ^ast.Expr, //used for signature help
+ field: ^ast.Expr, //used for completion
+ call: ^ast.Expr, //used for signature help
returns: ^ast.Return_Stmt, //used for completion
- comp_lit: ^ast.Comp_Lit, //used for completion
- parent_comp_lit: ^ast.Comp_Lit, //used for completion
- implicit: bool, //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
- parent_binary: ^ast.Binary_Expr, //used for completion
- assign: ^ast.Assign_Stmt, //used for completion
- switch_stmt: ^ast.Switch_Stmt, //used for completion
+ binary: ^ast.Binary_Expr, //used for completion
+ parent_binary: ^ast.Binary_Expr, //used for completion
+ assign: ^ast.Assign_Stmt, //used for completion
+ switch_stmt: ^ast.Switch_Stmt, //used for completion
switch_type_stmt: ^ast.Type_Switch_Stmt, //used for completion
- case_clause: ^ast.Case_Clause, //used for completion
- value_decl: ^ast.Value_Decl, //used for completion
+ case_clause: ^ast.Case_Clause, //used for completion
+ value_decl: ^ast.Value_Decl, //used for completion
abort_completion: bool,
hint: DocumentPositionContextHint,
global_lhs_stmt: bool,
+ import_stmt: ^ast.Import_Decl,
}
DocumentLocal :: struct {
@@ -67,26 +68,28 @@ DocumentLocal :: struct {
}
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 {
+ 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,
+ uri: string,
+
+}
+
+make_ast_context :: proc(file: ast.File, imports: []Package, package_name: string, uri: string, allocator := context.temp_allocator) -> AstContext {
ast_context := AstContext {
locals = make(map[string][dynamic]DocumentLocal, 0, allocator),
@@ -101,7 +104,13 @@ make_ast_context :: proc(file: ast.File, imports: []Package, package_name: strin
use_globals = true,
document_package = package_name,
current_package = package_name,
+ uri = uri,
};
+
+ when ODIN_OS == "windows" {
+ ast_context.uri = strings.to_lower(ast_context.uri, allocator);
+ }
+
return ast_context;
}
@@ -379,10 +388,10 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast
function_range: common.Range;
if ident, ok := call_expr.expr.derived.(Ident); ok {
- function_name = ident.name;
+ 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_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");
@@ -420,8 +429,6 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast
arg_types = params,
};
- //log.infof("return %v", poly_map);
-
return symbol, true;
}
@@ -451,10 +458,7 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou
using ast;
- //log.info("overload");
-
if ast_context.call == nil {
- //log.info("no call");
return index.Symbol {}, false;
}
@@ -623,7 +627,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i
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.expr = s.return_types[0].type;
selector_expr.field = v.field;
return resolve_type_expression(ast_context, selector_expr);
}
@@ -672,7 +676,7 @@ store_local :: proc(ast_context: ^AstContext, expr: ^ast.Expr, offset: int, name
if local_stack == nil {
ast_context.locals[name] = make([dynamic]DocumentLocal, context.temp_allocator);
- local_stack = &ast_context.locals[name];
+ local_stack = &ast_context.locals[name];
}
append(local_stack, DocumentLocal {expr = expr, offset = offset});
@@ -684,9 +688,7 @@ get_local :: proc(ast_context: ^AstContext, offset: int, name: string) -> ^ast.E
//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 ident, ok := value_decl_name.derived.(ast.Ident); ok {
if ident.name == name {
@@ -698,11 +700,13 @@ get_local :: proc(ast_context: ^AstContext, offset: int, name: string) -> ^ast.E
}
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;
+ if i - previous < 0 {
+ return nil;
+ } else {
+ return local_stack[i - previous].expr;
+ }
}
}
}
@@ -724,9 +728,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i
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,
@@ -741,13 +743,14 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i
//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;
+ if dist, ok := local.derived.(ast.Distinct_Type); ok {
+ if dist.type != nil {
+ local = dist.type; //save information for overloading
}
+ }
+ switch v in local.derived {
+ case Ident:
return resolve_type_identifier(ast_context, v);
case Union_Type:
return make_symbol_union_from_ast(ast_context, v, node), true;
@@ -774,17 +777,17 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i
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;
+ if dist, ok := global.derived.(ast.Distinct_Type); ok {
+ if dist.type != nil {
+ global = dist.type; //save information for overloading
}
+ }
+ switch v in global.derived {
+ case Ident:
return resolve_type_identifier(ast_context, v);
case Struct_Type:
return make_symbol_struct_from_ast(ast_context, v, node), true;
@@ -879,7 +882,6 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i
}
}
- //TODO(daniel, index can be used on identifiers if using is in the function scope)
}
return index.Symbol {}, false;
@@ -920,7 +922,7 @@ expand_struct_usings :: proc(ast_context: ^AstContext, symbol: index.Symbol, val
//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 {
@@ -966,6 +968,12 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok
return symbol, ok;
}
+ symbol := symbol;
+
+ if symbol.type == .Unresolved {
+ fix_symbol_unresolved_type(&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 {
@@ -997,6 +1005,29 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok
return symbol, true;
}
+fix_symbol_unresolved_type :: proc(symbol: ^index.Symbol) {
+
+ using index;
+
+ switch v in symbol.value {
+ case SymbolStructValue:
+ symbol.type = .Struct;
+ case SymbolPackageValue:
+ symbol.type = .Package;
+ case SymbolProcedureValue, SymbolProcedureGroupValue:
+ symbol.type = .Function;
+ case SymbolGenericValue:
+ symbol.type = .Variable;
+ case SymbolUnionValue:
+ symbol.type = .Enum;
+ case SymbolEnumValue:
+ symbol.type = .Enum;
+ case SymbolBitSetValue:
+ symbol.type = .Enum;
+ }
+
+}
+
resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (index.Symbol, bool) {
symbol: index.Symbol;
@@ -1359,7 +1390,7 @@ get_globals :: proc(file: ast.File, ast_context: ^AstContext) {
exprs := common.collect_globals(file);
for expr in exprs {
- ast_context.globals[expr.name] = expr.expr;
+ ast_context.globals[expr.name] = expr.expr;
ast_context.variables[expr.name] = expr.mutable;
}
}
@@ -1368,7 +1399,7 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A
using ast;
- ast_context.use_locals = true;
+ ast_context.use_locals = true;
ast_context.use_globals = true;
switch v in value.derived {
@@ -1424,7 +1455,7 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co
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);
+ store_local(ast_context, value_decl.type, value_decl.end.offset, str);
return;
}
@@ -1438,7 +1469,7 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co
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);
+ store_local(ast_context, results[i], value_decl.end.offset, str);
ast_context.variables[str] = value_decl.is_mutable;
}
}
@@ -1446,8 +1477,8 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co
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.use_locals = true;
+ ast_context.use_globals = true;
ast_context.current_package = ast_context.document_package;
using ast;
@@ -1509,8 +1540,8 @@ get_locals_using_stmt :: proc(stmt: ast.Using_Stmt, ast_context: ^AstContext) {
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.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;
@@ -1577,10 +1608,18 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont
switch v in generic.expr.derived {
case Map_Type:
- for val in stmt.vals {
- if ident, ok := val.derived.(Ident); ok {
+ if len(stmt.vals) >= 1 {
+ if ident, ok := stmt.vals[0].derived.(Ident); ok {
store_local(ast_context, v.key, ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
+ ast_context.variables[ident.name] = true;
+ ast_context.in_package[ident.name] = symbol.pkg;
+ }
+ }
+
+ if len(stmt.vals) >= 2 {
+ if ident, ok := stmt.vals[1].derived.(Ident); ok {
+ store_local(ast_context, v.value, ident.pos.offset, ident.name);
+ ast_context.variables[ident.name] = true;
ast_context.in_package[ident.name] = symbol.pkg;
}
}
@@ -1588,7 +1627,7 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont
if len(stmt.vals) >= 1 {
if ident, ok := stmt.vals[0].derived.(Ident); ok {
store_local(ast_context, v.elem, ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
+ ast_context.variables[ident.name] = true;
ast_context.in_package[ident.name] = symbol.pkg;
}
}
@@ -1596,7 +1635,7 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont
if len(stmt.vals) >= 2 {
if ident, ok := stmt.vals[1].derived.(Ident); ok {
store_local(ast_context, make_int_ast(), ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
+ ast_context.variables[ident.name] = true;
ast_context.in_package[ident.name] = symbol.pkg;
}
}
@@ -1605,7 +1644,7 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont
if ident, ok := stmt.vals[0].derived.(Ident); ok {
store_local(ast_context, v.elem, ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
+ ast_context.variables[ident.name] = true;
ast_context.in_package[ident.name] = symbol.pkg;
}
}
@@ -1614,7 +1653,7 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont
if ident, ok := stmt.vals[1].derived.(Ident); ok {
store_local(ast_context, make_int_ast(), ident.pos.offset, ident.name);
- ast_context.variables[ident.name] = true;
+ ast_context.variables[ident.name] = true;
ast_context.in_package[ident.name] = symbol.pkg;
}
}
@@ -1694,12 +1733,12 @@ get_locals :: proc(file: ast.File, function: ^ast.Node, ast_context: ^AstContext
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.variables[str] = true;
ast_context.parameters[str] = true;
if .Using in arg.flags {
using_stmt: ast.Using_Stmt;
- using_stmt.list = make([]^ast.Expr, 1, context.temp_allocator);
+ using_stmt.list = make([]^ast.Expr, 1, context.temp_allocator);
using_stmt.list[0] = arg.type;
get_locals_using_stmt(using_stmt, ast_context);
}
@@ -1716,7 +1755,7 @@ get_locals :: proc(file: ast.File, function: ^ast.Node, ast_context: ^AstContext
if result.type != nil {
str := common.get_ast_node_string(name, file.src);
store_local(ast_context, result.type, name.pos.offset, str);
- ast_context.variables[str] = true;
+ ast_context.variables[str] = true;
ast_context.parameters[str] = true;
}
}
@@ -1771,7 +1810,7 @@ get_definition_location :: proc(document: ^Document, position: common.Position)
location: common.Location;
- ast_context := make_ast_context(document.ast, document.imports, document.package_name);
+ ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri);
uri: string;
@@ -1817,8 +1856,8 @@ get_definition_location :: proc(document: ^Document, position: common.Position)
selector: index.Symbol;
- ast_context.use_locals = true;
- ast_context.use_globals = true;
+ 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);
@@ -1851,7 +1890,7 @@ get_definition_location :: proc(document: ^Document, position: common.Position)
case index.SymbolPackageValue:
if symbol, ok := index.lookup(field, selector.pkg); ok {
location.range = symbol.range;
- uri = symbol.uri;
+ uri = symbol.uri;
} else {
return location, false;
}
@@ -1864,7 +1903,7 @@ get_definition_location :: proc(document: ^Document, position: common.Position)
if resolved, ok := resolve_location_identifier(&ast_context, position_context.identifier.derived.(ast.Ident)); ok {
location.range = resolved.range;
- uri = resolved.uri;
+ uri = resolved.uri;
} else {
return location, false;
}
@@ -1888,7 +1927,7 @@ write_hover_content :: proc(ast_context: ^AstContext, symbol: index.Symbol) -> M
cat := concatenate_symbols_information(ast_context, symbol, false);
if cat != "" {
- content.kind = "markdown";
+ content.kind = "markdown";
content.value = fmt.tprintf("```odin\n %v\n```\n%v", cat, symbol.doc);
} else {
content.kind = "plaintext";
@@ -1941,7 +1980,7 @@ get_signature_information :: proc(document: ^Document, position: common.Position
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, document.uri.uri);
position_context, ok := get_document_position_context(document, position, .SignatureHelp);
@@ -1968,10 +2007,10 @@ get_signature_information :: proc(document: ^Document, position: common.Position
signature_information := make([]SignatureInformation, 1, context.temp_allocator);
- signature_information[0].label = concatenate_symbols_information(&ast_context, call, false);
+ signature_information[0].label = concatenate_symbols_information(&ast_context, call, false);
signature_information[0].documentation = call.doc;
- signature_help.signatures = signature_information;
+ signature_help.signatures = signature_information;
signature_help.activeSignature = 0;
signature_help.activeParameter = 0;
@@ -1980,7 +2019,7 @@ get_signature_information :: proc(document: ^Document, position: common.Position
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, document.uri.uri);
get_globals(document.ast, &ast_context);
@@ -1992,8 +2031,8 @@ get_document_symbols :: proc(document: ^Document) -> []DocumentSymbol {
return {};
}
- package_symbol.kind = .Package;
- package_symbol.name = path.base(document.package_name, false, context.temp_allocator);
+ 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,
@@ -2010,16 +2049,16 @@ get_document_symbols :: proc(document: ^Document) -> []DocumentSymbol {
symbol: DocumentSymbol;
- symbol.range = common.get_token_range(expr, ast_context.file.src);
+ symbol.range = common.get_token_range(expr, ast_context.file.src);
symbol.selectionRange = symbol.range;
- symbol.name = k;
+ symbol.name = k;
switch v in expr.derived {
case ast.Struct_Type:
symbol.kind = .Struct;
- case ast.Proc_Lit,ast.Proc_Group:
+ case ast.Proc_Lit, ast.Proc_Group:
symbol.kind = .Function;
- case ast.Enum_Type,ast.Union_Type:
+ case ast.Enum_Type, ast.Union_Type:
symbol.kind = .Enum;
case:
symbol.kind = .Variable;
@@ -2055,17 +2094,31 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi
position_context.position = absolute_position;
+ exists_in_decl := false;
+
for decl in document.ast.decls {
if position_in_node(decl, position_context.position) {
get_document_position(decl, &position_context);
-
+ exists_in_decl = true;
switch v in decl.derived {
case ast.Expr_Stmt:
position_context.global_lhs_stmt = true;
}
+ break;
+ }
+ }
+
+ for import_stmt in document.ast.imports {
+ if position_in_node(import_stmt, position_context.position) {
+ position_context.import_stmt = import_stmt;
+ break;
}
}
+ if !exists_in_decl && position_context.import_stmt == nil {
+ position_context.abort_completion = true;
+ }
+
if !position_in_node(position_context.comp_lit, position_context.position) {
position_context.comp_lit = nil;
}
@@ -2154,15 +2207,15 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm
if c == ' ' || c == '{' || c == ',' ||
c == '}' || c == '^' || c == ':' ||
c == '\n' || c == '\r' || c == '=' ||
- c == '<' || c == '-' ||
- c == '+' || c == '&' {
+ c == '<' || c == '-' || c == '!' ||
+ c == '+' || c == '&'|| c == '|' {
start = i + 1;
break;
} else if c == '>' {
partial_arrow = true;
}
- last_dot = false;
+ last_dot = false;
last_arrow = false;
i -= 1;
@@ -2189,12 +2242,12 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm
return;
}
+ s := string(position_context.file.src[begin_offset:end_offset]);
+
if !partial_arrow {
only_whitespaces := true;
- s := string(position_context.file.src[begin_offset:end_offset]);
-
for r in s {
if !strings.is_space(r) {
only_whitespaces = false;
@@ -2207,16 +2260,16 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm
}
p := parser.Parser {
- err = parser_warning_handler, //empty
+ 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);
- p.tok.ch = ' ';
- p.tok.line_count = position.line;
- p.tok.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);
@@ -2235,7 +2288,7 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm
position_context.selector = e;
} else if s, ok := e.derived.(ast.Selector_Expr); ok {
position_context.selector = s.expr;
- position_context.field = s.field;
+ position_context.field = s.field;
} else if s, ok := e.derived.(ast.Implicit_Selector_Expr); ok {
position_context.implicit = true;
} else if s, ok := e.derived.(ast.Tag_Expr); ok {
@@ -2253,9 +2306,9 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm
tokenizer.init(&p.tok, position_context.file.src[0:last_dot], position_context.file.fullpath, parser_warning_handler);
- p.tok.ch = ' ';
- p.tok.line_count = position.line;
- p.tok.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);
@@ -2320,16 +2373,16 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo
str := position_context.file.src[0:end_offset];
p := parser.Parser {
- err = parser_warning_handler, //empty
+ 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);
- p.tok.ch = ' ';
- p.tok.line_count = position.line;
- p.tok.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);
@@ -2342,11 +2395,7 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo
context.allocator = context.temp_allocator;
- e := parser.parse_expr(&p, true);
-
- if call, ok := e.derived.(ast.Call_Expr); ok {
- position_context.call = e;
- }
+ position_context.call = parser.parse_expr(&p, true);
//log.error(string(position_context.file.src[begin_offset:end_offset]));
}
@@ -2355,7 +2404,7 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo
All these fallback functions are not perfect and should be fixed. A lot of weird use of the odin tokenizer and parser.
*/
-get_document_position :: proc {
+get_document_position ::proc {
get_document_position_array,
get_document_position_dynamic_array,
get_document_position_node,
@@ -2439,12 +2488,13 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP
case Selector_Expr:
if position_context.hint == .Completion {
if n.field != nil && n.field.pos.line - 1 == position_context.line {
- position_context.selector = n.expr;
- position_context.field = n.field;
+ //The parser is not fault tolerant enough, relying on the fallback as the main completion parsing for now
+ //position_context.selector = n.expr;
+ //position_context.field = n.field;
}
} else if (position_context.hint == .Definition || position_context.hint == .Hover) && n.field != nil {
position_context.selector = n.expr;
- position_context.field = n.field;
+ position_context.field = n.field;
get_document_position(n.expr, position_context);
get_document_position(n.field, position_context);
} else {
diff --git a/src/server/completion.odin b/src/server/completion.odin
index 7dac1b9..cf26b9c 100644
--- a/src/server/completion.odin
+++ b/src/server/completion.odin
@@ -12,6 +12,8 @@ import "core:strconv"
import "core:path/filepath"
import "core:sort"
import "core:slice"
+import "core:os"
+
import "shared:common"
import "shared:index"
@@ -23,9 +25,10 @@ Completion_Type :: enum {
Identifier,
Comp_Lit,
Directive,
+ Package,
}
-get_completion_list :: proc(document: ^Document, position: common.Position) -> (CompletionList, bool) {
+get_completion_list :: proc(document: ^Document, position: common.Position, completion_context: CompletionContext) -> (CompletionList, bool) {
list: CompletionList;
@@ -35,7 +38,11 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> (
return list, true;
}
- ast_context := make_ast_context(document.ast, document.imports, document.package_name);
+ if position_context.import_stmt == nil && strings.contains_any(completion_context.triggerCharacter, "/:\"") {
+ return list, true;
+ }
+
+ ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri);
get_globals(document.ast, &ast_context);
@@ -64,10 +71,17 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> (
completion_type = .Implicit;
}
+ if position_context.import_stmt != nil {
+ completion_type = .Package;
+ }
+
if position_context.switch_type_stmt != nil && position_context.case_clause != nil {
if assign, ok := position_context.switch_type_stmt.tag.derived.(ast.Assign_Stmt); ok && assign.rhs != nil && len(assign.rhs) == 1 {
+ ast_context.use_globals = true;
+ ast_context.use_locals = true;
+
if symbol, ok := resolve_type_expression(&ast_context, assign.rhs[0]); ok {
if union_value, ok := symbol.value.(index.SymbolUnionValue); ok {
@@ -87,9 +101,11 @@ get_completion_list :: proc(document: ^Document, position: common.Position) -> (
case .Selector:
get_selector_completion(&ast_context, &position_context, &list);
case .Switch_Type:
- get_type_switch_Completion(&ast_context, &position_context, &list);
+ get_type_switch_completion(&ast_context, &position_context, &list);
case .Directive:
get_directive_completion(&ast_context, &position_context, &list);
+ case .Package:
+ get_package_completion(&ast_context, &position_context, &list);
}
return list, true;
@@ -203,7 +219,9 @@ get_comp_lit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc
#partial switch v in comp_symbol.value {
case index.SymbolStructValue:
for name, i in v.names {
- //ERROR no completion on name and hover
+
+ ast_context.current_package = comp_symbol.pkg;
+
if resolved, ok := resolve_type_expression(ast_context, v.types[i]); ok {
if field_exists_in_comp_lit(position_context.comp_lit, name) {
@@ -724,12 +742,8 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc
if proc_value, ok := symbol.value.(index.SymbolProcedureValue); ok {
- log.error("procedure symbol");
-
if enum_value, ok := unwrap_enum(ast_context, proc_value.arg_types[parameter_index].type); ok {
- log.error("unwrap");
-
for name in enum_value.names {
item := CompletionItem {
label = name,
@@ -800,9 +814,10 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D
append(&pkgs, ast_context.document_package);
if results, ok := index.fuzzy_search(lookup, pkgs[:]); ok {
-
for r in results {
- append(&combined, CombinedResult {score = r.score, symbol = r.symbol});
+ if r.symbol.uri != ast_context.uri {
+ append(&combined, CombinedResult {score = r.score, symbol = r.symbol});
+ }
}
}
@@ -938,9 +953,92 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D
}
get_package_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) {
+
+ items := make([dynamic]CompletionItem, context.temp_allocator);
+
+ list.isIncomplete = false;
+
+ fullpath_length := len(position_context.import_stmt.fullpath);
+
+ if fullpath_length <= 1 {
+ return;
+ }
+
+ without_quotes := position_context.import_stmt.fullpath[1:fullpath_length-1];
+ absolute_path := without_quotes;
+ colon_index := strings.index(without_quotes, ":");
+
+ if colon_index >= 0 {
+ c := without_quotes[0:colon_index];
+
+ if colon_index+1 < len(without_quotes) {
+ absolute_path = filepath.join(elems = {common.config.collections[c], filepath.dir(without_quotes[colon_index+1:], context.temp_allocator)}, allocator = context.temp_allocator);
+ } else {
+ absolute_path = common.config.collections[c];
+ }
+ } else {
+ import_file_dir := filepath.dir(position_context.import_stmt.pos.file, context.temp_allocator);
+ import_dir := filepath.dir(without_quotes, context.temp_allocator);
+ absolute_path = filepath.join(elems = {import_file_dir, import_dir}, allocator = context.temp_allocator);
+ }
+
+ if !strings.contains(position_context.import_stmt.fullpath, "/") && !strings.contains(position_context.import_stmt.fullpath, ":") {
+
+ for key, _ in common.config.collections {
+
+ item := CompletionItem {
+ detail = "collection",
+ label = key,
+ kind = .Module,
+ };
+
+ append(&items, item);
+ }
+
+ }
+
+ for pkg in search_for_packages(absolute_path) {
+
+ item := CompletionItem {
+ detail = pkg,
+ label = filepath.base(pkg),
+ kind = .Folder,
+ };
+
+ if item.label[0] == '.' {
+ continue;
+ }
+
+ append(&items, item);
+ }
+
+ list.items = items[:];
}
-get_type_switch_Completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) {
+search_for_packages :: proc(fullpath: string) -> [] string {
+
+ packages := make([dynamic]string, context.temp_allocator);
+
+ fh, err := os.open(fullpath);
+
+ if err != 0 {
+ return {};
+ }
+
+ if files, err := os.read_dir(fh, 0, context.temp_allocator); err == 0 {
+
+ for file in files {
+ if file.is_dir {
+ append(&packages, file.fullpath);
+ }
+ }
+
+ }
+
+ return packages[:];
+}
+
+get_type_switch_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) {
items := make([dynamic]CompletionItem, context.temp_allocator);
list.isIncomplete = false;
@@ -963,6 +1061,9 @@ get_type_switch_Completion :: proc(ast_context: ^AstContext, position_context: ^
}
}
+ ast_context.use_locals = true;
+ ast_context.use_globals = true;
+
if assign, ok := position_context.switch_type_stmt.tag.derived.(ast.Assign_Stmt); ok && assign.rhs != nil && len(assign.rhs) == 1 {
if union_value, ok := unwrap_union(ast_context, assign.rhs[0]); ok {
diff --git a/src/server/hover.odin b/src/server/hover.odin
index 109fffe..e22e539 100644
--- a/src/server/hover.odin
+++ b/src/server/hover.odin
@@ -24,7 +24,7 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
},
};
- ast_context := make_ast_context(document.ast, document.imports, document.package_name);
+ ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri);
position_context, ok := get_document_position_context(document, position, .Hover);
@@ -114,9 +114,6 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
return hover, true;
}
}
- } else 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 {
diff --git a/src/server/requests.odin b/src/server/requests.odin
index 91cd073..0b4f7a1 100644
--- a/src/server/requests.odin
+++ b/src/server/requests.odin
@@ -208,7 +208,7 @@ handle_request :: proc (request: json.Value, config: ^common.Config, writer: ^Wr
log.error("No root object");
return false;
}
-
+
id: RequestId;
id_value: json.Value;
id_value, ok = root["id"];
@@ -399,7 +399,7 @@ request_initialize :: proc (task: ^common.Task) {
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)
@@ -432,6 +432,10 @@ request_initialize :: proc (task: ^common.Task) {
config.collections[strings.clone(p.name)] = path.join(elems = {uri.path, forward_path}, allocator = context.allocator);
}
}
+
+ if ok := "" in config.collections; !ok {
+ config.collections[""] = uri.path;
+ }
} else {
log.errorf("Failed to unmarshal %v", ols_config_path);
}
@@ -461,8 +465,9 @@ request_initialize :: proc (task: ^common.Task) {
config.signature_offset_support = initialize_params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport;
- completionTriggerCharacters := []string {".", ">", "#"};
- signatureTriggerCharacters := []string {"("};
+ completionTriggerCharacters := []string {".", ">", "#", "\"", "/", ":"};
+ signatureTriggerCharacters := []string {"("};
+ signatureRetriggerCharacters := []string {","};
token_type := type_info_of(SemanticTokenTypes).variant.(runtime.Type_Info_Named).base.variant.(runtime.Type_Info_Enum);
token_modifier := type_info_of(SemanticTokenModifiers).variant.(runtime.Type_Info_Named).base.variant.(runtime.Type_Info_Enum);
@@ -494,7 +499,8 @@ request_initialize :: proc (task: ^common.Task) {
triggerCharacters = completionTriggerCharacters,
},
signatureHelpProvider = SignatureHelpOptions {
- triggerCharacters = signatureTriggerCharacters
+ triggerCharacters = signatureTriggerCharacters,
+ retriggerCharacters = signatureRetriggerCharacters,
},
semanticTokensProvider = SemanticTokensOptions {
range = false,
@@ -526,13 +532,13 @@ request_initialize :: proc (task: ^common.Task) {
*/
if core, ok := config.collections["core"]; ok {
- when ODIN_OS == "windows" {
+ when ODIN_OS == "windows" {
append(&index.indexer.built_in_packages, path.join(strings.to_lower(core, context.temp_allocator), "runtime"));
} else {
append(&index.indexer.built_in_packages, path.join(core, "runtime"));
}
}
-
+
log.info("Finished indexing");
}
@@ -624,7 +630,7 @@ request_completion :: proc (task: ^common.Task) {
}
list: CompletionList;
- list, ok = get_completion_list(document, completition_params.position);
+ list, ok = get_completion_list(document, completition_params.position, completition_params.context_);
if !ok {
handle_error(.InternalError, id, writer);
@@ -878,7 +884,7 @@ notification_did_save :: proc (task: ^common.Task) {
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);
}
diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin
index b60d7ef..4feced5 100644
--- a/src/server/semantic_tokens.odin
+++ b/src/server/semantic_tokens.odin
@@ -96,11 +96,15 @@ get_tokens :: proc(builder: SemanticTokenBuilder) -> 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);
+ ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, context.temp_allocator);
builder := make_token_builder();
get_globals(document.ast, &ast_context);
+ if document.ast.pkg_decl != nil {
+ write_semantic_token(&builder, document.ast.pkg_token, document.ast.src, .Keyword, .None);
+ }
+
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);
@@ -178,7 +182,7 @@ resolve_and_write_ident :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder,
return;
}
-write_semantic_tokens :: proc{
+write_semantic_tokens :: proc {
write_semantic_tokens_node,
write_semantic_tokens_dynamic_array,
write_semantic_tokens_array,
@@ -204,7 +208,6 @@ write_semantic_tokens_stmt :: proc(node: ^ast.Stmt, builder: ^SemanticTokenBuild
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);
}
@@ -354,8 +357,19 @@ write_semantic_tokens_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuild
write_semantic_token_pos(builder, n.tok_pos, "map", ast_context.file.src, .Keyword, .None);
write_semantic_tokens(n.key, builder, ast_context);
write_semantic_tokens(n.value, builder, ast_context);
+ case Defer_Stmt:
+ write_semantic_token_pos(builder, n.pos, "defer", ast_context.file.src, .Keyword, .None);
+ write_semantic_tokens(n.stmt, builder, ast_context);
+ case Import_Decl:
+ write_semantic_token(builder, n.import_tok, ast_context.file.src, .Keyword, .None);
+
+ if n.name.text != "" {
+ write_semantic_token(builder, n.name, ast_context.file.src, .Namespace, .None);
+ }
+
+ write_semantic_token(builder, n.relpath, ast_context.file.src, .String, .None);
case:
- log.infof("unhandled write node %v", n);
+ log.warnf("unhandled write node %v", n);
}
}
@@ -527,13 +541,18 @@ write_semantic_selector :: proc(selector: ^ast.Selector_Expr, builder: ^Semantic
using ast;
- if ident, ok := selector.expr.derived.(Ident); ok {
+ if _, ok := selector.expr.derived.(Selector_Expr); !ok {
get_locals_at(builder.current_function, selector.expr, ast_context);
- builder.selector_member, builder.selector_package, ast_context.current_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;
+ if symbol, ok := resolve_type_expression(ast_context, selector.expr); ok {
+
+ #partial switch v in symbol.value {
+ case index.SymbolStructValue:
+ builder.selector_member = true;
+ }
+
}
+
} else {
write_semantic_tokens(selector.expr, builder, ast_context);
}
diff --git a/src/server/types.odin b/src/server/types.odin
index 0efbd39..e2740f7 100644
--- a/src/server/types.odin
+++ b/src/server/types.odin
@@ -96,6 +96,10 @@ CompletionOptions :: struct {
triggerCharacters: []string,
}
+CompletionContext :: struct {
+ triggerCharacter: string,
+}
+
SaveOptions :: struct {
includeText: bool,
}
@@ -222,6 +226,7 @@ SignatureHelpParams :: struct {
CompletionParams :: struct {
textDocument: TextDocumentIdentifier,
position: common.Position,
+ context_: CompletionContext,
}
CompletionItemKind :: enum {
diff --git a/src/server/unmarshal.odin b/src/server/unmarshal.odin
index ba37497..1776b07 100644
--- a/src/server/unmarshal.odin
+++ b/src/server/unmarshal.odin
@@ -32,9 +32,19 @@ unmarshal :: proc(json_value: json.Value, v: any, allocator: mem.Allocator) -> j
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;
+
+ //TEMP most likely have to rewrite the entire unmarshal using tags instead, because i sometimes have to support names like 'context', which can't be written like that
+ if field[len(field)-1] == '_' {
+ if ret := unmarshal(j[field[:len(field)-1]], a, allocator); ret != .None {
+ return ret;
+ }
+ } else {
+ if ret := unmarshal(j[field], a, allocator); ret != .None {
+ return ret;
+ }
}
+
+
}
case Type_Info_Union:
diff --git a/src/testing/testing.odin b/src/testing/testing.odin
new file mode 100644
index 0000000..7b47f90
--- /dev/null
+++ b/src/testing/testing.odin
@@ -0,0 +1,25 @@
+package ols_testing
+
+import "core:testing"
+
+Package_Source :: struct {
+ pkg_name: string,
+ source: string,
+}
+
+Source :: struct {
+ main: string,
+ source_packages: Package_Source,
+}
+
+expect_signature :: proc(t: ^testing.T, src: Source, expect_arg: []string) {
+
+}
+
+expect_completion :: proc(t: ^testing.T, src: Source, completions: []string) {
+
+}
+
+expect_hover :: proc(t: ^testing.T, src: Source, hover_info: string) {
+
+} \ No newline at end of file