From ee4a7f64bcb9d6d7b60d5495fc072b2a62b5f790 Mon Sep 17 00:00:00 2001 From: DanielGavin Date: Mon, 16 Nov 2020 21:30:18 +0100 Subject: overloaded function work --- src/common/ast.odin | 430 ++++++++++++++++++++++++++++++++++++++++++++++- src/index/build.odin | 8 +- src/index/clone.odin | 16 +- src/server/analysis.odin | 105 +++++++++++- 4 files changed, 546 insertions(+), 13 deletions(-) (limited to 'src') 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; } -- cgit v1.2.3