Big changes to k - now all passes are top-level-item focused, does dead simple scope lookup. Added an error message when trying to match on not an ADT

This commit is contained in:
Nathan Braswell
2018-09-17 23:36:26 -04:00
parent 0cad409b07
commit 0e0ca8d7b4
4 changed files with 266 additions and 97 deletions

264
k.krak
View File

@@ -87,32 +87,95 @@ fun main(argc: int, argv: **char): int {
var name_ast_map = map<str, *tree<ast>>()
var passes = map<str, fun(*tree<ast>): void>()
// resolves all reachable imports
passes[str("import")] = fun(import_binding: *tree<ast>) {
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)
name_ast_map[file_path] = syntax_to_ast(file_path, parse_tree, import_paths)
}
set_bindings(import_binding, name_ast_map[file_path])
name_ast_map[file_path]->children.for_each(fun(n: *tree<ast>) {
match (n->data) {
ast::_import(b) {
pass_poset.add_close_dep(make_pair(import_binding, str("import")), make_pair(b.first, str("import")))
// resolves all binding possibilities for one top level item
passes[str("name_possibility_resolve")] = fun(item: *tree<ast>) {
println("Running name possibility resolver?")
var scope_lookup: fun(*tree<ast>, str, bool): vec<*tree<ast>> = fun(scope: *tree<ast>, name: str, is_type: bool): vec<*tree<ast>> {
var to_ret = vec<*tree<ast>>()
for (var i = 0; i < scope->children.size; i++;) {
match(scope->children[i]->data) {
ast::_import(b) if b.second.contains(name) || b.second.contains(str("*")) {
if !bound(b.first) {
// Import / parse file if not already
var file_path = binding_str(b.first)
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)
name_ast_map[file_path] = syntax_to_ast(file_path, parse_tree, import_paths)
}
set_binding(b.first, name_ast_map[file_path])
}
to_ret += scope_lookup(get_binding(b.first), name, is_type)
}
ast::_type_def(b) if (is_type && b == name)
to_ret += scope->children[i]
ast::_adt_def(b) if (is_type && b == name)
to_ret += scope->children[i]
ast::_function(b) if (!is_type && b.first == name)
to_ret += scope->children[i]
ast::_template(b) if (!is_type && b.first == name)
to_ret += scope->children[i]
ast::_identifier(b) if (!is_type && b.first == name)
to_ret += scope->children[i]
ast::_declaration() if (!is_type && scope->children[i]->children[0]->data._identifier.first == name)
to_ret += scope->children[i]->children[0]
}
}
})
if (scope->parent != null<tree<ast>>())
return to_ret + scope_lookup(scope->parent, name, is_type)
return to_ret
}
var try_binding = fun(binding: *tree<ast>, start_scope: *tree<ast>, type_binding: bool) {
if !bound(binding) {
var options = scope_lookup(start_scope, binding->data._binding.first, type_binding)
if (options.size != 1)
error("Do not have exactly one option for scope lookup of " + binding->data._binding.first)
set_binding(binding, options[0])
}
}
var handle_type: fun(*type, *tree<ast>): void = fun(t: *type, n: *tree<ast>) {
match(t->base) {
base_type::_obj(b) try_binding(b, n, true)
base_type::_fun(b) {
b.first.first.for_each(fun(it: *type) {
handle_type(it, n)
})
handle_type(b.first.second, n)
}
}
}
var traverse_for_bindings: fun(*tree<ast>): void = fun(t: *tree<ast>) {
match (t->data) {
// TODO: Handle type binding lookup
ast::_identifier(b) handle_type(b.second, t)
/*_binding: triple<str, vec<*type>, *tree<ast>>,*/
ast::_function(b) handle_type(b.second, t)
ast::_compiler_intrinsic(b) b.second.for_each(fun(ty: *type) {
handle_type(ty, t)
})
ast::_cast(b) handle_type(b, t)
/*_value: pair<str, *type>*/
ast::_binding(b) try_binding(t, t, false)
}
t->children.for_each(traverse_for_bindings)
}
traverse_for_bindings(item)
}
// resolves all binding possibilities for one top level item
passes[str("name_type_resolve")] = fun(item: *tree<ast>) {
println("Running name type resolver?")
// just temp
pass_poset.add_close_dep(make_pair(item, str("name_type_resolve")), make_pair(item, str("name_possibility_resolve")))
}
// emit C
var C_str = str()
passes[str("emit_C")] = fun(import_binding: *tree<ast>) {
if !pass_poset.done(make_pair(import_binding, str("import"))) {
pass_poset.add_open_dep(make_pair(import_binding, str("emit_C")), make_pair(import_binding, str("import")))
var C_func_declaration_str = str()
passes[str("emit_C")] = fun(item: *tree<ast>) {
if !pass_poset.done(make_pair(item, str("name_type_resolve"))) {
pass_poset.add_open_dep(make_pair(item, str("emit_C")), make_pair(item, str("name_type_resolve")))
return
}
@@ -122,25 +185,34 @@ fun main(argc: int, argv: **char): int {
error("type is ref in to_c_type")
match(t->base) {
base_type::_unknown() error("unknown in to_c_type")
base_type::_void() return "void" + ind
base_type::_void() return "void" + ind
base_type::_obj(b) error("ob in to_c_type unimplemented")
base_type::_fun(b) error("fun in to_c_type unimplemented")
base_type::_template_placeholder() error("template_placeholder in to_c_type")
base_type::_bool() return "bool" + ind
base_type::_char() return "char" + ind
base_type::_uchar() return "usigned char" + ind
base_type::_short() return "short" + ind
base_type::_ushort() return "unsigned short" + ind
base_type::_int() return "int" + ind
base_type::_uint() return "unsigned int" + ind
base_type::_long() return "long" + ind
base_type::_ulong() return "unsigned long" + ind
base_type::_float() return "float" + ind
base_type::_double() return "double" + ind
base_type::_bool() return "bool" + ind
base_type::_char() return "char" + ind
base_type::_uchar() return "usigned char" + ind
base_type::_short() return "short" + ind
base_type::_ushort() return "unsigned short" + ind
base_type::_int() return "int" + ind
base_type::_uint() return "unsigned int" + ind
base_type::_long() return "long" + ind
base_type::_ulong() return "unsigned long" + ind
base_type::_float() return "float" + ind
base_type::_double() return "double" + ind
}
error("fell through to_c_type")
}
var emit_name = fun(x: *tree<ast>): void {
match(x->data) {
ast::_identifier(b) { C_str += b.first; return; }
ast::_type_def(b) { C_str += b; return; }
ast::_function(b) { C_str += b.first; return; }
}
error("cannot emit_name of thing: " + to_string(x->data))
}
var emit_C: fun(*tree<ast>, int): void = fun(t: *tree<ast>, level: int) {
var idt = str("\t") * level
match (t->data) {
@@ -150,41 +222,60 @@ fun main(argc: int, argv: **char): int {
C_str += ";\n"
})
}
ast::_import(b) {
pass_poset.add_close_dep(make_pair(import_binding, str("emit_C")), make_pair(b.first, str("emit_C")))
}
ast::_import(b) { }
ast::_identifier(b) { C_str += idt + b.first; }
ast::_binding(b) { error("binding gen unimplemented"); }
ast::_binding(b) {
if (is_top_level_item(b.third))
pass_poset.add_close_dep(make_pair(item, str("emit_C")), make_pair(b.third, str("emit_C")))
emit_name(b.third)
}
ast::_type_def(b) { error("type_def gen unimplemented"); }
ast::_adt_def(b) { error("no adt_def should remain at C emit"); }
ast::_function(b) {
var fun_name = b.first
var fun_type = b.second
var is_ext = b.third
var return_type = fun_type->base._fun.first.second
var parameter_types = fun_type->base._fun.first.first
var is_variadic = fun_type->base._fun.second
var is_raw = fun_type->base._fun.third
C_str += to_c_type(return_type) + " " + fun_name + " ("
// TODO check is_ext for name mangling
C_str += to_c_type(return_type) + " " + fun_name + "("
C_func_declaration_str += to_c_type(return_type) + " " + fun_name + "("
for (var i = 0; i < parameter_types.size; i++;) {
if (i != 0)
C_str += ", "
C_str += to_c_type(parameter_types[i]) + " "
if (i != 0) {
C_str += ", "
C_func_declaration_str += ", "
}
C_str += to_c_type(parameter_types[i]) + " "
C_func_declaration_str += to_c_type(parameter_types[i])
emit_C(t->children[i], 0)
}
if (is_variadic) {
if (parameter_types.size != 0)
if (parameter_types.size != 0) {
C_str += ", "
C_str += "..."
C_func_declaration_str += ", "
}
C_str += "..."
C_func_declaration_str += "..."
}
C_str += ") {\n"
C_str += ") {\n"
C_func_declaration_str += ");\n"
for (var i = parameter_types.size; i < t->children.size; i++;) {
emit_C(t->children[i], level+1)
C_str += ";\n"
}
C_str += "}"
C_str += "}\n"
}
ast::_template(b) { /* template should be ignored */ }
ast::_declaration() { error("declaration gen unimplemented"); }
ast::_declaration() {
C_str += idt + to_c_type(t->children[0]->data._identifier.second) + " "
emit_name(t->children[0])
if (t->children.size > 1) {
C_str += " = "
emit_C(t->children[1], 0)
}
}
ast::_assignment() { error("assignment gen unimplemented"); }
ast::_block() {
C_str += idt + "{\n"
@@ -192,7 +283,7 @@ fun main(argc: int, argv: **char): int {
emit_C(c, level+1)
C_str += ";\n"
})
C_str += idt + "}\n"
C_str += idt + "}"
}
ast::_if() { error("if gen unimplemented"); }
ast::_match() { error("no match should remain at C emit"); }
@@ -209,25 +300,54 @@ fun main(argc: int, argv: **char): int {
ast::_break() { C_str += idt + "break"; }
ast::_continue() { C_str += idt + "continue"; }
ast::_defer() { error("no defer should remain at C emit"); }
ast::_call() { error("call gen unimplemented"); }
ast::_call() {
emit_C(t->children[0], level)
C_str += "("
for (var i = 1; i < t->children.size; i++;) {
if (i != 1)
C_str += ", "
emit_C(t->children[1], level+1)
}
C_str += ")"
}
ast::_compiler_intrinsic(b) { error("compiler_intrinsic gen unimplemented"); }
ast::_cast(b) { error("cast gen unimplemented"); }
ast::_value(b) { C_str += idt + b.first; }
}
}
var file_path = binding_str(import_binding)
println("Running emit C for " + file_path)
emit_C(name_ast_map[file_path], 0)
emit_C(item, 0)
}
var top_binding = make_binding(kraken_file_name)
pass_poset.add_job(make_pair(top_binding, str("emit_C")))
// We construct our real main entry function and add an emit_C pass for it,
// starting generation of the entire program
var real_main = _function(
str("main"),
type(base_type::_fun(make_triple(make_pair(vec(
type(base_type::_int(), 0, false),
type(base_type::_char(), 2, false)
),
type(base_type::_int(), 0, false)
), false, false)), 0, false),
true, vec(
_identifier(str("argc"), type(base_type::_int(), 0, false)),
_identifier(str("argv"), type(base_type::_char(), 2, false)),
_return(vec(_call(vec(make_binding("fmain")))))
)
)
var top_unit = _translation_unit(str(), vec(
_import(make_binding(kraken_file_name), set(str("*")), vec(
_identifier(kraken_file_name, type(base_type::_void(), 0, false))
)),
real_main
))
pass_poset.add_job(make_pair(real_main, str("emit_C")))
pass_poset.run(fun(file_pass: pair<*tree<ast>, str>) {
printlnerr("doing pass new style " + file_pass.second + " on " + to_string(file_pass.first->data))
passes[file_pass.second](file_pass.first)
})
C_str = C_func_declaration_str + "\n" + C_str
println()
println()
@@ -252,44 +372,6 @@ fun main(argc: int, argv: **char): int {
return 0
}
var bindings: *vec<*tree<ast>>
fun make_binding(s: str): *tree<ast> {
var binding = _binding(s, vec<*type>(), null<tree<ast>>())
if (bindings == null<vec<*tree<ast>>>())
bindings = new<vec<*tree<ast>>>()->construct()
bindings->add(binding)
return binding
}
fun set_bindings(binding: *tree<ast>, to: *tree<ast>) {
match(binding->data) {
ast::_binding(b) {
var from = b.third
// don't set null, that will set all unbound ones
if (from == null<tree<ast>>()) {
b.third = to
return
}
for (var i = 0; i < bindings->size; i++;)
if (bindings->get(i)->data._binding.third == from)
bindings->get(i)->data._binding.third = to
return
}
}
error("trying to set bindings on not a binding")
}
fun bound(binding: *tree<ast>): bool {
match(binding->data) {
ast::_binding(b) return b.third != null<tree<ast>>()
}
error("Trying to check bound for not a binding")
}
fun binding_str(binding: *tree<ast>): str {
match(binding->data) {
ast::_binding(b) return b.first
}
error("Trying to get name for not a binding")
}
fun parse_type(syntax: *tree<symbol>): *type {
var is_ref = get_node("\"ref\"", syntax) != null<tree<symbol>>()
var indr = 0
@@ -373,7 +455,7 @@ fun syntax_to_ast(file_name: str, syntax: *tree<symbol>, import_paths: ref vec<s
else
return_type = type(base_type::_void(), 0, false)
var function_type = type(base_type::_fun(make_triple(make_pair(parameters.map(fun(i: *tree<ast>): *type return i->data._identifier.second;), return_type), false, false)), 0, false)
var n = _function(concat(get_node("func_identifier", syntax)), function_type, parameters + body)
var n = _function(concat(get_node("func_identifier", syntax)), function_type, false, parameters + body)
var template = get_node("template_dec", syntax)
if (template == null<tree<symbol>>()) {
return n

View File

@@ -151,6 +151,8 @@ fun adt_lower(name_ast_map: *map<str, pair<*tree<symbol>,*ast_node>>, ast_to_syn
block->code_block.children.add(_assign(holder, make_operator_call("&", vec(value))))
backing.cases.for_each(fun(case_stmt: *ast_node) {
var option = case_stmt->case_statement.option
if (!get_ast_scope(get_ast_type(value)->type_def)->contains_key(str("flag")))
error("trying to get flag from struct without it - are you matching on not an adt? - ")
var flag = get_from_scope(get_ast_type(value)->type_def, "flag")
var data = get_from_scope(get_ast_type(value)->type_def, "data")
var option_num = -7

View File

@@ -13,7 +13,7 @@ adt ast {
_binding: triple<str, vec<*type>, *tree<ast>>,
_type_def: str,
_adt_def: str,
_function: pair<str, *type>,
_function: triple<str, *type, bool>,
_template: pair<str, set<str>>,
_declaration,
_assignment,
@@ -40,7 +40,7 @@ fun to_string(a: ref ast): str {
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 + ": " + deref_to_string(b.second) + ")"
ast::_function(b) return str("_function(") + b.first + ": " + deref_to_string(b.second) + ", ext?:" + to_string(b.third) + ")"
ast::_template(b) return str("_template(") + b.first + "[" + str(",").join(b.second.data) + "])"
ast::_declaration() return str("_declaration")
ast::_assignment() return str("_assignment")
@@ -81,8 +81,8 @@ fun _identifier(p1: str, p2: *type): *tree<ast> {
fun _binding(p1: str, p2: vec<*type>, p3: *tree<ast>): *tree<ast> {
return new<tree<ast>>()->construct(ast::_binding(make_triple(p1, p2, p3)))
}
fun _function(p1: str, p2: *type): *tree<ast> {
return new<tree<ast>>()->construct(ast::_function(make_pair(p1, p2)))
fun _function(p1: str, p2: *type, p3: bool): *tree<ast> {
return new<tree<ast>>()->construct(ast::_function(make_triple(p1, p2, p3)))
}
fun _template(p1: str, p2: set<str>): *tree<ast> {
return new<tree<ast>>()->construct(ast::_template(make_pair(p1, p2)))
@@ -156,8 +156,8 @@ fun _identifier(p1: str, p2: *type, c: ref vec<*tree<ast>>): *tree<ast> {
fun _binding(p1: str, p2: vec<*type>, p3: *tree<ast>, c: ref vec<*tree<ast>>): *tree<ast> {
return new<tree<ast>>()->construct(ast::_binding(make_triple(p1, p2, p3)), c)
}
fun _function(p1: str, p2: *type, c: ref vec<*tree<ast>>): *tree<ast> {
return new<tree<ast>>()->construct(ast::_function(make_pair(p1, p2)), c)
fun _function(p1: str, p2: *type, p3: bool, c: ref vec<*tree<ast>>): *tree<ast> {
return new<tree<ast>>()->construct(ast::_function(make_triple(p1, p2, p3)), c)
}
fun _template(p1: str, p2: set<str>, c: ref vec<*tree<ast>>): *tree<ast> {
return new<tree<ast>>()->construct(ast::_template(make_pair(p1, p2)), c)
@@ -207,3 +207,81 @@ fun _defer(c: ref vec<*tree<ast>>): *tree<ast> {
fun _call(c: ref vec<*tree<ast>>): *tree<ast> {
return new<tree<ast>>()->construct(ast::_call(), c)
}
fun is_translation_unit(i: *tree<ast>): bool { match(i->data) { ast::_translation_unit(b) return true; } return false; }
fun is_import(i: *tree<ast>): bool { match(i->data) { ast::_import(b) return true; } return false; }
fun is_identifier(i: *tree<ast>): bool { match(i->data) { ast::_identifier(b) return true; } return false; }
fun is_binding(i: *tree<ast>): bool { match(i->data) { ast::_binding(b) return true; } return false; }
fun is_type_def(i: *tree<ast>): bool { match(i->data) { ast::_type_def(b) return true; } return false; }
fun is_adt_def(i: *tree<ast>): bool { match(i->data) { ast::_adt_def(b) return true; } return false; }
fun is_function(i: *tree<ast>): bool { match(i->data) { ast::_function(b) return true; } return false; }
fun is_template(i: *tree<ast>): bool { match(i->data) { ast::_template(b) return true; } return false; }
fun is_declaration(i: *tree<ast>): bool { match(i->data) { ast::_declaration() return true; } return false; }
fun is_assignment(i: *tree<ast>): bool { match(i->data) { ast::_assignment() return true; } return false; }
fun is_block(i: *tree<ast>): bool { match(i->data) { ast::_block() return true; } return false; }
fun is_if(i: *tree<ast>): bool { match(i->data) { ast::_if() return true; } return false; }
fun is_match(i: *tree<ast>): bool { match(i->data) { ast::_match() return true; } return false; }
fun is_case(i: *tree<ast>): bool { match(i->data) { ast::_case() return true; } return false; }
fun is_while(i: *tree<ast>): bool { match(i->data) { ast::_while() return true; } return false; }
fun is_for(i: *tree<ast>): bool { match(i->data) { ast::_for() return true; } return false; }
fun is_return(i: *tree<ast>): bool { match(i->data) { ast::_return() return true; } return false; }
fun is_break(i: *tree<ast>): bool { match(i->data) { ast::_break() return true; } return false; }
fun is_continue(i: *tree<ast>): bool { match(i->data) { ast::_continue() return true; } return false; }
fun is_defer(i: *tree<ast>): bool { match(i->data) { ast::_defer() return true; } return false; }
fun is_call(i: *tree<ast>): bool { match(i->data) { ast::_call() return true; } return false; }
fun is_compiler_intrinsic(i: *tree<ast>): bool { match(i->data) { ast::_compiler_intrinsic(b) return true; } return false; }
fun is_cast(i: *tree<ast>): bool { match(i->data) { ast::_cast(b) return true; } return false; }
fun is_value(i: *tree<ast>): bool { match(i->data) { ast::_value(b) return true; } return false; }
fun is_top_level_item(i: *tree<ast>): bool { return i->parent != null<tree<ast>>() && is_translation_unit(i->parent); }
var bindings: *vec<*tree<ast>>
fun make_binding(s: *char): *tree<ast> {
return make_binding(str(s))
}
fun make_binding(s: str): *tree<ast> {
var binding = _binding(s, vec<*type>(), null<tree<ast>>())
if (bindings == null<vec<*tree<ast>>>())
bindings = new<vec<*tree<ast>>>()->construct()
bindings->add(binding)
return binding
}
fun get_binding(binding: *tree<ast>): *tree<ast> {
match(binding->data) {
ast::_binding(b) {
return b.third
}
}
error("trying to get binding on not a binding")
}
fun set_binding(binding: *tree<ast>, to: *tree<ast>) {
match(binding->data) {
ast::_binding(b) {
var from = b.third
// don't set null, that will set all unbound ones
if (from == null<tree<ast>>()) {
b.third = to
return
}
for (var i = 0; i < bindings->size; i++;)
if (bindings->get(i)->data._binding.third == from)
bindings->get(i)->data._binding.third = to
return
}
}
error("trying to set binding on not a binding")
}
fun bound(binding: *tree<ast>): bool {
match(binding->data) {
ast::_binding(b) return b.third != null<tree<ast>>()
}
error("Trying to check bound for not a binding")
}
fun binding_str(binding: *tree<ast>): str {
match(binding->data) {
ast::_binding(b) return b.first
}
error("Trying to get name for not a binding")
}

View File

@@ -3,21 +3,28 @@ import vec
obj tree<T> (Object) {
var data: T
var parent: *tree<T>
var children: vec::vec<*tree<T>>
fun construct(dataIn: T): *tree<T> {
mem::maybe_copy_construct(&data, &dataIn)
parent = mem::null<tree<T>>()
children.construct()
return this
}
fun construct(dataIn: T, c: ref vec::vec<*tree<T>>): *tree<T> {
mem::maybe_copy_construct(&data, &dataIn)
parent = mem::null<tree<T>>()
children.copy_construct(&c)
children.for_each(fun(i: *tree<T>) {
i->parent = this
})
return this
}
// Some of these don't really make much sense considering this tree is all about
// heap allocated pointers. Best to have it for saftey, though
fun copy_construct(old: *tree<T>) {
mem::maybe_copy_construct(&data, &old->data)
parent = old->parent
children.copy_construct(&old->children)
}
// ditto