From 7543b95529af115454b3e633797b3e284c92d026 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Thu, 10 Mar 2016 04:49:38 -0500 Subject: [PATCH] 60 tests passing --- stdlib/ast_transformation.krak | 28 +++++++++++++++++++++++++++- stdlib/c_generator.krak | 25 ++++++++++++++++++++----- tests/.gitignore | 3 +++ tests/test_close_over_members.krak | 4 ++-- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/stdlib/ast_transformation.krak b/stdlib/ast_transformation.krak index 5cd34d2..ea3bbbd 100644 --- a/stdlib/ast_transformation.krak +++ b/stdlib/ast_transformation.krak @@ -19,14 +19,17 @@ adt search_type { obj ast_transformation (Object) { var ast_to_syntax: map<*ast_node, *tree> + var type_def_to_this: map<*ast_node, *ast_node> var fourth_pass_worklist: queue<*ast_node> fun construct(): *ast_transformation { ast_to_syntax.construct() + type_def_to_this.construct() fourth_pass_worklist.construct() return this } fun copy_construct(old: *ast_transformation) { ast_to_syntax.copy_construct(&old->ast_to_syntax) + type_def_to_this.copy_construct(&old->type_def_to_this) fourth_pass_worklist.copy_construct(&old->fourth_pass_worklist) } fun operator=(old: ref ast_transformation) { @@ -35,6 +38,7 @@ obj ast_transformation (Object) { } fun destruct() { ast_to_syntax.destruct() + type_def_to_this.destruct() fourth_pass_worklist.destruct() } // first pass defines all type_defs (objects and aliases), ADTs, and top-level if-comps/passthroughs @@ -396,12 +400,17 @@ obj ast_transformation (Object) { fun transform_all(nodes: vector<*tree>, scope: *ast_node, template_replacements: map): vector<*ast_node> { return nodes.map(fun(node: *tree): *ast_node return transform(node, scope, template_replacements);) } + fun make_this(object: *ast_node): *ast_node { + if (!type_def_to_this.contains_key(object)) + type_def_to_this[object] = ast_identifier_ptr("this", object->type_def.self_type->clone_with_indirection(1), object) + return type_def_to_this[object] + } fun transform_identifier(node: *tree, scope: *ast_node, searching_for: search_type): *ast_node { // first, we check for and generate this var name = concat_symbol_tree(node) if (name == "this") { while (!is_type_def(scope)) scope = get_ast_scope(scope)->get(string("~enclosing_scope"))[0] - return ast_identifier_ptr("this", scope->type_def.self_type->clone_with_indirection(1), scope) + return make_this(scope) } match (searching_for) { search_type::none() return identifier_lookup(name, scope) @@ -431,6 +440,8 @@ obj ast_transformation (Object) { value_type = type_ptr(base_type::character(), 1) else if (value_str[0] == '\'') //'// lol, comment hack for vim syntax highlighting (my fault, of course) value_type = type_ptr(base_type::character()) + else if (value_str == "true" || value_str == "false") + value_type = type_ptr(base_type::boolean()) else { // should differentiate between float and double... var contains_dot = false @@ -666,10 +677,25 @@ obj ast_transformation (Object) { ast_node::function_call(backing) { println("found an function_call") // XXX should special case . and ->, I think + if (is_function(backing.func) && (backing.func->function.name == "." || backing.func->function.name == ".")) + return find_closed_variables(func, backing.parameters.first()) var to_ret = find_closed_variables(func, backing.func) backing.parameters.for_each(fun(n: *ast_node) to_ret += find_closed_variables(func, n);) return to_ret } + ast_node::function(backing) { + // now if this is a method, it is called without an access operator because we are in a lambda inside another method + // this is because we don't look at the right side of access operators, note the above function_call case + if (backing.scope.contains_key(string("~enclosing_scope"))) { + var enclosing = backing.scope[string("~enclosing_scope")][0] + if (is_type_def(enclosing)) + return set(make_this(enclosing)) + if (is_template(enclosing) && is_type_def(enclosing->template.scope[string("~enclosing_scope")][0])) + return set(make_this(enclosing->template.scope[string("~enclosing_scope")][0])) + } + // we don't close over actual functions + return set<*ast_node>() + } ast_node::return_statement(backing) { println("found an return_statement") return find_closed_variables(func, backing.return_value) diff --git a/stdlib/c_generator.krak b/stdlib/c_generator.krak index 6540ceb..d02914c 100644 --- a/stdlib/c_generator.krak +++ b/stdlib/c_generator.krak @@ -179,7 +179,8 @@ obj c_generator (Object) { var parameter_types = string() var parameters = string() - if (enclosing_object) { + // lambdas can have the enclosing object too, if it's needed (lambda in a method) + if (enclosing_object && backing.closed_variables.size() == 0) { parameter_types = type_to_c(enclosing_object->type_def.self_type) + "*" parameters = type_to_c(enclosing_object->type_def.self_type) + "* this" } @@ -218,7 +219,18 @@ obj c_generator (Object) { name_ast_map.for_each(fun(name: string, tree_pair: pair<*tree,*ast_node>) { // iterate through children for each ast // assert translation_unit? - (tree_pair.second->translation_unit.children + tree_pair.second->translation_unit.lambdas).for_each(fun(child: *ast_node) { + // do lambdas seperatly, so we can reconstitute the enclosing object if it has one + tree_pair.second->translation_unit.lambdas.for_each(fun(child: *ast_node) { + var enclosing_object_traverse = child + while(enclosing_object_traverse && !is_type_def(enclosing_object_traverse) && + get_ast_scope(enclosing_object_traverse) && get_ast_scope(enclosing_object_traverse)->contains_key(string("~enclosing_scope"))) + enclosing_object_traverse = get_ast_scope(enclosing_object_traverse)->get(string("~enclosing_scope"))[0] + if (enclosing_object_traverse && is_type_def(enclosing_object_traverse)) + generate_function_definition(child, enclosing_object_traverse) + else + generate_function_definition(child, null()) + }) + tree_pair.second->translation_unit.children.for_each(fun(child: *ast_node) { match (*child) { // should really check the genrator ast_node::if_comp(backing) { @@ -281,7 +293,7 @@ obj c_generator (Object) { closure_struct_definitions += "typedef struct {\n" // note that we keep our is_ref, which would not normally happen on a clone with increased indirection closed_variables.for_each(fun(i: *ast_node) closure_struct_definitions += type_to_c(i->identifier.type->clone_with_increased_indirection(1,i->identifier.type->is_ref)) + - " " + i->identifier.name + ";\n";) + " " + get_name(i) + ";\n";) closure_struct_definitions += string("} ") + closure_name + ";\n" closure_struct_map[closed_variables] = closure_name } @@ -529,7 +541,10 @@ obj c_generator (Object) { var methods = enclosing_object->type_def.methods for (var i = 0; i < methods.size; i++;) { if (methods[i] == node->function_call.func || (is_template(methods[i]) && methods[i]->template.instantiated.contains(node->function_call.func))) { - call_string += "this"; + if (enclosing_func && enclosing_func->function.closed_variables.size()) + call_string += "(*(closure_data->this))"; + else + call_string += "this"; break } } @@ -589,7 +604,7 @@ obj c_generator (Object) { var param_type = get_ast_type(param) if (param_type->is_object() && !in_function_param_type->is_ref && param_type->indirection == 0 && has_method(param_type->type_def, "copy_construct", vector(param_type->clone_with_indirection(1)))) { - var temp_ident = ast_identifier_ptr(string("temporary_param")+get_id(), param_type, null()) + var temp_ident = ast_identifier_ptr(string("temporary_param")+get_id(), param_type->clone_without_ref(), null()) var declaration = ast_declaration_statement_ptr(temp_ident, null()) // have to pass false to the declaration generator, so can't do it through generate_statement call_string.pre += generate_declaration_statement(declaration, enclosing_object, enclosing_func, null>>>(), false).one_string() + ";\n" diff --git a/tests/.gitignore b/tests/.gitignore index d6b34f6..734aac7 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,6 +1,7 @@ tester test_compiler *.results +*.c test_chainedIndirectTemplates test_functionsValues test_future @@ -8,3 +9,5 @@ test_grammer test_set test_templateFuncInfr test_util +test_close_over_members +test_string diff --git a/tests/test_close_over_members.krak b/tests/test_close_over_members.krak index c4e1585..85a6100 100644 --- a/tests/test_close_over_members.krak +++ b/tests/test_close_over_members.krak @@ -1,6 +1,6 @@ import io:* import set -import mem +import util fun runFunc(func: fun():void) { func() @@ -26,7 +26,7 @@ obj One (Object) { } fun destruct() { var a:One - mem::safe_recursive_delete(&a, fun(it: *One): set::set<*One> { return set::set(it); } ) + util::safe_recursive_delete(&a, fun(it: *One): set::set<*One> { return set::set(it); } ) } }