From 29eff2a23e5c8afc59dc71a9ecd74cedbd5663c3 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 22 Jun 2016 01:41:57 -0700 Subject: [PATCH] Fix defer_lower to handle return statements, starting on obj_lower which has now taken over calling destruct for declared varaibles. Some of the code from the c_generator has been commented out or bypassed to use the new system - it should be removed when it's complete. --- kraken.krak | 3 ++ stdlib/ast_nodes.krak | 5 ++ stdlib/c_generator.krak | 16 ++++++- stdlib/defer_lower.krak | 23 +++++++++ stdlib/obj_lower.krak | 44 +++++++++++++++++ stdlib/pass_common.krak | 104 ++++++++++++++++++++++++++++++---------- 6 files changed, 169 insertions(+), 26 deletions(-) create mode 100644 stdlib/obj_lower.krak diff --git a/kraken.krak b/kraken.krak index cffec54..3ab08ff 100644 --- a/kraken.krak +++ b/kraken.krak @@ -10,6 +10,7 @@ import interpreter:* import os:* import ast_transformation:* import adt_lower:* +import obj_lower:* import defer_lower:* import c_line_control:* import c_generator:* @@ -102,6 +103,8 @@ fun main(argc: int, argv: **char):int { // Passes printlnerr("Lowering ADTs") adt_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) + printlnerr("Lowering Objects") + obj_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) printlnerr("Lowering Defer") defer_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) if (interpret_instead) { diff --git a/stdlib/ast_nodes.krak b/stdlib/ast_nodes.krak index 69bd3b2..50f4e05 100644 --- a/stdlib/ast_nodes.krak +++ b/stdlib/ast_nodes.krak @@ -417,6 +417,11 @@ obj template (Object) { instantiated_map == other.instantiated_map && is_function == other.is_function } } +fun ast_code_block_ptr(stmt: *ast_node): *ast_node { + var to_ret = ast_code_block_ptr() + to_ret->code_block.children.add(stmt) + return to_ret +} fun ast_code_block_ptr(): *ast_node { var to_ret.construct(): code_block var ptr = new() diff --git a/stdlib/c_generator.krak b/stdlib/c_generator.krak index d959f28..91bbade 100644 --- a/stdlib/c_generator.krak +++ b/stdlib/c_generator.krak @@ -431,8 +431,8 @@ obj c_generator (Object) { to_ret += code_triple() + generate(node->declaration_statement.init_method_call, enclosing_object, enclosing_func, null>>>(), false) } // reference can happen because some passes generate them (adt_lower right now) - if (add_to_defer && !ident_type->is_ref && ident_type->indirection == 0 && (ident_type->is_object() && has_method(ident_type->type_def, "destruct", vector<*type>()))) - defer_stack->top().second.push(ast_statement_ptr(make_method_call(identifier, "destruct", vector<*ast_node>()))) + /*if (add_to_defer && !ident_type->is_ref && ident_type->indirection == 0 && (ident_type->is_object() && has_method(ident_type->type_def, "destruct", vector<*type>())))*/ + /*defer_stack->top().second.push(ast_statement_ptr(make_method_call(identifier, "destruct", vector<*ast_node>())))*/ return to_ret } fun generate_assignment_statement(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): code_triple { @@ -492,6 +492,18 @@ obj c_generator (Object) { var return_value = node->return_statement.return_value var function_return_type = get_ast_type(enclosing_func)->return_type var to_ret = code_triple() + + // new one + to_ret += code_triple("return") + var refamp = string() + if (function_return_type->is_ref) + refamp = "&" + if (return_value) + to_ret += code_triple(" ") + refamp + generate(return_value, enclosing_object, enclosing_func, null>>>(), false) + to_ret.pre += generate_from_defer_stack(defer_stack, -1, enclosing_object, enclosing_func).one_string() + return to_ret + + if (return_value) { var return_value_type = get_ast_type(return_value) // always need a return temp so we don't destruct things the return depends on before they're calculated diff --git a/stdlib/defer_lower.krak b/stdlib/defer_lower.krak index ace5dd3..c79b426 100644 --- a/stdlib/defer_lower.krak +++ b/stdlib/defer_lower.krak @@ -12,6 +12,7 @@ import ast_transformation:* import pass_common:* fun defer_lower(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { + var enclosing_function = null() name_ast_map->for_each(fun(name: string, syntax_ast_pair: pair<*tree,*ast_node>) { var defer_double_stack = stack>() var loop_stack = stack(-1) @@ -36,6 +37,9 @@ fun defer_lower(name_ast_map: *map,*ast_node>>, ast_t ast_node::while_loop(backing) { loop_stack.push(defer_double_stack.size()) } + ast_node::function(backing) { + enclosing_function = node + } } } var helper_after = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { @@ -47,6 +51,25 @@ fun defer_lower(name_ast_map: *map,*ast_node>>, ast_t block->code_block.children.add_all(defer_double_stack.from_top(i).reverse_vector()) block->code_block.children.add(ast_statement_ptr(node)) } + ast_node::return_statement(backing) { + var block = ast_code_block_ptr() + replace_with_in(node, block, parent_chain) + var return_value = node->return_statement.return_value + if (return_value) { + if (get_ast_type(enclosing_function)->return_type->is_ref) + return_value = make_operator_call("&", vector(return_value)) + var temp_return = ast_identifier_ptr("temp_boom_return", get_ast_type(return_value)->clone_without_ref(), block) + block->code_block.children.add(ast_statement_ptr(ast_declaration_statement_ptr(temp_return, null(), false))) + block->code_block.children.add(ast_statement_ptr(assign_or_copy_construct_statement(temp_return, return_value))) + // dereference so that the real ref can take it back + if (get_ast_type(enclosing_function)->return_type->is_ref) + temp_return = make_operator_call("*", vector(temp_return)) + node->return_statement.return_value = temp_return + } + for (var i = 0; i < defer_double_stack.size(); i++;) + block->code_block.children.add_all(defer_double_stack.from_top(i).reverse_vector()) + block->code_block.children.add(ast_statement_ptr(node)) + } ast_node::code_block(backing) { node->code_block.children.add_all(defer_double_stack.pop().reverse_vector()) } diff --git a/stdlib/obj_lower.krak b/stdlib/obj_lower.krak new file mode 100644 index 0000000..e6dd1ae --- /dev/null +++ b/stdlib/obj_lower.krak @@ -0,0 +1,44 @@ +import symbol:* +import tree:* +import vector:* +import map:* +import util:* +import string:* +import mem:* +import io:* +import ast_nodes:* +import ast_transformation:* + +import pass_common:* + +fun obj_lower(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { + name_ast_map->for_each(fun(name: string, syntax_ast_pair: pair<*tree,*ast_node>) { + var helper_before = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { + match(*node) { + ast_node::type_def(backing) { + /*println(backing.name + ": enter")*/ + } + } + } + var helper_after = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { + match(*node) { + ast_node::type_def(backing) { + /*println(backing.name + ": exit")*/ + } + ast_node::declaration_statement(backing) { + var ident_type = get_ast_type(backing.identifier) + if (is_translation_unit(parent_chain->top()) || is_type_def(parent_chain->top())) + return; + if (!ident_type->is_ref && ident_type->indirection == 0 && (ident_type->is_object() && has_method(ident_type->type_def, "destruct", vector<*type>()))) { + ensure_enclosing_statement_scope_is_block(parent_chain) + // have to go up one because our parent is a statement + add_after_in(ast_statement_ptr(ast_defer_statement_ptr(ast_statement_ptr(make_method_call(backing.identifier, "destruct", vector<*ast_node>())))), parent_chain->top(), parent_chain->from_top(1)) + } + /*println(backing.name + ": exit")*/ + } + } + } + run_on_tree(helper_before, helper_after, syntax_ast_pair.second) + }) +} + diff --git a/stdlib/pass_common.krak b/stdlib/pass_common.krak index 4de568c..bbb5007 100644 --- a/stdlib/pass_common.krak +++ b/stdlib/pass_common.krak @@ -95,42 +95,98 @@ fun add_before_in(to_add: *ast_node, before: *ast_node, in: *ast_node) { } error(string("cannot add_before_in to ") + get_ast_name(in)) } +fun add_after_in(to_add: *ast_node, before: *ast_node, in: *stack<*ast_node>) + add_after_in(to_add, before, in->top()) +fun add_after_in(to_add: *ast_node, before: *ast_node, in: *ast_node) { + var bc = get_children_pointer(in) + if (bc) { + var i = bc->find(before) + if (i >= 0) { + bc->add(to_add, i+1) + return + } + } + error(string("cannot add_after_in to ") + get_ast_name(in)) +} + +// only works for statements (not for loop init, etc) +fun ensure_enclosing_statement_scope_is_block(parent_chain: *stack<*ast_node>) { + var node = parent_chain->top() + match (*node) { + ast_node::for_loop(backing) { + var old = backing.body + if (!is_statement(old)) + error("for loop body is not statement") + if (!is_code_block(old->statement.child)) { + var block = ast_code_block_ptr(old) + var stmt = ast_statement_ptr(block); + parent_chain->push(stmt) + parent_chain->push(block) + node->for_loop.body = stmt + } + return + } + ast_node::while_loop(backing) { + var old = backing.statement + if (!is_statement(old)) + error("while loop body is not statement") + if (!is_code_block(old->statement.child)) { + var block = ast_code_block_ptr(old) + var stmt = ast_statement_ptr(block); + parent_chain->push(stmt) + parent_chain->push(block) + node->while_loop.statement = stmt + } + return + } + ast_node::code_block(backing) return + ast_node::if_statement(backing) error("ensure enclosing statment can't do if_statement yet") + ast_node::function(backing) error("ensure enclosing statment can't do function yet") + } + var old = parent_chain->pop() + if (parent_chain->empty()) + error("hit top of parent chain in ensure_enclosing_statement_scope_is_block") + ensure_enclosing_statement_scope_is_block(parent_chain) + parent_chain->push(old) +} fun empty_pass_half(node: *ast_node, parent_chain: *stack<*ast_node>) {} fun run_on_tree(func_before: fun(*ast_node,*stack<*ast_node>):void, func_after: fun(*ast_node,*stack<*ast_node>):void, tree: *ast_node) { var parent_stack = stack<*ast_node>() - run_on_tree_helper(func_before, func_after, tree, &parent_stack) + run_on_tree_helper(func_before, func_after, tree, &parent_stack, false) } -fun run_on_tree_helper(func_before: fun(*ast_node,*stack<*ast_node>):void, func_after: fun(*ast_node,*stack<*ast_node>):void, node: *ast_node, parent_chain: *stack<*ast_node>) { - if (!node) return +fun run_on_tree_helper(func_before: fun(*ast_node,*stack<*ast_node>):void, func_after: fun(*ast_node,*stack<*ast_node>):void, node: *ast_node, parent_chain: *stack<*ast_node>, do_func: bool) { + if (!node || (!do_func && is_function(node))) return func_before(node, parent_chain) parent_chain->push(node) match(*node) { - ast_node::translation_unit(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::type_def(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::adt_def(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::function(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::template(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::code_block(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::if_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::match_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::case_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::while_loop(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::for_loop(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::return_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::defer_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::assignment_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::declaration_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) - ast_node::if_comp(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) + ast_node::translation_unit(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, true);) + ast_node::type_def(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, true);) + ast_node::adt_def(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, true);) + ast_node::function(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::template(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, true);) + ast_node::code_block(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::if_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::match_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::case_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::while_loop(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::for_loop(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::return_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::defer_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::assignment_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::declaration_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) + ast_node::if_comp(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, true);) ast_node::function_call(backing) { if (!is_function(backing.func)) - run_on_tree_helper(func_before, func_after, backing.func, parent_chain) - node->function_call.parameters.for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) + run_on_tree_helper(func_before, func_after, backing.func, parent_chain, false) + node->function_call.parameters.for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) } - ast_node::cast(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain);) + ast_node::cast(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, false);) } - parent_chain->pop() + // function may have messed with the parent chain + if (parent_chain->data.contains(node)) + while(parent_chain->pop() != node){} func_after(node, parent_chain) }