From daae39fe197f4fcd056e789dfde78906f4f189cd Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Thu, 7 Jan 2016 02:52:22 -0500 Subject: [PATCH] Added in the beginnings of pass three which can parse and emit statements and code blocks --- stdlib/ast_nodes.krak | 8 ++++++-- stdlib/ast_transformation.krak | 25 ++++++++++++++++++++++++- stdlib/c_generator.krak | 13 ++++++++++++- stdlib/util.krak | 3 +++ stdlib/vector.krak | 12 +++++++++--- tests/to_parse.krak | 8 +++----- 6 files changed, 57 insertions(+), 12 deletions(-) diff --git a/stdlib/ast_nodes.krak b/stdlib/ast_nodes.krak index 399cf5d..844fe4f 100644 --- a/stdlib/ast_nodes.krak +++ b/stdlib/ast_nodes.krak @@ -258,17 +258,20 @@ obj function (Object) { var name: string var type: *type var parameters: vector<*ast_node> + var body_statement: *ast_node var scope: map> fun construct(name_in: string, type_in: *type, parameters_in: vector<*ast_node>): *function { name.copy_construct(&name_in) parameters.copy_construct(¶meters_in) scope.construct() type = type_in + body_statement = null() return this } fun copy_construct(old: *function) { name.copy_construct(&old->name) type = old->type + body_statement = old->body_statement parameters.copy_construct(&old->parameters) scope.copy_construct(&old->scope) } @@ -282,7 +285,7 @@ obj function (Object) { copy_construct(&other) } fun operator==(other: ref function): bool { - return name == name && type == other.type && parameters == other.parameters + return name == name && type == other.type && parameters == other.parameters && body_statement == other.body_statement } } fun ast_code_block_ptr(): *ast_node { @@ -337,6 +340,7 @@ obj statement (Object) { var scope: map> var child: *ast_node fun construct(): *statement { + child = null() scope.construct() return this } @@ -849,7 +853,7 @@ fun get_ast_children(node: *ast_node): vector<*ast_node> { ast_node::identifier(backing) return vector<*ast_node>() ast_node::type_def(backing) return vector<*ast_node>() ast_node::adt_def(backing) return vector<*ast_node>() - ast_node::function(backing) return vector<*ast_node>() + ast_node::function(backing) return backing.parameters + backing.body_statement ast_node::code_block(backing) return backing.children ast_node::statement(backing) return vector<*ast_node>(backing.child) ast_node::if_statement(backing) return vector<*ast_node>() diff --git a/stdlib/ast_transformation.krak b/stdlib/ast_transformation.krak index 5e33df6..8bbb875 100644 --- a/stdlib/ast_transformation.krak +++ b/stdlib/ast_transformation.krak @@ -19,16 +19,20 @@ import type:* /*NodeTree* topScope; //maintained for templates that need to add themselves to the top scope no matter where they are instantiated*/ /*int lambdaID = 0;*/ obj ast_transformation (Object) { + var ast_to_syntax: map<*ast_node, *tree> fun construct(): *ast_transformation { + ast_to_syntax.construct() return this } fun copy_construct(old: *ast_transformation) { + ast_to_syntax.copy_construct(&old->ast_to_syntax) } fun operator=(old: ref ast_transformation) { destruct() copy_construct(&old) } fun destruct() { + ast_to_syntax.destruct() } // first pass defines all type_defs (objects and aliases), ADTs, and top-level if-comps/passthroughs fun first_pass(file_name: string, parse_tree: *tree, importer: *importer): *ast_node { @@ -39,6 +43,7 @@ obj ast_transformation (Object) { var name = concat_symbol_tree(get_node("identifier", child)) var type_def_node = ast_type_def_ptr(name) translation_unit->translation_unit.children.add(type_def_node) + ast_to_syntax.set(type_def_node, child) add_to_scope("~enclosing_scope", translation_unit, type_def_node) add_to_scope(name, type_def_node, translation_unit) // set up type - self-referential, traits, template, etc @@ -46,11 +51,13 @@ obj ast_transformation (Object) { var name = concat_symbol_tree(get_node("identifier", child)) var adt_def_node = ast_adt_def_ptr(name) translation_unit->translation_unit.children.add(adt_def_node) + ast_to_syntax.set(adt_def_node, child) add_to_scope("~enclosing_scope", translation_unit, adt_def_node) add_to_scope(name, adt_def_node, translation_unit) } else if (child->data.name == "if_comp") { var if_comp_node = transform_if_comp(child, translation_unit) translation_unit->translation_unit.children.add(if_comp_node) + ast_to_syntax.set(if_comp_node, child) } }) @@ -62,6 +69,7 @@ obj ast_transformation (Object) { var name = concat_symbol_tree(import_identifier_children[0]) var import_node = ast_import_ptr(name) translation_unit->translation_unit.children.add(import_node) + ast_to_syntax.set(import_node, child) add_to_scope("~enclosing_scope", translation_unit, import_node) var outside_translation_unit = importer->import_first_pass(name + ".krak") add_to_scope(name, outside_translation_unit, translation_unit) @@ -80,7 +88,9 @@ obj ast_transformation (Object) { } else if (child->data.name == "adt_def") { // set up options and all the generated functions (operator==, operator!=, copy_construct, operator=, destruct) } else if (child->data.name == "function") { - translation_unit->translation_unit.children.add(second_pass_function(child, translation_unit, map())) + var function_node = second_pass_function(child, translation_unit, map()) + translation_unit->translation_unit.children.add(function_node) + ast_to_syntax.set(function_node, child) } else if (child->data.name == "declaration_statement") { // second pass declaration can actually just call a normal transform (but maybe should be it's own method to do so because typedef has to do it too?)... } @@ -109,9 +119,22 @@ obj ast_transformation (Object) { parameters.for_each(fun(parameter: *ast_node) add_to_scope(parameter->identifier.name, parameter, function_node);) return function_node } + // The third pass finishes up by doing all function bodies (top level and methods in objects) fun third_pass(parse_tree: *tree, translation_unit: *ast_node) { println(string("Third Pass for ") + translation_unit->translation_unit.name) + translation_unit->translation_unit.children.for_each(fun(node: *ast_node) { + match(*node) { + ast_node::type_def(backing) do_nothing() // actually go through and do methods inside + ast_node::function(backing) { + // make sure not a template + // huh, I guess I can't actually assign to the backing. + // This is actually a little bit of a problem, maybe these should be pointers also. All the pointers! + node->function.body_statement = transform_statement(get_node("statement", ast_to_syntax[node]), translation_unit) + } + } + }) } + // The fourth pass generates the class templates that have not yet been generated in a "chaotic iteration" loop fun fourth_pass(parse_tree: *tree, translation_unit: *ast_node) { println(string("Fourth Pass for ") + translation_unit->translation_unit.name) } diff --git a/stdlib/c_generator.krak b/stdlib/c_generator.krak index 5b29c64..7170b0e 100644 --- a/stdlib/c_generator.krak +++ b/stdlib/c_generator.krak @@ -62,7 +62,7 @@ obj c_generator (Object) { function_prototypes += type_to_c(backing.type->return_type) + " " + backing.name + "(" + parameter_types + ");\n" // add parameters to destructor thingy (for returns)? Or should that be a different pass? - function_definitions += type_to_c(backing.type->return_type) + " " + backing.name + "(" + parameters + ") { " + " /* body here */ " + function_definitions += type_to_c(backing.type->return_type) + " " + backing.name + "(" + parameters + ") {\n" + generate_statement(backing.body_statement) // emit parameter destructors? function_definitions += "}\n" } @@ -76,11 +76,22 @@ obj c_generator (Object) { // deal with all the passthrough params return node->simple_passthrough.passthrough_str } + fun generate_statement(node: *ast_node): string return generate(node->statement.child) + ";\n"; + fun generate_code_block(node: *ast_node): string { + var to_ret = string("{\n") + node->code_block.children.for_each(fun(child: *ast_node) to_ret += generate(child);) + return to_ret + "}\n" + } + // for now, anyway fun generate(node: *ast_node): string { + if (!node) return string("/*NULL*/") match (*node) { ast_node::simple_passthrough(backing) return generate_simple_passthrough(node) + ast_node::statement(backing) return generate_statement(node) + ast_node::code_block(backing) return generate_code_block(node) } + return string("/* COULD NOT GENERATE */") } fun type_to_c(type: *type): string { match (type->base) { diff --git a/stdlib/util.krak b/stdlib/util.krak index 9c6ab3b..6451f71 100644 --- a/stdlib/util.krak +++ b/stdlib/util.krak @@ -2,6 +2,9 @@ import mem import vector import serialize +// maybe my favorite function +fun do_nothing() {} + fun max(a: T, b: T): T { if (a > b) return a; diff --git a/stdlib/vector.krak b/stdlib/vector.krak index f8200d5..e5ea470 100644 --- a/stdlib/vector.krak +++ b/stdlib/vector.krak @@ -71,13 +71,19 @@ obj vector (Object, Serializable) { } fun operator+(other:vector):vector { - var newVec.construct():vector - for (var i = 0; i < size; i++;) - newVec.addEnd(get(i)) + // lets be at least a little bit smarter by copy_constructing our copy. + // We could get a lot better than this by initially creating enough space + // for both and copy_constructing all of them, but this is just a quick fix + var newVec.copy_construct(this):vector for (var i = 0; i < other.size; i++;) newVec.addEnd(other.get(i)) return newVec } + fun operator+(other: T):vector { + var newVec.copy_construct(this):vector + newVec.addEnd(other) + return newVec + } fun operator+=(other: T):void { addEnd(other) diff --git a/tests/to_parse.krak b/tests/to_parse.krak index 1b22490..7d54d63 100644 --- a/tests/to_parse.krak +++ b/tests/to_parse.krak @@ -7,10 +7,8 @@ obj Something (ObjectTrait) { } } -fun some_function(): float { - return 0 -} -fun some_other_function(in: bool): int { - return 0 +fun some_function(): int return 0; +fun some_other_function(in: bool): float { + return 0.0 }