aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanielGavin <danielgavin5@hotmail.com>2020-11-16 21:30:18 +0100
committerDanielGavin <danielgavin5@hotmail.com>2020-11-16 21:30:18 +0100
commitee4a7f64bcb9d6d7b60d5495fc072b2a62b5f790 (patch)
tree4ff2c689e5e1456a514993bead6d3dcf4c6e1300
parent1c2c7cd727bcc420d99741e1862573fa07294c90 (diff)
overloaded function work
-rw-r--r--src/common/ast.odin430
-rw-r--r--src/index/build.odin8
-rw-r--r--src/index/clone.odin16
-rw-r--r--src/server/analysis.odin105
4 files changed, 546 insertions, 13 deletions
diff --git a/src/common/ast.odin b/src/common/ast.odin
index cc8ad83..8642afd 100644
--- a/src/common/ast.odin
+++ b/src/common/ast.odin
@@ -1,17 +1,443 @@
package common
import "core:odin/ast"
-
+import "core:log"
+import "core:mem"
get_ast_node_string :: proc(node: ^ast.Node, src: [] byte) -> string {
return string(src[node.pos.offset:node.end.offset]);
}
+free_ast :: proc{
+ free_ast_node,
+ free_ast_array,
+ free_ast_dynamic_array
+};
-free_ast_node :: proc(file: ^ast.Node) {
+free_ast_array :: proc(array: $A/[]^$T) {
+ for elem, i in array {
+ free_ast(elem);
+ }
+}
+free_ast_dynamic_array :: proc(array: $A/[dynamic]^$T) {
+ for elem, i in array {
+ free_ast(elem);
+ }
}
+free_ast_node :: proc(node: ^ast.Node) {
+
+ using ast;
+
+ if node == nil {
+ return;
+ }
+
+ switch n in node.derived {
+ case Bad_Expr:
+ case Ident:
+ case Implicit:
+ case Undef:
+ case Basic_Directive:
+ case Basic_Lit:
+ case Ellipsis:
+ free_ast(n.expr);
+ case Proc_Lit:
+ free_ast(n.type);
+ free_ast(n.body);
+ case Comp_Lit:
+ free_ast(n.type);
+ free_ast(n.elems);
+ case Tag_Expr:
+ free_ast(n.expr);
+ case Unary_Expr:
+ free_ast(n.expr);
+ case Binary_Expr:
+ free_ast(n.left);
+ free_ast(n.right);
+ case Paren_Expr:
+ free_ast(n.expr);
+ case Call_Expr:
+ free_ast(n.expr);
+ free_ast(n.args);
+ case Selector_Expr:
+ free_ast(n.expr);
+ free_ast(n.field);
+ case Implicit_Selector_Expr:
+ free_ast(n.field);
+ case Index_Expr:
+ free_ast(n.expr);
+ free_ast(n.index);
+ case Deref_Expr:
+ free_ast(n.expr);
+ case Slice_Expr:
+ free_ast(n.expr);
+ free_ast(n.low);
+ free_ast(n.high);
+ case Field_Value:
+ free_ast(n.field);
+ free_ast(n.value);
+ case Ternary_Expr:
+ free_ast(n.cond);
+ free_ast(n.x);
+ free_ast(n.y);
+ case Ternary_If_Expr:
+ free_ast(n.x);
+ free_ast(n.cond);
+ free_ast(n.y);
+ case Ternary_When_Expr:
+ free_ast(n.x);
+ free_ast(n.cond);
+ free_ast(n.y);
+ case Type_Assertion:
+ free_ast(n.expr);
+ free_ast(n.type);
+ case Type_Cast:
+ free_ast(n.type);
+ free_ast(n.expr);
+ case Auto_Cast:
+ free_ast(n.expr);
+ case Bad_Stmt:
+ case Empty_Stmt:
+ case Expr_Stmt:
+ free_ast(n.expr);
+ case Tag_Stmt:
+ r := cast(^Expr_Stmt)node;
+ free_ast(r.expr);
+ case Assign_Stmt:
+ free_ast(n.lhs);
+ free_ast(n.rhs);
+ case Block_Stmt:
+ free_ast(n.label);
+ free_ast(n.stmts);
+ case If_Stmt:
+ free_ast(n.label);
+ free_ast(n.init);
+ free_ast(n.cond);
+ free_ast(n.body);
+ free_ast(n.else_stmt);
+ case When_Stmt:
+ free_ast(n.cond);
+ free_ast(n.body);
+ free_ast(n.else_stmt);
+ case Return_Stmt:
+ free_ast(n.results);
+ case Defer_Stmt:
+ free_ast(n.stmt);
+ case For_Stmt:
+ free_ast(n.label);
+ free_ast(n.init);
+ free_ast(n.cond);
+ free_ast(n.post);
+ free_ast(n.body);
+ case Range_Stmt:
+ free_ast(n.label);
+ free_ast(n.val0);
+ free_ast(n.val1);
+ free_ast(n.expr);
+ free_ast(n.body);
+ case Case_Clause:
+ free_ast(n.list);
+ free_ast(n.body);
+ case Switch_Stmt:
+ free_ast(n.label);
+ free_ast(n.init);
+ free_ast(n.cond);
+ free_ast(n.body);
+ case Type_Switch_Stmt:
+ free_ast(n.label);
+ free_ast(n.tag);
+ free_ast(n.expr);
+ free_ast(n.body);
+ case Branch_Stmt:
+ free_ast(n.label);
+ case Using_Stmt:
+ free_ast(n.list);
+ case Bad_Decl:
+ case Value_Decl:
+ free_ast(n.attributes);
+ free_ast(n.names);
+ free_ast(n.type);
+ free_ast(n.values);
+ case Package_Decl:
+ case Import_Decl:
+ case Foreign_Block_Decl:
+ free_ast(n.attributes);
+ free_ast(n.foreign_library);
+ free_ast(n.body);
+ case Foreign_Import_Decl:
+ free_ast(n.name);
+ case Proc_Group:
+ free_ast(n.args);
+ case Attribute:
+ free_ast(n.elems);
+ case Field:
+ free_ast(n.names);
+ free_ast(n.type);
+ free_ast(n.default_value);
+ case Field_List:
+ free_ast(n.list);
+ case Typeid_Type:
+ free_ast(n.specialization);
+ case Helper_Type:
+ free_ast(n.type);
+ case Distinct_Type:
+ free_ast(n.type);
+ case Opaque_Type:
+ free_ast(n.type);
+ case Poly_Type:
+ free_ast(n.type);
+ free_ast(n.specialization);
+ case Proc_Type:
+ free_ast(n.params);
+ free_ast(n.results);
+ case Pointer_Type:
+ free_ast(n.elem);
+ case Array_Type:
+ free_ast(n.len);
+ free_ast(n.elem);
+ case Dynamic_Array_Type:
+ free_ast(n.elem);
+ case Struct_Type:
+ free_ast(n.poly_params);
+ free_ast(n.align);
+ free_ast(n.fields);
+ case Union_Type:
+ free_ast(n.poly_params);
+ free_ast(n.align);
+ free_ast(n.variants);
+ case Enum_Type:
+ free_ast(n.base_type);
+ free_ast(n.fields);
+ case Bit_Field_Type:
+ free_ast(n.fields);
+ case Bit_Set_Type:
+ free_ast(n.elem);
+ free_ast(n.underlying);
+ case Map_Type:
+ free_ast(n.key);
+ free_ast(n.value);
+ case:
+ log.errorf("free Unhandled node kind: %T", n);
+ }
+
+ mem.free(node);
+}
+
+
+
free_ast_file :: proc(file: ast.File) {
+ for decl in file.decls {
+ free_ast(decl);
+ }
+
+}
+
+
+node_equal :: proc{
+ node_equal_node,
+ node_equal_array,
+ node_equal_dynamic_array
+};
+
+node_equal_array :: proc(a, b: $A/[]^$T) -> bool {
+
+ ret := true;
+
+ if len(a) != len(b) {
+ return false;
+ }
+
+ for elem, i in a {
+ ret &= node_equal(elem, b[i]);
+ }
+
+ return ret;
+}
+
+node_equal_dynamic_array :: proc(a, b: $A/[dynamic]^$T) -> bool {
+
+ ret := true;
+
+ if len(a) != len(b) {
+ return false;
+ }
+
+ for elem, i in a {
+ ret &= node_equal(elem, b[i]);
+ }
+
+ return ret;
+}
+
+
+node_equal_node :: proc(a, b: ^ast.Node) -> bool {
+
+ using ast;
+
+ if a == nil || b == nil {
+ return false;
+ }
+
+ switch m in b.derived {
+ case Bad_Expr:
+ if n, ok := a.derived.(Bad_Expr); ok {
+ return true;
+ }
+ case Ident:
+ if n, ok := a.derived.(Ident); ok {
+ return n.name == m.name;
+ }
+ case Implicit:
+ if n, ok := a.derived.(Implicit); ok {
+ return true;
+ }
+ case Undef:
+ if n, ok := a.derived.(Undef); ok {
+ return true;
+ }
+ case Basic_Lit:
+ if n, ok := a.derived.(Basic_Lit); ok {
+ return true;
+ }
+ case Poly_Type:
+ if n, ok := a.derived.(Poly_Type); ok {
+ ret := node_equal(n.type, m.type);
+ ret &= node_equal(n.specialization, m.specialization);
+ return ret;
+ }
+ case Ellipsis:
+ if n, ok := a.derived.(Ellipsis); ok {
+ return node_equal(n.expr, m.expr);
+ }
+ case Tag_Expr:
+ if n, ok := a.derived.(Tag_Expr); ok {
+ return node_equal(n.expr, m.expr);
+ }
+ case Unary_Expr:
+ if n, ok := a.derived.(Unary_Expr); ok {
+ return node_equal(n.expr, m.expr);
+ }
+ case Binary_Expr:
+ if n, ok := a.derived.(Binary_Expr); ok {
+ ret := node_equal(n.left, m.left);
+ ret &= node_equal(n.right, m.right);
+ return ret;
+ }
+ case Paren_Expr:
+ if n, ok := a.derived.(Paren_Expr); ok {
+ return node_equal(n.expr, m.expr);
+ }
+ case Selector_Expr:
+ if n, ok := a.derived.(Selector_Expr); ok {
+ ret := node_equal(n.expr, m.expr);
+ ret &= node_equal(n.field, m.field);
+ return ret;
+ }
+ case Slice_Expr:
+ if n, ok := a.derived.(Slice_Expr); ok {
+ ret := node_equal(n.expr, m.expr);
+ ret &= node_equal(n.low, m.low);
+ ret &= node_equal(n.high, m.high);
+ return ret;
+ }
+ case Distinct_Type:
+ if n, ok := a.derived.(Distinct_Type); ok {
+ return node_equal(n.type, m.type);
+ }
+ case Opaque_Type:
+ if n, ok := a.derived.(Opaque_Type); ok {
+ return node_equal(n.type, m.type);
+ }
+ case Proc_Type:
+ if n, ok := a.derived.(Proc_Type); ok {
+ ret := node_equal(n.params, m.params);
+ ret &= node_equal(n.results, m.results);
+ return ret;
+ }
+ case Pointer_Type:
+ if n, ok := a.derived.(Pointer_Type); ok {
+ return node_equal(n.elem, m.elem);
+ }
+ case Array_Type:
+ if n, ok := a.derived.(Array_Type); ok {
+ ret := node_equal(n.len, m.len);
+ ret &= node_equal(n.elem, m.elem);
+ return ret;
+ }
+ case Dynamic_Array_Type:
+ if n, ok := a.derived.(Dynamic_Array_Type); ok {
+ return node_equal(n.elem, m.elem);
+ }
+ case Struct_Type:
+ if n, ok := a.derived.(Struct_Type); ok {
+ ret := node_equal(n.poly_params, m.poly_params);
+ ret &= node_equal(n.align, m.align);
+ ret &= node_equal(n.fields, m.fields);
+ return ret;
+ }
+ case Field:
+ if n, ok := a.derived.(Field); ok {
+ ret := node_equal(n.names, m.names);
+ ret &= node_equal(n.type, m.type);
+ ret &= node_equal(n.default_value, m.default_value);
+ return ret;
+ }
+ case Field_List:
+ if n, ok := a.derived.(Field_List); ok {
+ return node_equal(n.list, m.list);
+ }
+ case Field_Value:
+ if n, ok := a.derived.(Field_Value); ok {
+ ret := node_equal(n.field, m.field);
+ ret &= node_equal(n.value, m.value);
+ return ret;
+ }
+ case Union_Type:
+ if n, ok := a.derived.(Union_Type); ok {
+ ret := node_equal(n.poly_params, m.poly_params);
+ ret &= node_equal(n.align, m.align);
+ ret &= node_equal(n.variants, m.variants);
+ return ret;
+ }
+ case Enum_Type:
+ if n, ok := a.derived.(Enum_Type); ok {
+ ret := node_equal(n.base_type, m.base_type);
+ ret &= node_equal(n.fields, m.fields);
+ return ret;
+ }
+ case Bit_Field_Type:
+ if n, ok := a.derived.(Bit_Field_Type); ok {
+ return node_equal(n.fields, m.fields);
+ }
+ case Bit_Set_Type:
+ if n, ok := a.derived.(Bit_Set_Type); ok {
+ ret := node_equal(n.elem, m.elem);
+ ret &= node_equal(n.underlying, m.underlying);
+ return ret;
+ }
+ case Map_Type:
+ if n, ok := a.derived.(Map_Type); ok {
+ ret := node_equal(n.key, m.key);
+ ret &= node_equal(n.value, m.value);
+ return ret;
+ }
+ case Call_Expr:
+ if n, ok := a.derived.(Call_Expr); ok {
+ ret := node_equal(n.expr, m.expr);
+ ret &= node_equal(n.args, m.args);
+ return ret;
+ }
+ case Typeid_Type:
+ if n, ok := a.derived.(Typeid_Type); ok {
+ return node_equal(n.specialization, m.specialization);
+ }
+ case:
+ log.error("Unhandled poly node kind: %T", m);
+ }
+
+ return false;
+
} \ No newline at end of file
diff --git a/src/index/build.odin b/src/index/build.odin
index 8f3c114..f9529ba 100644
--- a/src/index/build.odin
+++ b/src/index/build.odin
@@ -5,6 +5,7 @@ import "core:os"
import "core:fmt"
import "core:odin/parser"
import "core:odin/ast"
+import "core:log"
import "core:odin/tokenizer"
import "shared:common"
@@ -35,7 +36,7 @@ build_static_index :: proc(allocator := context.allocator, config: ^common.Confi
}
//bit worried about using temp allocator here since we might overwrite all our temp allocator budget
- data, ok := os.read_entire_file(info.fullpath, context.allocator);
+ data, ok := os.read_entire_file(info.fullpath, context.temp_allocator);
if !ok {
return 1, false;
@@ -51,14 +52,13 @@ build_static_index :: proc(allocator := context.allocator, config: ^common.Confi
src = data,
};
- parser.parse_file(&p, &file);
+ ok = parser.parse_file(&p, &file);
uri := common.create_uri(info.fullpath, context.temp_allocator);
collect_symbols(&symbol_collection, file, uri.uri);
- delete(data);
-
+ common.free_ast_file(file);
return 0, false;
};
diff --git a/src/index/clone.odin b/src/index/clone.odin
index 0dcb0b9..a09f1b7 100644
--- a/src/index/clone.odin
+++ b/src/index/clone.odin
@@ -7,6 +7,16 @@ import "core:odin/ast"
import "core:strings"
import "core:log"
+new_type :: proc($T: typeid, pos, end: tokenizer.Pos, allocator := context.allocator) -> ^T {
+ n := mem.new(T);
+ n.pos = pos;
+ n.end = end;
+ n.derived = n^;
+ base: ^ast.Node = n; // dummy check
+ _ = base; // "Use" type to make -vet happy
+ return n;
+}
+
clone_type :: proc{
clone_node,
clone_expr,
@@ -72,7 +82,6 @@ clone_node :: proc(node: ^ast.Node, allocator := context.allocator) -> ^ast.Node
case Implicit:
case Undef:
case Basic_Lit:
-
case Ellipsis:
r := cast(^Ellipsis)res;
r.expr = clone_type(r.expr, allocator);
@@ -165,6 +174,11 @@ clone_node :: proc(node: ^ast.Node, allocator := context.allocator) -> ^ast.Node
case Typeid_Type:
r := cast(^Typeid_Type)res;
r.specialization = clone_type(r.specialization, allocator);
+ case Ternary_When_Expr:
+ r := cast(^Ternary_When_Expr)res;
+ r.x = clone_type(r.x);
+ r.cond = clone_type(r.cond);
+ r.y = clone_type(r.y);
case:
log.error("Unhandled node kind: %T", n);
}
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index 19a43d7..f4b9ddd 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -8,11 +8,16 @@ import "core:log"
import "core:strings"
import "core:path"
import "core:mem"
+import "core:strconv"
import "shared:common"
import "shared:index"
+bool_lit := "bool";
+int_lit := "int";
+string_lit := "string";
+
DocumentPositionContextHint :: enum {
Completion,
SignatureHelp,
@@ -115,7 +120,7 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s
/*
Note(Daniel, uncertain about the switch cases being enough or too little)
- */
+ */
using ast;
@@ -338,21 +343,102 @@ resolve_generic_function :: proc(ast_context: ^AstContext, proc_lit: ast.Proc_Li
return_types = return_types[:],
};
- log.info(poly_map);
+ //log.info(poly_map);
return symbol, true;
}
+
/*
Figure out which function the call expression is using out of the list from proc group
*/
resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Group) -> (index.Symbol, bool) {
+ using ast;
+
+ if ast_context.call == nil {
+ return index.Symbol {}, false;
+ }
+
+ call_expr := ast_context.call.derived.(Call_Expr);
+
+ for arg_expr in group.args {
+
+ next_fn: if f, ok := resolve_type_expression(ast_context, arg_expr, false); ok {
+
+ if procedure, ok := f.value.(index.SymbolProcedureValue); ok {
+
+ if len(procedure.arg_types) != len(call_expr.args) {
+ continue;
+ }
+
+ for proc_args, i in procedure.arg_types {
+
+ if eval_call_expr, ok := resolve_type_expression(ast_context, call_expr.args[i], false); ok {
+
+ #partial switch v in eval_call_expr.value {
+ case index.SymbolProcedureValue:
+ case index.SymbolGenericValue:
+ if !common.node_equal(proc_args.type, v.expr) {
+ break next_fn;
+ }
+ case index.SymbolStructValue:
+ }
+
+ }
+
+ else {
+ return index.Symbol {}, false;
+ }
+
+
+
+ }
+
+ return f, true;
+ }
+
+ }
+
+ }
return index.Symbol {}, false;
}
+resolve_basic_lit :: proc(ast_context: ^AstContext, basic_lit: ast.Basic_Lit) -> (index.Symbol, bool) {
+
+ /*
+ This is temporary, since basic lit is untyped, but either way it's going to be an ident representing a keyword.
+
+ Could perhaps name them "$integer", "$float", etc.
+ */
+
+ ident := index.new_type(ast.Ident, basic_lit.pos, basic_lit.end, context.temp_allocator);
+
+ symbol := index.Symbol {
+ type = .Keyword,
+ };
+
+ if v, ok := strconv.parse_bool(basic_lit.tok.text); ok {
+ ident.name = bool_lit;
+ }
+
+ else if v, ok := strconv.parse_int(basic_lit.tok.text); ok {
+ ident.name = int_lit;
+ }
+
+ else {
+ ident.name = string_lit;
+ }
+
+ symbol.value = index.SymbolGenericValue {
+ expr = ident,
+ };
+
+ return symbol, true;
+}
+
resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr, expect_identifier := true) -> (index.Symbol, bool) {
using ast;
@@ -360,6 +446,8 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr, expec
switch v in node.derived {
case Ident:
return resolve_type_identifier(ast_context, v, expect_identifier);
+ case Basic_Lit:
+ return resolve_basic_lit(ast_context, v);
case Index_Expr:
indexed, ok := resolve_type_expression(ast_context, v.expr, false);
@@ -415,7 +503,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr, expec
return index.Symbol {}, false;
}
case:
- log.errorf("Unhandled node kind: %T", v);
+ log.errorf("Unhandled node kind, resolve_type_expression: %T", v);
}
return index.Symbol {}, false;
@@ -521,6 +609,13 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident, expec
type = .Keyword,
};
+ ident := index.new_type(Ident, node.pos, node.end, context.temp_allocator);
+ ident.name = node.name;
+
+ symbol.value = index.SymbolGenericValue {
+ expr = ident,
+ };
+
return symbol, true;
}
@@ -734,8 +829,6 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co
case Comp_Lit:
append(&results, v.type);
- case Proc_Group:
-
case:
append(&results, value);
}
@@ -797,7 +890,7 @@ get_definition_location :: proc(document: ^Document, position: common.Position)
position_context, ok := get_document_position_context(document, position, .Definition);
if !ok {
- log.info("Failed to get position context");
+ log.error("Failed to get position context");
return location, false;
}