From e851d0eac598ac9b212c9f36447f6905c97742d3 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Fri, 22 Jun 2018 20:58:47 -0400 Subject: [PATCH] Add basis for types in k, and move to new poset setup (depend on individual imports, functions, types, and global variables) --- k.krak | 154 ++++++++++++++++-------- stdlib/ast.krak | 16 +-- stdlib/ast_transformation.krak | 21 ++-- stdlib/map.krak | 4 +- stdlib/poset.krak | 21 ++++ stdlib/type2.krak | 206 +++++++++++++++++++++++++++++++++ 6 files changed, 354 insertions(+), 68 deletions(-) create mode 100644 stdlib/type2.krak diff --git a/k.krak b/k.krak index 6255e7d..2ceded8 100644 --- a/k.krak +++ b/k.krak @@ -1,4 +1,3 @@ - import io:* import grammer:* import lexer:* @@ -12,6 +11,7 @@ import vec_literals:* import poset:* import util:* import ast:* +import type2:* import tree:* import symbol:* @@ -19,6 +19,7 @@ fun main(argc: int, argv: **char): int { // delay construction until we either load it or copy construct it var gram: grammer var base_dir = str("/").join(str(argv[0]).split('/').slice(0,-2)) + var import_paths = vec(str(), base_dir + "/stdlib/") var file_name = base_dir + "/krakenGrammer.kgm" var compiled_name = file_name + str(".comp_new") var compiled_version = 1 @@ -82,59 +83,56 @@ fun main(argc: int, argv: **char): int { if (positional_args.size > 1) executable_name = positional_args[1] - var pass_poset = poset>() + var pass_poset = poset>() var name_ast_map = map>() - var import_paths = vec(str(), base_dir + "/stdlib/") - var passes = vec>() - passes = vec( - fun(file_name: str): *tree { - var file = str() - for (var i = 0; i < import_paths.size; i++;) { - if (file_exists(import_paths[i] + file_name)) { - if (file != "") - error("File: " + file_name + ", found in multiple import paths - at least two of [" + str(",").join(import_paths) + "]") - file = read_file(import_paths[i] + file_name) - } - } - if (file == "") - error("File: " + file_name + ", not found in any import path - none of [" + str(",").join(import_paths) + "]") - printerr(file_name + ", ") - var parse_tree = parse.parse_input(file, file_name) + var passes = map() + + // resolves a single import + passes[str("import_resolver")] = fun(import_binding: *ast): bool { + var file_path = binding_str(import_binding) + println("Running import resolver for" + file_path) + if (!name_ast_map.contains_key(file_path)) { + printerr(file_path + ", ") + var parse_tree = parse.parse_input(read_file(file_path), file_path) trim(parse_tree) - return syntax_to_ast(file_name, parse_tree) - }, - fun(file_name: str): *tree { - println("Checking for imports in " + file_name) - name_ast_map[file_name]->children.for_each(fun(n: *tree) { - match (n->data) { - ast::_import(b) { - var imported_file_name = n->children[0]->data._identifier.first + ".krak" - for (var i = 0; i < passes.size; i++;) { - if (i == 0) - pass_poset.add_relationship(make_pair(file_name, 2), make_pair(imported_file_name, 0)) - else - pass_poset.add_relationship(make_pair(imported_file_name, i), make_pair(imported_file_name, i-1)) - } + name_ast_map[file_path] = syntax_to_ast(file_path, parse_tree, import_paths) + } + set_bindings(import_binding, name_ast_map[file_path]) + + return true + } + + // ensures that all imports reachable from this one are resolved + passes[str("import_checker")] = fun(import_binding: *ast): bool { + var all_resolved = true + var file_path = binding_str(import_binding) + println("Running import checker for " + file_path) + name_ast_map[file_path]->children.for_each(fun(n: *tree) { + match (n->data) { + ast::_import(b) { + if (!bound(b.first)) { + all_resolved = false + pass_poset.add_relationship(make_pair(import_binding, str("import_checker")), make_pair(b.first, str("import_resolver"))) + println(to_string(*b.first) + " is not bound!") + } else { + println(to_string(*b.first) + " is bound!") } } - }) - return name_ast_map[file_name] - }, - fun(file_name: str): *tree { - println("Doing thing 3 to " + file_name) - return name_ast_map[file_name] - } - ) - for (var i = 0; i < passes.size; i++;) { - if (i == 0) - pass_poset.add_vertex(make_pair(kraken_file_name, i)) - else - pass_poset.add_relationship(make_pair(kraken_file_name, i), make_pair(kraken_file_name, i-1)) + } + }) + + return all_resolved } + + var top_binding = make_binding(kraken_file_name) + pass_poset.add_relationship(make_pair(top_binding, str("import_checker")), make_pair(top_binding, str("import_resolver"))) + while (pass_poset.size() != 0) { - var file_pass = pass_poset.pop() - printlnerr("doing pass " + to_string(file_pass.second) + " on " + file_pass.first) - name_ast_map[file_pass.first] = passes[file_pass.second](file_pass.first) + var file_pass = pass_poset.top() + printlnerr("doing pass " + file_pass.second + " on " + to_string(*file_pass.first)) + var done = passes[file_pass.second](file_pass.first) + if (done) + pass_poset.remove(file_pass) } println() @@ -160,11 +158,65 @@ fun main(argc: int, argv: **char): int { return 0 } -fun syntax_to_ast(file_name: str, syntax: *tree): *tree { +var bindings: *vec<*ast> +fun make_binding(s: str): *ast { + var binding = new()->copy_construct(&ast::_binding(make_triple(s, vec<*type>(), null>()))) + if (bindings == null>()) + bindings = new>()->construct() + bindings->add(binding) + return binding +} +fun set_bindings(binding: *tree, to: *tree) { + set_bindings(&binding->data, to) +} +fun set_bindings(binding: *ast, to: *tree) { + match(*binding) { + ast::_binding(b) { + var from = binding->_binding.third + // don't set null, that will set all unbound ones + if (from == null>()) { + binding->_binding.third = to + return + } + for (var i = 0; i < bindings->size; i++;) + if (bindings->get(i)->_binding.third == from) + bindings->get(i)->_binding.third = to + return + } + } + error("trying to set bindings on not a binding") +} +fun bound(binding: *ast): bool { + match(*binding) { + ast::_binding(b) return b.third != null>() + } + error("Trying to check bound for not a binding") +} +fun binding_str(binding: *ast): str { + match(*binding) { + ast::_binding(b) return b.first + } + error("Trying to get name for not a binding") +} + +fun syntax_to_ast(file_name: str, syntax: *tree, import_paths: ref vec): *tree { + var resolve_import_file = fun(file_name: str): str { + var file_path = str() + for (var i = 0; i < import_paths.size; i++;) { + if (file_exists(import_paths[i] + file_name)) { + if (file_path != "") + error("File: " + file_name + ", found in multiple import paths - at least two of [" + str(",").join(import_paths) + "]") + file_path = import_paths[i] + file_name + } + } + if (file_path == "") + error("File: " + file_name + ", not found in any import path - none of [" + str(",").join(import_paths) + "]") + return file_path + } + var syntax_to_ast_helper: fun(*tree): *tree = fun(syntax: *tree): *tree { - printlnerr("syntax_to_ast " + syntax->data.name) if (syntax->data.name == "import") { - return _import(from_vector(syntax->children.slice(2,-1).filter(fun(s:*tree):bool { + return _import(make_binding(resolve_import_file(concat(syntax->children[1]) + ".krak")), from_vector(syntax->children.slice(2,-1).filter(fun(s:*tree):bool { return s->data.name == "identifier" || s->data.data == "*" }).map(concat)), vec(syntax_to_ast_helper(syntax->children[1]))) } else if (syntax->data.name == "function") diff --git a/stdlib/ast.krak b/stdlib/ast.krak index ab89db6..ce4ba65 100644 --- a/stdlib/ast.krak +++ b/stdlib/ast.krak @@ -1,5 +1,5 @@ import tree:* -import type:* +import type2:* import vec:* import set:* import util:* @@ -8,7 +8,7 @@ import mem:* adt ast { _translation_unit: str, - _import: set, + _import: pair<*ast, set>, _identifier: pair, _binding: triple, *tree>, _type_def: str, @@ -35,9 +35,9 @@ adt ast { fun to_string(a: ref ast): str { match(a) { ast::_translation_unit(b) return str("_translation_unit(") + b + ")" - ast::_import(b) return str("_import[") + str(",").join(b.data) + "]" + ast::_import(b) return str("_import(") + to_string(*b.first) + ")[" + str(",").join(b.second.data) + "]" ast::_identifier(b) return str("_identifier(") + b.first + ")" - ast::_binding(b) return str("_binding(") + b.first + ")" + ast::_binding(b) return str("_binding(") + b.first + "->" + to_string(b.third) + ")" ast::_type_def(b) return str("_type_def(") + b + ")" ast::_adt_def(b) return str("_adt_def(") + b + ")" ast::_function(b) return str("_function(") + b.first + ")" @@ -63,8 +63,8 @@ fun to_string(a: ref ast): str { fun _translation_unit(p: str): *tree { return new>()->construct(ast::_translation_unit(p)) } -fun _import(p: set): *tree { - return new>()->construct(ast::_import(p)) +fun _import(p1: *ast, p2: set): *tree { + return new>()->construct(ast::_import(make_pair(p1,p2))) } fun _type_def(p: str): *tree { return new>()->construct(ast::_type_def(p)) @@ -141,8 +141,8 @@ fun _call(): *tree { fun _translation_unit(p: str, c: ref vec<*tree>): *tree { return new>()->construct(ast::_translation_unit(p), c) } -fun _import(p: set, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_import(p), c) +fun _import(p1: *ast, p2: set, c: ref vec<*tree>): *tree { + return new>()->construct(ast::_import(make_pair(p1,p2)), c) } fun _type_def(p: str, c: ref vec<*tree>): *tree { return new>()->construct(ast::_type_def(p), c) diff --git a/stdlib/ast_transformation.krak b/stdlib/ast_transformation.krak index 4554b0e..01ff8cc 100644 --- a/stdlib/ast_transformation.krak +++ b/stdlib/ast_transformation.krak @@ -838,14 +838,21 @@ obj ast_transformation (Object) { if (!possible_value) match (searching_for) { search_type::function(type_vec) possible_value = find_or_instantiate_template_function(concat_symbol_tree(node->children[0]), null>(), scope, type_vec, template_replacements, map()); } - if (!possible_value) + if (!possible_value) { + var function_error_str = str() + match (searching_for) { + search_type::function() { + function_error_str = "(" + searching_for.function.reduce(fun(n:*type, s:str):str { + if (n) + return s+","+n->to_string() + else + return s+",null" + }, str()) + ")" + } + } error(node, concat_symbol_tree(node) + ": HAS NO POSSIBLE FUNCTION OR FUNCTION TEMPLATE SOLUTIONS\nlooking for: " + - concat_symbol_tree(node->children[0]) + "(" + searching_for.function.reduce(fun(n:*type, s:str):str { - if (n) - return s+","+n->to_string() - else - return s+",null" - }, str()) + ")") + concat_symbol_tree(node->children[0]) + function_error_str) + } return possible_value } else if (node->children.size == 2) { var template_inst = get_node("template_inst", node) diff --git a/stdlib/map.krak b/stdlib/map.krak index 8bb121d..ec4ba42 100644 --- a/stdlib/map.krak +++ b/stdlib/map.krak @@ -66,7 +66,7 @@ obj map (Object, Serializable) { fun contains_key(key: ref T): bool { return keys.contains(key) } - fun contains_value(value: ref U): bool { + fun contains_value(value: ref V): bool { return values.contains(value) } fun get(key: ref T): ref U { @@ -86,7 +86,7 @@ obj map (Object, Serializable) { return get(key) return default_val } - fun reverse_get(value: ref U): ref T { + fun reverse_get(value: ref V): ref T { /*return values.get(keys.find(key))*/ var value_loc = values.find(value) if (value_loc == -1) diff --git a/stdlib/poset.krak b/stdlib/poset.krak index 486955e..6485c2b 100644 --- a/stdlib/poset.krak +++ b/stdlib/poset.krak @@ -48,6 +48,27 @@ obj poset (Object) { }) return depends_on } + fun top(): T { + for (var i = 0; i < adj_matrix.keys.size; i++;) { + if (adj_matrix.values[i].size() == 0) { + return adj_matrix.keys[i] + } + } + error("Nothing to top") + } + fun remove(x: ref T) { + var dependencies = adj_matrix.get_ptr_or_null(x) + if (dependencies == null>()) + error("Trying to remove item from poset that doesn't contain it!") + if (dependencies->size() != 0) + error("Trying to remove item from poset that still has dependencies on it!") + + for (var j = 0; j < adj_matrix.keys.size; j++;) { + // remove is ok if it doesn't exist + adj_matrix.values[j].remove(x) + } + adj_matrix.remove(x) + } fun pop(): T { for (var i = 0; i < adj_matrix.keys.size; i++;) { if (adj_matrix.values[i].size() == 0) { diff --git a/stdlib/type2.krak b/stdlib/type2.krak new file mode 100644 index 0000000..d2c91b0 --- /dev/null +++ b/stdlib/type2.krak @@ -0,0 +1,206 @@ +import mem:* +import str:* +import vec:* +import util:* +import ast:* + +adt base_type { + _unknown, + _void, + _object: *ast, + // triple, is_variadic, is raw> + _function: triple, *type>, bool, bool>, + _template_placeholder, + _bool, + _char, + _uchar, + _short, + _ushort, + _int, + _uint, + _long, + _ulong, + _float, + _double +} + +obj type (Object) { + var base: base_type + var indirection: int + var is_ref: bool + fun construct(): *type { + base.copy_construct(&base_type::_unknown()) + indirection = 0 + is_ref = false + return this + } + fun construct(base_in: base_type, indirection_in: int, is_ref_in: bool): *type { + base.copy_construct(&base_in) + indirection = indirection_in + is_ref = is_ref_in + return this + } + fun copy_construct(old: *type) { + base.copy_construct(&old->base) + indirection = old->indirection + is_ref = old->is_ref + } + fun operator=(other: ref type) { + destruct() + copy_construct(&other) + } + fun destruct() { + base.destruct() + } + fun operator!=(other: ref type):bool return !equality(other, true); + fun operator==(other: ref type):bool return equality(other, true); + fun equality(other: *type, care_about_ref: bool):bool return equality(*other, care_about_ref); + fun equality(other: ref type, care_about_ref: bool):bool { + if (care_about_ref && (is_ref != other.is_ref)) + return false + return base == other.base && indirection == other.indirection + } + fun to_string(): str { + var indr_string = str("") + if (is_ref) + indr_string += " ref " + for (var i = 0; i < indirection; i++;) indr_string += "*" + match (base) { + base_type::_unknown() return indr_string + "_unknown" + base_type::_void() return indr_string + "_void" + base_type::_object(b) { + return indr_string + "_object" + } + base_type::_function(b) { + // triple, is_variadic, is raw> + return indr_string + "_function()" + } + base_type::_template_placeholder() return indr_string + "_template_placeholder" + base_type::_bool() return indr_string + "_bool" + base_type::_char() return indr_string + "_char" + base_type::_uchar() return indr_string + "_uchar" + base_type::_short() return indr_string + "_short" + base_type::_ushort() return indr_string + "_ushort" + base_type::_int() return indr_string + "_int" + base_type::_uint() return indr_string + "_uint" + base_type::_long() return indr_string + "_long" + base_type::_ulong() return indr_string + "_ulong" + base_type::_float() return indr_string + "_float" + base_type::_double() return indr_string + "_double" + } + return str("impossible type, indirection:") + indirection + } + fun is_unknown(): bool { + match (base) { + base_type::_unknown() return true + } + return false + } + fun is_void(): bool { + match (base) { + base_type::_void() return true + } + return false + } + fun is_object(): bool { + match (base) { + base_type::_object() return true + } + return false + } + fun is_function(): bool { + match (base) { + base_type::_function() return true + } + return false + } + fun is_template_placeholder(): bool { + match (base) { + base_type::_template_placeholder() return true + } + return false + } + fun is_bool(): bool { + match (base) { + base_type::_bool() return true + } + return false + } + fun is_char(): bool { + match (base) { + base_type::_char() return true + } + return false + } + fun is_uchar(): bool { + match (base) { + base_type::_uchar() return true + } + return false + } + fun is_short(): bool { + match (base) { + base_type::_short() return true + } + return false + } + fun is_ushort(): bool { + match (base) { + base_type::_ushort() return true + } + return false + } + fun is_int(): bool { + match (base) { + base_type::_int() return true + } + return false + } + fun is_uint(): bool { + match (base) { + base_type::_uint() return true + } + return false + } + fun is_long(): bool { + match (base) { + base_type::_long() return true + } + return false + } + fun is_ulong(): bool { + match (base) { + base_type::_ulong() return true + } + return false + } + fun is_float(): bool { + match (base) { + base_type::_float() return true + } + return false + } + fun is_double(): bool { + match (base) { + base_type::_double() return true + } + return false + } + fun is_signed(): bool { + match (base) { + base_type::_char() return true + base_type::_int() return true + base_type::_long() return true + base_type::_short() return true + base_type::_float() return true + base_type::_double() return true + + base_type::_uchar() return false + base_type::_ushort() return false + base_type::_uint() return false + base_type::_ulong() return false + } + return false + } +} +