aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Gavin <danielgavin5@hotmail.com>2021-12-31 14:51:12 +0100
committerDaniel Gavin <danielgavin5@hotmail.com>2021-12-31 14:51:12 +0100
commitd28b0ac8400136d0ccc6942c907e6fb3f034488f (patch)
tree2bfe679da112da226db2cd95c9c3d145bd1ca0d5 /src
parentbb1379a911f43134b8dc5ed9ec2eebb889b800fb (diff)
parente587db0c06c0972a67867282eb9f16448101f34b (diff)
Merge branch 'master' into refractor-analysis
Diffstat (limited to 'src')
-rw-r--r--src/analysis/analysis.odin303
-rw-r--r--src/common/ast.odin7
-rw-r--r--src/common/config.odin1
-rw-r--r--src/index/collector.odin32
-rw-r--r--src/index/symbol.odin21
-rw-r--r--src/odin/printer/visit.odin10
-rw-r--r--src/server/check.odin280
-rw-r--r--src/server/completion.odin174
-rw-r--r--src/server/hover.odin12
-rw-r--r--src/server/requests.odin7
-rw-r--r--src/server/signature.odin12
-rw-r--r--src/server/types.odin1
-rw-r--r--src/testing/testing.odin35
13 files changed, 605 insertions, 290 deletions
diff --git a/src/analysis/analysis.odin b/src/analysis/analysis.odin
index c16bdf9..1330796 100644
--- a/src/analysis/analysis.odin
+++ b/src/analysis/analysis.odin
@@ -44,6 +44,7 @@ DocumentPositionContext :: struct {
returns: ^ast.Return_Stmt, //used for completion
comp_lit: ^ast.Comp_Lit, //used for completion
parent_comp_lit: ^ast.Comp_Lit, //used for completion
+ field_value: ^ast.Field_Value,
implicit: bool, //used for completion
arrow: bool,
binary: ^ast.Binary_Expr, //used for completion
@@ -292,10 +293,18 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s
}
}
-resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, current_symbol: index.Symbol, current_comp_lit: ^ast.Comp_Lit) -> (index.Symbol, bool) {
+resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, current_symbol: index.Symbol, current_comp_lit: ^ast.Comp_Lit) -> (index.Symbol, ^ast.Comp_Lit, bool) {
if position_context.comp_lit == current_comp_lit {
- return current_symbol, true;
+ return current_symbol, current_comp_lit, true;
+ }
+
+ element_index := 0;
+
+ for elem, i in current_comp_lit.elems {
+ if position_in_node(elem, position_context.position) {
+ element_index = i;
+ }
}
for elem in current_comp_lit.elems {
@@ -303,28 +312,42 @@ resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^D
if !position_in_node(elem, position_context.position) {
continue;
}
-
- if field_value, ok := elem.derived.(ast.Field_Value); ok {
-
+
+ if field_value, ok := elem.derived.(ast.Field_Value); ok { //named
if comp_lit, ok := field_value.value.derived.(ast.Comp_Lit); ok {
-
if s, ok := current_symbol.value.(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 {
+ //Stop at bitset, because we don't want to enter a comp_lit of a bitset
+ if _, ok := symbol.value.(index.SymbolBitSetValue); ok {
+ return current_symbol, current_comp_lit, true;
+ }
return resolve_type_comp_literal(ast_context, position_context, symbol, cast(^ast.Comp_Lit)field_value.value);
}
}
}
}
}
+ } else { //indexed
+ if s, ok := current_symbol.value.(index.SymbolStructValue); ok {
+
+ if len(s.types) <= element_index {
+ return {}, {}, false;
+ }
+
+ if symbol, ok := resolve_type_expression(ast_context, s.types[element_index]); ok {
+ //Stop at bitset, because we don't want to enter a comp_lit of a bitset
+ if _, ok := symbol.value.(index.SymbolBitSetValue); ok {
+ return current_symbol, current_comp_lit, true;
+ }
+ return resolve_type_comp_literal(ast_context, position_context, symbol, cast(^ast.Comp_Lit)field_value.value);
+ }
+ }
}
}
- return current_symbol, true;
+ return current_symbol, current_comp_lit, true;
}
resolve_generic_function :: proc {
@@ -411,7 +434,6 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast
argument_types := make([dynamic]^ast.Field, context.temp_allocator);
for result in results {
-
if result.type == nil {
continue;
}
@@ -430,7 +452,6 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast
}
for param in params {
-
if len(param.names) == 0 {
continue;
}
@@ -515,12 +536,12 @@ is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: index.Symbol, flags
return false;
}
- if a.is_distinct != b.is_distinct {
+ if .Distinct in a.flags != .Distinct in b.flags {
return false;
}
- if a.is_distinct == b.is_distinct &&
- a.is_distinct == true &&
+ if .Distinct in a.flags == .Distinct in b.flags &&
+ .Distinct in a.flags &&
a.name == b.name &&
a.pkg == b.pkg {
return true;
@@ -806,6 +827,14 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i
using ast;
switch v in &node.derived {
+ case Union_Type:
+ return make_symbol_union_from_ast(ast_context, v, ast_context.field_name, true), true;
+ case Enum_Type:
+ return make_symbol_enum_from_ast(ast_context, v, ast_context.field_name, true), true;
+ case Struct_Type:
+ return make_symbol_struct_from_ast(ast_context, v, ast_context.field_name, true), true;
+ case Bit_Set_Type:
+ return make_symbol_bitset_from_ast(ast_context, v, ast_context.field_name, true), true;
case Array_Type:
return make_symbol_array_from_ast(ast_context, v), true;
case Dynamic_Array_Type:
@@ -823,7 +852,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i
case Basic_Lit:
return resolve_basic_lit(ast_context, v);
case Type_Cast:
- return resolve_type_expression(ast_context, v.type);
+ return resolve_type_expression(ast_context, v.type);
case Auto_Cast:
return resolve_type_expression(ast_context, v.expr);
case Comp_Lit:
@@ -855,7 +884,20 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i
ident.name = v.tok.text;
return resolve_type_identifier(ast_context, ident^);
case Type_Assertion:
- return resolve_type_expression(ast_context, v.type);
+ if unary, ok := v.type.derived.(ast.Unary_Expr); ok {
+ if unary.op.kind == .Question {
+ if symbol, ok := resolve_type_expression(ast_context, v.expr); ok {
+ if union_value, ok := symbol.value.(index.SymbolUnionValue); ok {
+ if len(union_value.types) != 1 {
+ return {}, false;
+ }
+ return resolve_type_expression(ast_context, union_value.types[0]);
+ }
+ }
+ }
+ } else {
+ return resolve_type_expression(ast_context, v.type);
+ }
case Proc_Lit:
if v.type.results != nil {
if len(v.type.results.list) == 1 {
@@ -1090,7 +1132,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i
if is_distinct {
return_symbol.name = node.name;
- return_symbol.is_distinct = is_distinct;
+ return_symbol.flags |= {.Distinct};
}
return return_symbol, ok;
@@ -1148,7 +1190,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i
if is_distinct {
return_symbol.name = node.name;
- return_symbol.is_distinct = is_distinct;
+ return_symbol.flags |= {.Distinct};
}
return_symbol.doc = common.get_doc(global.docs, context.temp_allocator);
@@ -1335,8 +1377,8 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok
if symbol.type == .Unresolved {
resolve_unresolved_symbol(ast_context, &symbol);
}
-
- #partial switch v in symbol.value {
+
+ #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;
@@ -1353,14 +1395,33 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok
} else {
return symbol, true;
}
+ case index.SymbolUnionValue:
+ if v.poly != nil {
+ //Todo(daniel): Maybe change the function to return a new symbol instead of referencing it.
+ //resolving the poly union means changing the type, so we do a copy of it.
+ types := make([dynamic]^ast.Expr, context.temp_allocator);
+ append_elems(&types, ..v.types);
+ v.types = types[:];
+ resolve_poly_union(ast_context, v.poly, &symbol);
+ }
+ return symbol, ok;
case index.SymbolStructValue:
+ if v.poly != nil {
+ //Todo(daniel): Maybe change the function to return a new symbol instead of referencing it.
+ //resolving the struct union means changing the type, so we do a copy of it.
+ types := make([dynamic]^ast.Expr, context.temp_allocator);
+ append_elems(&types, ..v.types);
+ v.types = types[:];
+ resolve_poly_struct(ast_context, v.poly, &symbol);
+ }
+
//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;
+ return symbol, true;
}
case index.SymbolGenericValue:
ret, ok := resolve_type_expression(ast_context, v.expr);
@@ -1556,7 +1617,9 @@ make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v
}
if expr, ok := ast_context.globals[name]; ok {
- symbol.is_deprecated = expr.deprecated;
+ if expr.deprecated {
+ symbol.flags |= {.Distinct};
+ }
}
symbol.value = index.SymbolProcedureValue {
@@ -1635,14 +1698,19 @@ make_symbol_basic_type_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node,
return symbol;
}
-make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, ident: string) -> index.Symbol {
+make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, ident: string, inlined := false) -> index.Symbol {
symbol := index.Symbol {
range = common.get_token_range(v, ast_context.file.src),
- type = .Enum,
+ type = .Union,
pkg = get_package_from_node(v.node),
};
+ if inlined {
+ symbol.flags |= {.Anonymous};
+ symbol.name = "union";
+ }
+
names := make([dynamic]string, context.temp_allocator);
for variant in v.variants {
@@ -1658,22 +1726,30 @@ make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type,
}
symbol.value = index.SymbolUnionValue {
- names = names[:],
types = v.variants,
union_name = ident,
};
+ if v.poly_params != nil {
+ resolve_poly_union(ast_context, v.poly_params, &symbol);
+ }
+
return symbol;
}
-make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, ident: string) -> index.Symbol {
-
+make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, ident: string, inlined := false) -> index.Symbol {
symbol := index.Symbol {
range = common.get_token_range(v, ast_context.file.src),
type = .Enum,
pkg = get_package_from_node(v.node),
};
+ if inlined {
+ symbol.flags |= {.Anonymous};
+ symbol.name = "enum";
+ }
+
+
names := make([dynamic]string, context.temp_allocator);
for n in v.fields {
@@ -1696,7 +1772,7 @@ make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, id
return symbol;
}
-make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Type, ident: string) -> index.Symbol {
+make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Type, ident: string, inlined := false) -> index.Symbol {
symbol := index.Symbol {
range = common.get_token_range(v, ast_context.file.src),
@@ -1704,6 +1780,11 @@ make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Typ
pkg = get_package_from_node(v.node),
};
+ if inlined {
+ symbol.flags |= {.Anonymous};
+ symbol.name = "bitset";
+ }
+
symbol.value = index.SymbolBitSetValue {
expr = v.elem,
bitset_name = ident,
@@ -1712,7 +1793,7 @@ make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Typ
return symbol;
}
-make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type, ident: string) -> index.Symbol {
+make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type, ident: string, inlined := false) -> index.Symbol {
symbol := index.Symbol {
range = common.get_token_range(v, ast_context.file.src),
@@ -1720,12 +1801,16 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type
pkg = get_package_from_node(v.node),
};
+ if inlined {
+ symbol.flags |= {.Anonymous};
+ symbol.name = "struct";
+ }
+
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 {
-
for n in field.names {
if identifier, ok := n.derived.(ast.Ident); ok {
append(&names, identifier.name);
@@ -1746,7 +1831,7 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type
};
if v.poly_params != nil {
- resolve_poly_struct(ast_context, v, &symbol);
+ resolve_poly_struct(ast_context, v.poly_params, &symbol);
}
//TODO change the expand to not double copy the array, but just pass the dynamic arrays
@@ -1757,13 +1842,13 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type
return symbol;
}
-resolve_poly_struct :: proc(ast_context: ^AstContext, v: ast.Struct_Type, symbol: ^index.Symbol) {
+resolve_poly_union :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_List, symbol: ^index.Symbol) {
if ast_context.call == nil {
return;
}
- symbol_value := &symbol.value.(index.SymbolStructValue);
+ symbol_value := &symbol.value.(index.SymbolUnionValue);
if symbol_value == nil {
return;
@@ -1773,10 +1858,8 @@ resolve_poly_struct :: proc(ast_context: ^AstContext, v: ast.Struct_Type, symbol
poly_map := make(map[string]^ast.Expr, 0, context.temp_allocator);
- for param in v.poly_params.list {
-
+ for param in poly_params.list {
for name in param.names {
-
if len(ast_context.call.args) <= i {
break;
}
@@ -1784,37 +1867,96 @@ resolve_poly_struct :: proc(ast_context: ^AstContext, v: ast.Struct_Type, symbol
if param.type == nil {
continue;
}
-
+
if poly, ok := param.type.derived.(ast.Typeid_Type); ok {
-
if ident, ok := name.derived.(ast.Ident); ok {
poly_map[ident.name] = ast_context.call.args[i];
+ } else if poly, ok := name.derived.(ast.Poly_Type); ok {
+ if poly.type != nil {
+ poly_map[poly.type.name] = ast_context.call.args[i];
+ }
}
}
i += 1;
}
}
-
+
for type, i in symbol_value.types {
-
if ident, ok := type.derived.(ast.Ident); ok {
-
if expr, ok := poly_map[ident.name]; ok {
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 {
+ symbol_value.types[i] = expr;
+ }
+ }
+ }
+ }
+ }
+}
+resolve_poly_struct :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_List, symbol: ^index.Symbol) {
+
+ if ast_context.call == nil {
+ return;
+ }
+
+ symbol_value := &symbol.value.(index.SymbolStructValue);
+
+ if symbol_value == nil {
+ return;
+ }
+
+ i := 0;
+
+ poly_map := make(map[string]^ast.Expr, 0, context.temp_allocator);
+
+ for param in 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];
+ } else if poly, ok := name.derived.(ast.Poly_Type); ok {
+ if poly.type != nil {
+ poly_map[poly.type.name] = ast_context.call.args[i];
+ }
+ }
+ }
+
+ i += 1;
+ }
+ }
+
+ for type, i in symbol_value.types {
+ if ident, ok := type.derived.(ast.Ident); ok {
+ if expr, ok := poly_map[ident.name]; ok {
+ 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;
+ symbol_value.types[i] = expr;
}
}
}
@@ -1841,7 +1983,7 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A
ast_context.use_locals = true;
ast_context.use_globals = true;
- switch v in value.derived {
+ switch v in &value.derived {
case Call_Expr:
ast_context.call = cast(^ast.Call_Expr)value;
@@ -1874,8 +2016,16 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A
}
case Type_Assertion:
if v.type != nil {
- append(results, v.type);
- append(results, make_bool_ast());
+ //This is the unique .? that can only be used with maybe
+ if unary, ok := v.type.derived.(ast.Unary_Expr); ok && unary.op.kind == .Question {
+ append(results, cast(^ast.Expr)&v.node);
+ } else {
+ append(results, v.type);
+ }
+
+ b := make_bool_ast();
+ b.pos.file = v.type.pos.file;
+ append(results, b);
}
case:
//log.debugf("default node get_generic_assignment %v", v);
@@ -1884,7 +2034,6 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A
}
get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_context: ^AstContext) {
-
using ast;
if len(value_decl.names) <= 0 {
@@ -1892,9 +2041,11 @@ 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.end.offset, str);
+ for name, i in value_decl.names {
+ str := common.get_ast_node_string(value_decl.names[i], file.src);
+ ast_context.variables[str] = value_decl.is_mutable;
+ store_local(ast_context, value_decl.type, value_decl.end.offset, str);
+ }
return;
}
@@ -1904,13 +2055,16 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co
get_generic_assignment(file, value, ast_context, &results);
}
+ if len(results) == 0 {
+ return;
+ }
+
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], value_decl.end.offset, str);
- ast_context.variables[str] = value_decl.is_mutable;
- }
+ result_i := min(len(results)-1, i);
+ str := common.get_ast_node_string(name, file.src);
+ ast_context.in_package[str] = get_package_from_node(results[result_i]);
+ store_local(ast_context, results[result_i], value_decl.end.offset, str);
+ ast_context.variables[str] = value_decl.is_mutable;
}
}
@@ -1946,9 +2100,7 @@ get_locals_stmt :: proc(file: ast.File, stmt: ^ast.Stmt, ast_context: ^AstContex
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);
- }
+ get_locals_block_stmt(file, v, ast_context, document_position);
case Proc_Lit:
get_locals_stmt(file, v.body, ast_context, document_position);
case Assign_Stmt:
@@ -1969,6 +2121,17 @@ get_locals_stmt :: proc(file: ast.File, stmt: ^ast.Stmt, ast_context: ^AstContex
}
}
+get_locals_block_stmt :: proc(file: ast.File, block: ast.Block_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) {
+
+ if !(block.pos.offset <= document_position.position && document_position.position <= block.end.offset) {
+ return;
+ }
+
+ for stmt in block.stmts {
+ get_locals_stmt(file, stmt, ast_context, document_position);
+ }
+}
+
get_locals_using_stmt :: proc(stmt: ast.Using_Stmt, ast_context: ^AstContext) {
for u in stmt.list {
@@ -2265,11 +2428,9 @@ resolve_entire_procedure :: proc(procedure: ^ast.Proc_Type, symbols: ^[]^index.S
}
concatenate_symbols_information :: proc(ast_context: ^AstContext, symbol: index.Symbol, is_completion: bool) -> 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 {
@@ -2337,6 +2498,10 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: index.
return symbol.signature;
}
+ if .Distinct in symbol.flags {
+ return symbol.name;
+ }
+
is_variable := resolve_ident_is_variable(ast_context, ident);
#partial switch v in symbol.value {
@@ -2496,6 +2661,17 @@ get_call_commas :: proc(position_context: ^DocumentPositionContext, document: ^c
position_context.call_commas = commas[:];
}
+type_to_string :: proc(ast_context: ^AstContext, expr: ^ast.Expr) -> string {
+
+ if symbol, ok := resolve_type_expression(ast_context, expr); ok {
+ if .Anonymous in symbol.flags {
+ return symbol.name;
+ }
+ }
+
+ return common.node_to_string(expr);
+}
+
/*
Figure out what exactly is at the given position and whether it is in a function, struct, etc.
*/
@@ -2953,6 +3129,7 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP
get_document_position(n.low, position_context);
get_document_position(n.high, position_context);
case Field_Value:
+ position_context.field_value = cast(^Field_Value)node;
get_document_position(n.field, position_context);
get_document_position(n.value, position_context);
case Ternary_If_Expr:
diff --git a/src/common/ast.odin b/src/common/ast.odin
index 62ae7e9..ff6f7e2 100644
--- a/src/common/ast.odin
+++ b/src/common/ast.odin
@@ -771,7 +771,12 @@ build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder) {
case Call_Expr:
build_string(n.expr, builder);
strings.write_string(builder, "(");
- build_string(n.args, builder);
+ for arg, i in n.args {
+ build_string(arg, builder);
+ if len(n.args) - 1 != i {
+ strings.write_string(builder, ", ");
+ }
+ }
strings.write_string(builder, ")");
case Selector_Expr:
build_string(n.expr, builder);
diff --git a/src/common/config.odin b/src/common/config.odin
index e80d752..e3da120 100644
--- a/src/common/config.odin
+++ b/src/common/config.odin
@@ -18,6 +18,7 @@ Config :: struct {
thread_count: int,
file_log: bool,
formatter: Format_Config,
+ odin_command: string,
}
Format_Config :: struct {
diff --git a/src/index/collector.odin b/src/index/collector.odin
index 74c47e1..077f6ee 100644
--- a/src/index/collector.odin
+++ b/src/index/collector.odin
@@ -119,6 +119,7 @@ collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.St
types = types[:],
usings = usings,
struct_name = get_index_unique_string(collection, ident),
+ poly = cast(^ast.Field_List)clone_type(struct_type.poly_params, collection.allocator, &collection.unique_strings),
};
return value;
@@ -151,30 +152,18 @@ collect_enum_fields :: proc(collection: ^SymbolCollection, fields: []^ast.Expr,
collect_union_fields :: proc(collection: ^SymbolCollection, union_type: ast.Union_Type, package_map: map[string]string, ident: string) -> SymbolUnionValue {
- names := make([dynamic]string, 0, collection.allocator);
types := make([dynamic]^ast.Expr, 0, collection.allocator);
for variant in union_type.variants {
-
- if ident, ok := variant.derived.(ast.Ident); ok {
- append(&names, get_index_unique_string(collection, ident.name));
- } else if selector, ok := variant.derived.(ast.Selector_Expr); ok {
-
- if ident, ok := selector.field.derived.(ast.Ident); ok {
- append(&names, get_index_unique_string(collection, ident.name));
- }
- }
-
cloned := clone_type(variant, collection.allocator, &collection.unique_strings);
replace_package_alias(cloned, package_map, collection);
-
append(&types, cloned);
}
value := SymbolUnionValue {
- names = names[:],
types = types[:],
union_name = get_index_unique_string(collection, ident),
+ poly = cast(^ast.Field_List)clone_type(union_type.poly_params, collection.allocator, &collection.unique_strings),
};
return value;
@@ -320,7 +309,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
symbol.signature = "enum";
case ast.Union_Type:
token = v;
- token_type = .Enum;
+ token_type = .Union;
symbol.value = collect_union_fields(collection, v, package_map, name);
symbol.signature = "union";
case ast.Bit_Set_Type:
@@ -371,9 +360,18 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
symbol.pkg = get_index_unique_string(collection, directory);
symbol.type = token_type;
symbol.doc = common.get_doc(expr.docs, collection.allocator);
- symbol.is_deprecated = expr.deprecated;
- symbol.is_private_file = expr.file_private;
- symbol.is_private_package = expr.package_private;
+
+ if expr.deprecated {
+ symbol.flags |= {.Deprecated};
+ }
+
+ if expr.file_private {
+ symbol.flags |= {.PrivateFile};
+ }
+
+ if expr.package_private {
+ symbol.flags |= {.PrivatePackage};
+ }
when ODIN_OS == "windows" {
symbol.uri = get_index_unique_string(collection, strings.to_lower(uri, context.temp_allocator));
diff --git a/src/index/symbol.odin b/src/index/symbol.odin
index 8e13786..5001054 100644
--- a/src/index/symbol.odin
+++ b/src/index/symbol.odin
@@ -15,7 +15,7 @@ SymbolStructValue :: struct {
names: []string,
types: []^ast.Expr,
usings: map[string]bool,
- generic: bool,
+ poly: ^ast.Field_List,
}
SymbolPackageValue :: struct {}
@@ -42,8 +42,8 @@ SymbolEnumValue :: struct {
SymbolUnionValue :: struct {
union_name: string,
- names: []string,
types: []^ast.Expr,
+ poly: ^ast.Field_List,
}
SymbolDynamicArrayValue :: struct {
@@ -102,6 +102,16 @@ SymbolValue :: union {
SymbolUntypedValue,
}
+SymbolFlag :: enum {
+ Distinct,
+ Deprecated,
+ PrivateFile,
+ PrivatePackage,
+ Anonymous,
+}
+
+SymbolFlags :: bit_set[SymbolFlag]
+
Symbol :: struct {
range: common.Range,
uri: string,
@@ -114,10 +124,7 @@ Symbol :: struct {
value: SymbolValue,
references: []common.Location,
pointers: int,
- is_distinct: bool,
- is_deprecated: bool,
- is_private_file: bool,
- is_private_package: bool,
+ flags: SymbolFlags,
}
SymbolType :: enum {
@@ -130,6 +137,7 @@ SymbolType :: enum {
EnumMember = 20,
Constant = 21,
Struct = 22,
+ Union = 9000,
Unresolved = 9999,
}
@@ -163,7 +171,6 @@ free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) {
case SymbolEnumValue:
delete(v.names, allocator);
case SymbolUnionValue:
- delete(v.names, allocator);
common.free_ast(v.types, allocator);
case SymbolBitSetValue:
common.free_ast(v.expr, allocator);
diff --git a/src/odin/printer/visit.odin b/src/odin/printer/visit.odin
index f20b46c..da36311 100644
--- a/src/odin/printer/visit.odin
+++ b/src/odin/printer/visit.odin
@@ -944,15 +944,12 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type =
document = cons_with_nopl(document, push_where_clauses(p, v.where_clauses))
- if v.variants != nil && (len(v.variants) == 0 || v.pos.line == v.end.line) {
+ if len(v.variants) == 0 {
document = cons_with_nopl(document, text("{"))
- document = cons(document, visit_exprs(p, v.variants, {.Add_Comma}))
document = cons(document, text("}"))
- } else if v.variants != nil {
- document = cons_with_opl(document, visit_begin_brace(p, v.pos, .Generic))
-
+ } else {
+ document = cons_with_opl(document, visit_begin_brace(p, v.pos, .Generic))
set_source_position(p, v.variants[0].pos)
-
document = cons(document, nest(p.indentation_count, cons(newline_position(p, 1, v.variants[0].pos), visit_exprs(p, v.variants, {.Add_Comma, .Trailing, .Enforce_Newline}))))
document = cons(document, visit_end_brace(p, v.end, 1))
}
@@ -966,7 +963,6 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type =
if len(v.fields) == 0 {
document = cons_with_nopl(document, text("{"))
- document = cons(document, visit_enum_exprs(p, v.fields, {.Add_Comma}))
document = cons(document, text("}"))
} else {
document = cons(document, cons(break_with_space(), visit_begin_brace(p, v.pos, .Generic)))
diff --git a/src/server/check.odin b/src/server/check.odin
index 5080c95..574227e 100644
--- a/src/server/check.odin
+++ b/src/server/check.odin
@@ -1,6 +1,5 @@
package server
-/*
import "core:fmt"
import "core:log"
import "core:mem"
@@ -19,175 +18,214 @@ import "core:text/scanner"
import "shared:common"
+when ODIN_OS == "windows" {
-check :: proc(uri: common.Uri, writer: ^Writer) {
+ is_package :: proc(file: string, pkg: string) {
+
+ }
- data := make([]byte, mem.kilobytes(10), context.temp_allocator);
+ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) {
+ data := make([]byte, mem.kilobytes(10), context.temp_allocator);
- buffer: []byte;
- code: u32;
- ok: bool;
+ buffer: []byte;
+ code: u32;
+ ok: bool;
- collection_builder := strings.make_builder(context.temp_allocator);
+ collection_builder := strings.make_builder(context.temp_allocator);
- for k, v in common.config.collections {
- if k == "" || k == "core" {
- continue;
+ for k, v in common.config.collections {
+ if k == "" || k == "core" || k == "vendor" {
+ continue;
+ }
+ strings.write_string(&collection_builder, fmt.aprintf("-collection:%v=%v ", k, v));
}
- strings.write_string(&collection_builder, fmt.aprintf("-collection:%v=%v ", k, v));
- }
- if code, ok, buffer = common.run_executable(fmt.tprintf("odin check %s %s -no-entry-point", path.dir(uri.path, context.temp_allocator), strings.to_string(collection_builder)), &data); !ok {
- log.errorf("Odin check failed with code %v for file %v", code, uri.path);
- return;
- }
-
- errors := make([dynamic]Diagnostic, context.temp_allocator);
+ command: string;
+
+ if config.odin_command != "" {
+ command = config.odin_command;
+
+ } else {
+ command = "odin";
+ }
+
+ if code, ok, buffer = common.run_executable(fmt.tprintf("%v check %s %s -no-entry-point", command, path.dir(uri.path, context.temp_allocator), strings.to_string(collection_builder)), &data); !ok {
+ log.errorf("Odin check failed with code %v for file %v", code, uri.path);
+ return;
+ }
- params := NotificationPublishDiagnosticsParams {
- uri = uri.uri,
- };
+ s: scanner.Scanner;
- s: scanner.Scanner;
+ scanner.init(&s, string(buffer));
- scanner.init(&s, string(buffer));
+ s.whitespace = {'\t', ' '};
- s.whitespace = {'\t', ' '};
+ current: rune;
- current: rune;
+ ErrorSeperator :: struct {
+ message: string,
+ line: int,
+ column: int,
+ uri: string,
+ }
- ErrorSeperator :: struct {
- message: string,
- line: int,
- column: int,
- uri: string,
- }
+ error_seperators := make([dynamic]ErrorSeperator, context.temp_allocator);
- error_seperators := make([dynamic]ErrorSeperator, context.temp_allocator);
+ //find all the signatures string(digit:digit)
+ loop: for scanner.peek(&s) != scanner.EOF {
- //find all the signatures string(digit:digit)
- loop: for scanner.peek(&s) != scanner.EOF {
+ error: ErrorSeperator;
- error: ErrorSeperator;
+ source_pos := s.src_pos;
- source_pos := s.src_pos;
+ if source_pos == 1 {
+ source_pos = 0;
+ }
- if source_pos == 1 {
- source_pos = 0;
- }
+ for scanner.peek(&s) != '(' {
+ n := scanner.scan(&s);
- for scanner.peek(&s) != '(' {
- n := scanner.scan(&s);
+ if n == scanner.EOF {
+ break loop;
+ }
+ }
- if n == scanner.EOF {
- break loop;
- }
- }
+ error.uri = string(buffer[source_pos:s.src_pos-1]);
- error.uri = string(buffer[source_pos:s.src_pos-1]);
+ left_paren := scanner.scan(&s);
- left_paren := scanner.scan(&s);
+ if left_paren != '(' {
+ break loop;
+ }
- if left_paren != '(' {
- break loop;
- }
+ lhs_digit := scanner.scan(&s);
- lhs_digit := scanner.scan(&s);
+ if lhs_digit != scanner.Int {
+ break loop;
+ }
- if lhs_digit != scanner.Int {
- break loop;
- }
+ line, column: int;
+ ok: bool;
- line, column: int;
- ok: bool;
+ line, ok = strconv.parse_int(scanner.token_text(&s));
- line, ok = strconv.parse_int(scanner.token_text(&s));
+ if !ok {
+ break loop;
+ }
- if !ok {
- break loop;
- }
+ seperator := scanner.scan(&s);
- seperator := scanner.scan(&s);
+ if seperator != ':' {
+ break loop;
+ }
- if seperator != ':' {
- break loop;
- }
+ rhs_digit := scanner.scan(&s)
- rhs_digit := scanner.scan(&s)
+ if rhs_digit != scanner.Int {
+ break loop;
+ }
- if rhs_digit != scanner.Int {
- break loop;
- }
+ column, ok = strconv.parse_int(scanner.token_text(&s));
- column, ok = strconv.parse_int(scanner.token_text(&s));
+ if !ok {
+ break loop;
+ }
- if !ok {
- break loop;
- }
+ right_paren := scanner.scan(&s);
- right_paren := scanner.scan(&s);
+ if right_paren != ')' {
+ break loop;
+ }
- if right_paren != ')' {
- break loop;
- }
+ source_pos = s.src_pos;
- source_pos = s.src_pos;
+ for scanner.peek(&s) != '\n' {
+ n := scanner.scan(&s);
- for scanner.peek(&s) != '\n' {
- n := scanner.scan(&s);
+ if n == scanner.EOF {
+ break;
+ }
+ }
- if n == scanner.EOF {
- break;
+ if source_pos == s.src_pos {
+ continue;
}
- }
- if source_pos == s.src_pos {
- continue;
- }
+ error.message = string(buffer[source_pos:s.src_pos-1]);
+ error.column = column;
+ error.line = line;
- error.message = string(buffer[source_pos:s.src_pos-1]);
- error.column = column;
- error.line = line;
+ append(&error_seperators, error);
+ }
- append(&error_seperators, error)
- }
+ errors := make(map[string][dynamic]Diagnostic, 0, context.temp_allocator);
- for error in error_seperators {
+ for error in error_seperators {
- if error.uri != uri.path {
- continue;
- }
+ if error.uri not_in errors {
+ errors[error.uri] = make([dynamic]Diagnostic, context.temp_allocator);
+ }
- append(&errors, Diagnostic {
- code = "checker",
- severity = .Error,
- range = {
- start = {
- character = 0,
- line = error.line - 1,
+ append(&errors[error.uri], Diagnostic {
+ code = "checker",
+ severity = .Error,
+ range = {
+ start = {
+ character = 0,
+ line = error.line - 1,
+ },
+ end = {
+ character = 0,
+ line = error.line,
+ },
},
- end = {
- character = 0,
- line = error.line,
- },
- },
- message = error.message,
- })
-
- }
+ message = error.message,
+ });
+ }
+
+ matches, err := filepath.glob(fmt.tprintf("%v/*.odin", path.dir(uri.path, context.temp_allocator)));
+
+ if err == .None {
+ for match in matches {
+ uri := common.create_uri(match, context.temp_allocator);
+
+ params := NotificationPublishDiagnosticsParams {
+ uri = uri.uri,
+ diagnostics = {},
+ };
+
+ notifaction := Notification {
+ jsonrpc = "2.0",
+ method = "textDocument/publishDiagnostics",
+ params = params,
+ };
+
+ if writer != nil {
+ send_notification(notifaction, writer);
+ }
+ }
+ }
- //fmt.println(errors)
+ for k, v in errors {
+ uri := common.create_uri(k, context.temp_allocator);
- params.diagnostics = errors[:];
+ params := NotificationPublishDiagnosticsParams {
+ uri = uri.uri,
+ diagnostics = v[:],
+ };
- notifaction := Notification {
- jsonrpc = "2.0",
- method = "textDocument/publishDiagnostics",
- params = params,
- };
+ notifaction := Notification {
+ jsonrpc = "2.0",
+ method = "textDocument/publishDiagnostics",
+ params = params,
+ };
- if writer != nil {
- send_notification(notifaction, writer);
+ if writer != nil {
+ send_notification(notifaction, writer);
+ }
+ }
+ }
+} else {
+ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) {
}
-}
-*/ \ No newline at end of file
+} \ No newline at end of file
diff --git a/src/server/completion.odin b/src/server/completion.odin
index 4326c35..38b3c34 100644
--- a/src/server/completion.odin
+++ b/src/server/completion.odin
@@ -180,7 +180,7 @@ get_comp_lit_completion :: proc(ast_context: ^analysis.AstContext, position_cont
if symbol, ok := resolve_type_expression(ast_context, position_context.parent_comp_lit.type); ok {
- if comp_symbol, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok {
+ if comp_symbol, _, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok {
#partial switch v in comp_symbol.value {
case index.SymbolStructValue:
@@ -362,13 +362,13 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont
case index.SymbolUnionValue:
list.isIncomplete = false;
- for name, i in v.names {
- if symbol, ok := resolve_type_expression(ast_context, v.types[i]); ok {
-
- if symbol.pkg == ast_context.document_package {
- symbol.name = fmt.aprintf("(%v)", name);
+ for type in v.types {
+ if symbol, ok := resolve_type_expression(ast_context, type); ok {
+ base := path.base(symbol.pkg, false, context.temp_allocator);
+ if symbol.pkg == ast_context.document_package || base == "runtime" {
+ symbol.name = fmt.aprintf("(%v)", common.node_to_string(type));
} else {
- symbol.name = fmt.aprintf("(%v.%v)", path.base(symbol.pkg, false, context.temp_allocator), name);
+ symbol.name = fmt.aprintf("(%v.%v)", path.base(symbol.pkg, false, context.temp_allocator), common.node_to_string(type));
}
item := CompletionItem {
@@ -408,7 +408,6 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont
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;
}
@@ -421,7 +420,7 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont
item := CompletionItem {
label = name,
kind = .Field,
- detail = fmt.tprintf("%v.%v: %v", selector.name, name, common.node_to_string(v.types[i])),
+ detail = fmt.tprintf("%v.%v: %v", selector.name, name, type_to_string(ast_context, v.types[i])),
documentation = symbol.doc,
};
@@ -449,8 +448,8 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont
symbol := search.symbol;
resolve_unresolved_symbol(ast_context, &symbol);
- build_symbol_return(&symbol);
- build_symbol_signature(&symbol);
+ build_procedure_symbol_return(&symbol);
+ build_procedure_symbol_signature(&symbol);
item := CompletionItem {
label = symbol.name,
@@ -463,7 +462,7 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont
item.insertText = fmt.tprintf("%v($0)", item.label);
item.insertTextFormat = .Snippet;
item.command.command = "editor.action.triggerParameterHints";
- item.deprecated = symbol.is_deprecated;
+ item.deprecated = .Deprecated in symbol.flags;
}
append(&items, item);
@@ -584,6 +583,7 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont
}
}
+ //infer bitset and enums based on the identifier comp_lit, i.e. a := My_Struct { my_ident = . }
if position_context.comp_lit != nil {
if position_context.parent_comp_lit.type == nil {
return;
@@ -591,37 +591,63 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont
field_name: string;
- for elem in position_context.comp_lit.elems {
- if position_in_node(elem, position_context.position) {
- if field, ok := elem.derived.(ast.Field_Value); ok {
- field_name = field.field.derived.(ast.Ident).name;
- }
- }
- }
-
- if field_name == "" {
- return;
+ if position_context.field_value != nil {
+ field_name = position_context.field_value.field.derived.(ast.Ident).name;
}
if symbol, ok := resolve_type_expression(ast_context, position_context.parent_comp_lit.type); ok {
- if comp_symbol, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok {
+ if comp_symbol, comp_lit, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok {
if s, ok := comp_symbol.value.(index.SymbolStructValue); ok {
+
+ //We can either have the final
+ elem_index := -1;
+
+ for elem, i in comp_lit.elems {
+ if position_in_node(elem, position_context.position) {
+ elem_index = i;
+ }
+ }
+
+ type: ^ast.Expr;
+
for name, i in s.names {
if name != field_name {
continue;
+ }
+
+ type = s.types[i];
+ break;
+ }
+
+ if type == nil && len(s.types) > elem_index {
+ type = s.types[elem_index];
+ }
+
+ if enum_value, ok := unwrap_enum(ast_context, type); ok {
+ for enum_name in enum_value.names {
+ item := CompletionItem {
+ label = enum_name,
+ kind = .EnumMember,
+ detail = enum_name,
+ };
+
+ append(&items, item);
}
- if enum_value, ok := unwrap_enum(ast_context, s.types[i]); ok {
- for enum_name in enum_value.names {
+ list.items = items[:];
+ return;
+ } else if bitset_symbol, ok := resolve_type_expression(ast_context, type); ok {
+ if value, ok := unwrap_bitset(ast_context, bitset_symbol); ok {
+ for name in value.names {
+
item := CompletionItem {
- label = enum_name,
+ label = name,
kind = .EnumMember,
- detail = enum_name,
+ detail = name,
};
-
+
append(&items, item);
- }
-
+ }
list.items = items[:];
return;
}
@@ -629,8 +655,8 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont
}
}
}
- }
-
+ }
+
if position_context.binary != nil && (position_context.binary.op.text == "==" || position_context.binary.op.text == "!=") {
context_node: ^ast.Expr;
@@ -846,8 +872,8 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co
for r in results {
r := r;
resolve_unresolved_symbol(ast_context, &r.symbol);
- build_symbol_return(&r.symbol);
- build_symbol_signature(&r.symbol);
+ build_procedure_symbol_return(&r.symbol);
+ build_procedure_symbol_signature(&r.symbol);
if r.symbol.uri != ast_context.uri {
append(&combined, CombinedResult {score = r.score, symbol = r.symbol});
}
@@ -875,12 +901,12 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co
ident := index.new_type(ast.Ident, v.expr.pos, v.expr.end, context.temp_allocator);
ident.name = k;
- if symbol, ok := resolve_type_identifier(ast_context, ident^); ok {
- symbol.name = ident.name;
+ if symbol, ok := resolve_type_identifier(ast_context, ident^); ok {
symbol.signature = get_signature(ast_context, ident^, symbol);
+ symbol.name = ident.name;
- build_symbol_return(&symbol);
- build_symbol_signature(&symbol);
+ build_procedure_symbol_return(&symbol);
+ build_procedure_symbol_signature(&symbol);
if score, ok := common.fuzzy_match(matcher, symbol.name); ok == 1 {
append(&combined, CombinedResult {score = score * 1.1, symbol = symbol, variable = ident});
@@ -901,11 +927,12 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co
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);
+ symbol.name = ident.name;
- build_symbol_return(&symbol);
- build_symbol_signature(&symbol);
+ build_procedure_symbol_return(&symbol);
+ build_procedure_symbol_signature(&symbol);
if score, ok := common.fuzzy_match(matcher, symbol.name); ok == 1 {
append(&combined, CombinedResult {score = score * 1.1, symbol = symbol, variable = ident});
@@ -961,13 +988,13 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co
sort.sort(combined_sort_interface(&combined));
//hard code for now
- top_results := combined[0:(min(20, len(combined)))];
+ top_results := combined[0:(min(50, len(combined)))];
for result in top_results {
result := result;
- //Skip procedures when the position is in proc decl
+ //Skip procedures when the position is in proc decl
if position_in_proc_decl(position_context) && result.symbol.type == .Function && common.config.enable_procedure_context {
continue;
}
@@ -1014,7 +1041,7 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co
if result.symbol.type == .Function {
item.insertText = fmt.tprintf("%v($0)", item.label);
item.insertTextFormat = .Snippet;
- item.deprecated = result.symbol.is_deprecated;
+ item.deprecated = .Deprecated in result.symbol.flags;
item.command.command = "editor.action.triggerParameterHints";
}
@@ -1101,7 +1128,6 @@ search_for_packages :: proc(fullpath: string) -> [] string {
}
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);
@@ -1123,13 +1149,9 @@ get_type_switch_completion :: proc(ast_context: ^analysis.AstContext, position_c
used_unions := make(map[string]bool, 5, context.temp_allocator);
if block, ok := position_context.switch_type_stmt.body.derived.(ast.Block_Stmt); ok {
-
for stmt in block.stmts {
-
if case_clause, ok := stmt.derived.(ast.Case_Clause); ok {
-
for name in case_clause.list {
-
if ident, ok := name.derived.(ast.Ident); ok {
used_unions[ident.name] = true;
}
@@ -1142,23 +1164,21 @@ get_type_switch_completion :: proc(ast_context: ^analysis.AstContext, position_c
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 {
-
- for name, i in union_value.names {
+ for type, i in union_value.types {
+ name := common.node_to_string(type);
if name in used_unions {
continue;
}
if symbol, ok := resolve_type_expression(ast_context, union_value.types[i]); ok {
-
item := CompletionItem {
kind = .EnumMember,
};
if symbol.pkg == ast_context.document_package {
- item.label = fmt.aprintf("%v", name);
+ item.label = fmt.aprintf("%v", common.node_to_string(union_value.types[i]));
item.detail = item.label;
} else {
item.label = fmt.aprintf("%v.%v", path.base(symbol.pkg, false, context.temp_allocator), name);
@@ -1228,11 +1248,47 @@ is_bitset_assignment_operator :: proc(op: string) -> bool {
}
language_keywords: []string = {
- "align_of","case","defer","enum","import","proc","transmute","when",
- "auto_cast","cast","distinct","fallthrough","in","notin","return","type_of",
- "bit_field","const","do","for","inline","offset_of","size_of","typeid",
- "bit_set","context","dynamic","foreign","opaque","struct","union",
- "break","continue","else","if","map","package","switch","using",
+ "align_of",
+ "case",
+ "defer",
+ "enum",
+ "import",
+ "proc",
+ "transmute",
+ "when",
+ "auto_cast",
+ "cast",
+ "distinct",
+ "fallthrough",
+ "in",
+ "notin",
+ "return",
+ "type_of",
+ "bit_field",
+ "const",
+ "do",
+ "for",
+ "inline",
+ "offset_of",
+ "size_of",
+ "typeid",
+ "bit_set",
+ "context",
+ "dynamic",
+ "foreign",
+ "opaque",
+ "struct",
+ "union",
+ "break",
+ "continue",
+ "else",
+ "if",
+ "map",
+ "package",
+ "switch",
+ "using",
+ "or_return",
+ "or_else",
};
swizzle_color_components: map[u8]bool = {
diff --git a/src/server/hover.odin b/src/server/hover.odin
index 443a528..e3e08fa 100644
--- a/src/server/hover.odin
+++ b/src/server/hover.odin
@@ -34,8 +34,8 @@ write_hover_content :: proc(ast_context: ^analysis.AstContext, symbol: index.Sym
}
}
- build_symbol_return(&symbol);
- build_symbol_signature(&symbol);
+ build_procedure_symbol_return(&symbol);
+ build_procedure_symbol_signature(&symbol);
cat := concatenate_symbols_information(ast_context, symbol, false);
@@ -95,9 +95,9 @@ get_hover_information :: proc(document: ^common.Document, position: common.Posit
if ident.name == base.name {
- if resolved, ok := resolve_type_identifier(&ast_context, ident); ok {
- resolved.name = ident.name;
+ if resolved, ok := resolve_type_identifier(&ast_context, ident); ok {
resolved.signature = get_signature(&ast_context, ident, resolved);
+ resolved.name = ident.name;
if is_variable, ok := ast_context.variables[ident.name]; ok && is_variable {
resolved.pkg = ast_context.document_package;
@@ -162,9 +162,9 @@ get_hover_information :: proc(document: ^common.Document, position: common.Posit
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;
+ if resolved, ok := resolve_type_identifier(&ast_context, ident); ok {
resolved.signature = get_signature(&ast_context, ident, resolved);
+ resolved.name = ident.name;
if is_variable, ok := ast_context.variables[ident.name]; ok && is_variable {
resolved.pkg = ast_context.document_package;
diff --git a/src/server/requests.odin b/src/server/requests.odin
index 8fc0fa1..fc5ea68 100644
--- a/src/server/requests.odin
+++ b/src/server/requests.odin
@@ -85,7 +85,7 @@ read_and_parse_header :: proc (reader: ^Reader) -> (Header, bool) {
header: Header;
builder := strings.make_builder(context.temp_allocator);
-
+
found_content_length := false;
for true {
@@ -422,7 +422,8 @@ request_initialize :: proc (task: ^common.Task) {
config.verbose = ols_config.verbose;
config.file_log = ols_config.file_log;
config.formatter = ols_config.formatter;
-
+ config.odin_command = strings.clone(ols_config.odin_command, context.allocator);
+
for p in ols_config.collections {
forward_path, _ := filepath.to_slash(p.path, context.temp_allocator);
@@ -947,7 +948,7 @@ notification_did_save :: proc (task: ^common.Task) {
log.errorf("failed to collect symbols on save %v", ret);
}
- //check(uri, writer);
+ check(uri, writer, config);
}
request_semantic_token_full :: proc (task: ^common.Task) {
diff --git a/src/server/signature.odin b/src/server/signature.odin
index f634327..1e89dc1 100644
--- a/src/server/signature.odin
+++ b/src/server/signature.odin
@@ -52,7 +52,7 @@ ParameterInformation :: struct {
/*
Lazily build the signature and returns from ast.Nodes
*/
-build_symbol_signature :: proc(symbol: ^index.Symbol) {
+build_procedure_symbol_signature :: proc(symbol: ^index.Symbol) {
if value, ok := symbol.value.(index.SymbolProcedureValue); ok {
builder := strings.make_builder(context.temp_allocator);
@@ -69,7 +69,7 @@ build_symbol_signature :: proc(symbol: ^index.Symbol) {
}
}
-build_symbol_return :: proc(symbol: ^index.Symbol) {
+build_procedure_symbol_return :: proc(symbol: ^index.Symbol) {
if value, ok := symbol.value.(index.SymbolProcedureValue); ok {
builder := strings.make_builder(context.temp_allocator);
@@ -174,8 +174,8 @@ get_signature_information :: proc(document: ^common.Document, position: common.P
parameters[i].label = common.node_to_string(arg);
}
- build_symbol_signature(&call);
- build_symbol_return(&call);
+ build_procedure_symbol_signature(&call);
+ build_procedure_symbol_return(&call);
info := SignatureInformation {
label = concatenate_symbols_information(&ast_context, call, false),
@@ -205,8 +205,8 @@ get_signature_information :: proc(document: ^common.Document, position: common.P
parameters[i].activeParameter = i;
}
- build_symbol_signature(&symbol);
- build_symbol_return(&symbol);
+ build_procedure_symbol_signature(&symbol);
+ build_procedure_symbol_return(&symbol);
info := SignatureInformation {
label = concatenate_symbols_information(&ast_context, symbol, false),
diff --git a/src/server/types.odin b/src/server/types.odin
index d369b33..4a36d82 100644
--- a/src/server/types.odin
+++ b/src/server/types.odin
@@ -301,6 +301,7 @@ OlsConfig :: struct {
verbose: bool,
file_log: bool,
formatter: common.Format_Config,
+ odin_command: string,
}
OlsConfigCollection :: struct {
diff --git a/src/testing/testing.odin b/src/testing/testing.odin
index 0703708..bd4e39b 100644
--- a/src/testing/testing.odin
+++ b/src/testing/testing.odin
@@ -160,6 +160,41 @@ expect_signature_parameter_position :: proc(t: ^testing.T, src: ^Source, positio
}
}
+expect_completion_labels :: proc(t: ^testing.T, src: ^Source, trigger_character: string, expect_labels: []string) {
+ setup(src);
+
+ completion_context := server.CompletionContext {
+ triggerCharacter = trigger_character,
+ };
+
+ completion_list, ok := server.get_completion_list(src.document, src.position, completion_context);
+
+ if !ok {
+ testing.error(t, "Failed get_completion_list");
+ }
+
+ if len(expect_labels) == 0 && len(completion_list.items) > 0 {
+ testing.errorf(t, "Expected empty completion label, but received %v", completion_list.items);
+ }
+
+ flags := make([]int, len(expect_labels));
+
+ for expect_label, i in expect_labels {
+ for completion, j in completion_list.items {
+ if expect_label == completion.label {
+ flags[i] += 1;
+ }
+ }
+ }
+
+ for flag, i in flags {
+ if flag != 1 {
+ testing.errorf(t, "Expected completion detail %v, but received %v", expect_labels[i], completion_list.items);
+ }
+ }
+
+}
+
expect_completion_details :: proc(t: ^testing.T, src: ^Source, trigger_character: string, expect_details: []string) {
setup(src);