Closures working! (in the basic case, anyway)
This commit is contained in:
@@ -77,7 +77,7 @@ obj c_generator (Object) {
|
|||||||
var id_counter: int
|
var id_counter: int
|
||||||
var ast_to_syntax: map<*ast_node, *tree<symbol>>
|
var ast_to_syntax: map<*ast_node, *tree<symbol>>
|
||||||
var ast_name_map: map<*ast_node, string>
|
var ast_name_map: map<*ast_node, string>
|
||||||
var closure_struct_map: map<set<*ast_node>, string>
|
/*var closure_struct_map: map<set<*ast_node>, string>*/
|
||||||
var function_type_map: map<type, string>
|
var function_type_map: map<type, string>
|
||||||
var function_typedef_string: string
|
var function_typedef_string: string
|
||||||
var closure_struct_definitions: string
|
var closure_struct_definitions: string
|
||||||
@@ -89,7 +89,7 @@ obj c_generator (Object) {
|
|||||||
id_counter = 0
|
id_counter = 0
|
||||||
ast_to_syntax.construct()
|
ast_to_syntax.construct()
|
||||||
ast_name_map.construct()
|
ast_name_map.construct()
|
||||||
closure_struct_map.construct()
|
/*closure_struct_map.construct()*/
|
||||||
function_type_map.construct()
|
function_type_map.construct()
|
||||||
function_typedef_string.construct()
|
function_typedef_string.construct()
|
||||||
closure_struct_definitions.construct()
|
closure_struct_definitions.construct()
|
||||||
@@ -148,7 +148,7 @@ obj c_generator (Object) {
|
|||||||
id_counter = old->id_counter
|
id_counter = old->id_counter
|
||||||
ast_to_syntax.copy_construct(&old->ast_to_syntax)
|
ast_to_syntax.copy_construct(&old->ast_to_syntax)
|
||||||
ast_name_map.copy_construct(&old->ast_name_map)
|
ast_name_map.copy_construct(&old->ast_name_map)
|
||||||
closure_struct_map.copy_construct(&old->closure_struct_map)
|
/*closure_struct_map.copy_construct(&old->closure_struct_map)*/
|
||||||
function_type_map.copy_construct(&old->function_type_map)
|
function_type_map.copy_construct(&old->function_type_map)
|
||||||
function_typedef_string.copy_construct(&old->function_typedef_string)
|
function_typedef_string.copy_construct(&old->function_typedef_string)
|
||||||
closure_struct_definitions.copy_construct(&old->closure_struct_definitions)
|
closure_struct_definitions.copy_construct(&old->closure_struct_definitions)
|
||||||
@@ -164,7 +164,7 @@ obj c_generator (Object) {
|
|||||||
fun destruct() {
|
fun destruct() {
|
||||||
ast_to_syntax.destruct()
|
ast_to_syntax.destruct()
|
||||||
ast_name_map.destruct()
|
ast_name_map.destruct()
|
||||||
closure_struct_map.destruct()
|
/*closure_struct_map.destruct()*/
|
||||||
function_type_map.destruct()
|
function_type_map.destruct()
|
||||||
function_typedef_string.destruct()
|
function_typedef_string.destruct()
|
||||||
closure_struct_definitions.destruct()
|
closure_struct_definitions.destruct()
|
||||||
@@ -183,12 +183,12 @@ obj c_generator (Object) {
|
|||||||
parameter_types = type_to_c(enclosing_object->type_def.self_type) + "*"
|
parameter_types = type_to_c(enclosing_object->type_def.self_type) + "*"
|
||||||
parameters = type_to_c(enclosing_object->type_def.self_type) + "* this"
|
parameters = type_to_c(enclosing_object->type_def.self_type) + "* this"
|
||||||
}
|
}
|
||||||
if (backing.closed_variables.size()) {
|
/*if (backing.closed_variables.size()) {*/
|
||||||
if (parameter_types != "") { parameter_types += ", "; parameters += ", ";}
|
/*if (parameter_types != "") { parameter_types += ", "; parameters += ", ";}*/
|
||||||
var closed_type_name = get_closure_struct_type(backing.closed_variables)
|
/*var closed_type_name = get_closure_struct_type(backing.closed_variables)*/
|
||||||
parameter_types += closed_type_name + "*"
|
/*parameter_types += closed_type_name + "*"*/
|
||||||
parameters += closed_type_name + "* closure_data"
|
/*parameters += closed_type_name + "* closure_data"*/
|
||||||
}
|
/*}*/
|
||||||
|
|
||||||
var decorated_name = string()
|
var decorated_name = string()
|
||||||
if (backing.is_extern)
|
if (backing.is_extern)
|
||||||
@@ -330,20 +330,20 @@ obj c_generator (Object) {
|
|||||||
|
|
||||||
return make_pair(prequal+plain_typedefs+function_typedef_string+top_level_c_passthrough+variable_extern_declarations+structs+closure_struct_definitions+function_prototypes+variable_declarations+function_definitions + "\n", linker_string)
|
return make_pair(prequal+plain_typedefs+function_typedef_string+top_level_c_passthrough+variable_extern_declarations+structs+closure_struct_definitions+function_prototypes+variable_declarations+function_definitions + "\n", linker_string)
|
||||||
}
|
}
|
||||||
fun get_closure_struct_type(closed_variables: set<*ast_node>): string {
|
/*fun get_closure_struct_type(closed_variables: set<*ast_node>): string {*/
|
||||||
if (!closure_struct_map.contains_key(closed_variables)) {
|
/*if (!closure_struct_map.contains_key(closed_variables)) {*/
|
||||||
var closure_name = string("closure_data_type") + get_id()
|
/*var closure_name = string("closure_data_type") + get_id()*/
|
||||||
closure_struct_definitions += "typedef struct {\n"
|
/*closure_struct_definitions += "typedef struct {\n"*/
|
||||||
// note that we keep our is_ref, which would not normally happen on a clone with increased indirection
|
/*// 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)) +
|
/*// 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)) +*/
|
||||||
// NO, now we don't keep our ref. Too hard to make, as &(&*i) isn't legal C
|
/*// NO, now we don't keep our ref. Too hard to make, as &(&*i) isn't legal C*/
|
||||||
closed_variables.for_each(fun(i: *ast_node) closure_struct_definitions += type_to_c(i->identifier.type->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()) +*/
|
||||||
" " + get_name(i) + ";\n";)
|
/*" " + get_name(i) + ";\n";)*/
|
||||||
closure_struct_definitions += string("} ") + closure_name + ";\n"
|
/*closure_struct_definitions += string("} ") + closure_name + ";\n"*/
|
||||||
closure_struct_map[closed_variables] = closure_name
|
/*closure_struct_map[closed_variables] = closure_name*/
|
||||||
}
|
/*}*/
|
||||||
return closure_struct_map[closed_variables]
|
/*return closure_struct_map[closed_variables]*/
|
||||||
}
|
/*}*/
|
||||||
fun generate_if_comp(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): code_triple {
|
fun generate_if_comp(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): code_triple {
|
||||||
if (node->if_comp.wanted_generator == "__C__")
|
if (node->if_comp.wanted_generator == "__C__")
|
||||||
return generate(node->if_comp.statement, enclosing_object, enclosing_func, false)
|
return generate(node->if_comp.statement, enclosing_object, enclosing_func, false)
|
||||||
@@ -438,13 +438,15 @@ obj c_generator (Object) {
|
|||||||
var post = string()
|
var post = string()
|
||||||
// note that we get rid of references on closing over, (or maybe everything's kind of a reference)
|
// note that we get rid of references on closing over, (or maybe everything's kind of a reference)
|
||||||
// so we do else if here
|
// so we do else if here
|
||||||
if (enclosing_func && enclosing_func->function.closed_variables.contains(node))
|
if (get_ast_type(node)->is_ref)
|
||||||
return code_triple(pre + string("(*(closure_data->") + get_name(node) + "))" + post)
|
|
||||||
else if (get_ast_type(node)->is_ref) {
|
|
||||||
error("still existin ref in identifier")
|
error("still existin ref in identifier")
|
||||||
pre += "(*"
|
/*if (enclosing_func && enclosing_func->function.closed_variables.contains(node))*/
|
||||||
post += ")"
|
/*return code_triple(pre + string("(*(closure_data->") + get_name(node) + "))" + post)*/
|
||||||
}
|
/*else if (get_ast_type(node)->is_ref) {*/
|
||||||
|
/*error("still existin ref in identifier")*/
|
||||||
|
/*pre += "(*"*/
|
||||||
|
/*post += ")"*/
|
||||||
|
/*}*/
|
||||||
if (enclosing_object && get_ast_scope(enclosing_object)->contains_key(node->identifier.name) && get_ast_scope(enclosing_object)->get(node->identifier.name).contains(node))
|
if (enclosing_object && get_ast_scope(enclosing_object)->contains_key(node->identifier.name) && get_ast_scope(enclosing_object)->get(node->identifier.name).contains(node))
|
||||||
return code_triple(pre + "(this->" + get_name(node) + ")" + post)
|
return code_triple(pre + "(this->" + get_name(node) + ")" + post)
|
||||||
return code_triple(pre + get_name(node) + post)
|
return code_triple(pre + get_name(node) + post)
|
||||||
@@ -570,9 +572,9 @@ obj c_generator (Object) {
|
|||||||
// handle method call from inside method of same object
|
// handle method call from inside method of same object
|
||||||
if (!dot_style_method_call && enclosing_object) {
|
if (!dot_style_method_call && enclosing_object) {
|
||||||
if (method_in_object(node->function_call.func, enclosing_object)) {
|
if (method_in_object(node->function_call.func, enclosing_object)) {
|
||||||
if (enclosing_func && enclosing_func->function.closed_variables.size())
|
/*if (enclosing_func && enclosing_func->function.closed_variables.size())*/
|
||||||
call_string += "(*(closure_data->this))";
|
/*call_string += "(*(closure_data->this))";*/
|
||||||
else
|
/*else*/
|
||||||
call_string += "this";
|
call_string += "this";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -645,42 +647,43 @@ obj c_generator (Object) {
|
|||||||
ref_pre += "(*"
|
ref_pre += "(*"
|
||||||
ref_post += ")"
|
ref_post += ")"
|
||||||
}
|
}
|
||||||
if (!is_function(node->function_call.func) || node->function_call.func->function.closed_variables.size()) {
|
if (!is_function(node->function_call.func)) {
|
||||||
|
/*if (!is_function(node->function_call.func) || node->function_call.func->function.closed_variables.size()) {*/
|
||||||
// not function, so we must be an identifier or function call return or something
|
// not function, so we must be an identifier or function call return or something
|
||||||
if (!dot_style_method_call) {
|
if (!dot_style_method_call) {
|
||||||
// and also is closure style, so need special call
|
// and also is closure style, so need special call
|
||||||
if (!func_type->is_raw) {
|
/*if (!func_type->is_raw) {*/
|
||||||
// lambda
|
/*// lambda*/
|
||||||
if (pre_call == "" && (!func_return_type->is_void() || func_return_type->indirection)) {
|
/*if (pre_call == "" && (!func_return_type->is_void() || func_return_type->indirection)) {*/
|
||||||
var temp_ident = ast_identifier_ptr(string("temporary_return") + get_id(), func_return_type, null<ast_node>())
|
/*var temp_ident = ast_identifier_ptr(string("temporary_return") + get_id(), func_return_type, null<ast_node>())*/
|
||||||
var declaration = ast_declaration_statement_ptr(temp_ident, null<ast_node>())
|
/*var declaration = ast_declaration_statement_ptr(temp_ident, null<ast_node>())*/
|
||||||
// have to pass false to the declaration generator, so can't do it through generate_statement
|
/*// 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, false).one_string() + ";\n"
|
/*call_string.pre += generate_declaration_statement(declaration, enclosing_object, enclosing_func, false).one_string() + ";\n"*/
|
||||||
pre_call = generate_identifier(temp_ident, enclosing_object, enclosing_func).one_string()
|
/*pre_call = generate_identifier(temp_ident, enclosing_object, enclosing_func).one_string()*/
|
||||||
}
|
/*}*/
|
||||||
var name_temp = generate(node->function_call.func, enclosing_object, enclosing_func, false)
|
/*var name_temp = generate(node->function_call.func, enclosing_object, enclosing_func, false)*/
|
||||||
call_string.pre += name_temp.pre
|
/*call_string.pre += name_temp.pre*/
|
||||||
call_string.post += name_temp.post
|
/*call_string.post += name_temp.post*/
|
||||||
func_name = name_temp.value
|
/*func_name = name_temp.value*/
|
||||||
// should not have return var because is void
|
/*// should not have return var because is void*/
|
||||||
var pre_call_plus = pre_call
|
/*var pre_call_plus = pre_call*/
|
||||||
if (pre_call_plus != "")
|
/*if (pre_call_plus != "")*/
|
||||||
pre_call_plus += " = "
|
/*pre_call_plus += " = "*/
|
||||||
|
|
||||||
var func_type = get_ast_type(node->function_call.func)
|
/*var func_type = get_ast_type(node->function_call.func)*/
|
||||||
call_string.pre += string("if (")+func_name+".data) " + pre_call_plus + " ((" + type_to_c(func_type) + "_with_data) "+func_name+".func)("+func_name +".data"
|
/*call_string.pre += string("if (")+func_name+".data) " + pre_call_plus + " ((" + type_to_c(func_type) + "_with_data) "+func_name+".func)("+func_name +".data"*/
|
||||||
if (call_string.value != "")
|
/*if (call_string.value != "")*/
|
||||||
call_string.pre += string(",") + call_string.value
|
/*call_string.pre += string(",") + call_string.value*/
|
||||||
call_string.pre += ");\n"
|
/*call_string.pre += ");\n"*/
|
||||||
call_string.pre += string("else ") + pre_call_plus + " ((" + type_to_c(func_type) + "_without_data) " + func_name+".func)(" + call_string.value + ");\n"
|
/*call_string.pre += string("else ") + pre_call_plus + " ((" + type_to_c(func_type) + "_without_data) " + func_name+".func)(" + call_string.value + ");\n"*/
|
||||||
call_string.value = pre_call
|
/*call_string.value = pre_call*/
|
||||||
|
|
||||||
call_string.value = ref_pre + call_string.value + ref_post
|
/*call_string.value = ref_pre + call_string.value + ref_post*/
|
||||||
return call_string
|
/*return call_string*/
|
||||||
} else {
|
/*} else {*/
|
||||||
// this is a raw function value
|
// this is a raw function value
|
||||||
func_name = generate(node->function_call.func, enclosing_object, enclosing_func, false).one_string()
|
func_name = generate(node->function_call.func, enclosing_object, enclosing_func, false).one_string()
|
||||||
}
|
/*}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pre_call != "") {
|
if (pre_call != "") {
|
||||||
|
|||||||
@@ -35,11 +35,20 @@ fun function_value_lower(name_ast_map: *map<string, pair<*tree<symbol>,*ast_node
|
|||||||
var all_types = set<*type>()
|
var all_types = set<*type>()
|
||||||
var function_value_creation_points = vector<function_parent_block>()
|
var function_value_creation_points = vector<function_parent_block>()
|
||||||
var function_value_call_points = vector<function_parent_block>()
|
var function_value_call_points = vector<function_parent_block>()
|
||||||
|
var closed_over_uses = vector<pair<*ast_node, pair<*ast_node, *ast_node>>>()
|
||||||
name_ast_map->for_each(fun(name: string, syntax_ast_pair: pair<*tree<symbol>,*ast_node>) {
|
name_ast_map->for_each(fun(name: string, syntax_ast_pair: pair<*tree<symbol>,*ast_node>) {
|
||||||
var helper_before = fun(node: *ast_node, parent_chain: *stack<*ast_node>) {
|
var helper_before = fun(node: *ast_node, parent_chain: *stack<*ast_node>) {
|
||||||
var t = get_ast_type(node)
|
var t = get_ast_type(node)
|
||||||
if (t) all_types.add(t)
|
if (t) all_types.add(t)
|
||||||
match(*node) {
|
match(*node) {
|
||||||
|
ast_node::identifier(backing) {
|
||||||
|
// see if this identifier use is a closed variable in a closure
|
||||||
|
var enclosing_func = parent_chain->item_from_top_satisfying(fun(n: *ast_node): bool return is_function(n);)
|
||||||
|
if (enclosing_func->function.closed_variables.contains(node)) {
|
||||||
|
println(backing.name + " is being used in a closed fashion")
|
||||||
|
closed_over_uses.add(make_pair(node, make_pair(parent_chain->top(), enclosing_func)))
|
||||||
|
}
|
||||||
|
}
|
||||||
ast_node::function(backing) {
|
ast_node::function(backing) {
|
||||||
var parent = parent_chain->top()
|
var parent = parent_chain->top()
|
||||||
// need to use function value if
|
// need to use function value if
|
||||||
@@ -138,7 +147,7 @@ fun function_value_lower(name_ast_map: *map<string, pair<*tree<symbol>,*ast_node
|
|||||||
var new_type_def = ast_type_def_ptr(new_type_def_name)
|
var new_type_def = ast_type_def_ptr(new_type_def_name)
|
||||||
l->function.closed_variables.for_each(fun(v: *ast_node) {
|
l->function.closed_variables.for_each(fun(v: *ast_node) {
|
||||||
// TODO: need to clean this type if it's a lambda type or contains it
|
// TODO: need to clean this type if it's a lambda type or contains it
|
||||||
var closed_ident = ast_identifier_ptr(v->identifier.name, v->identifier.type->clone_with_ref(), new_type_def)
|
var closed_ident = ast_identifier_ptr(v->identifier.name, v->identifier.type->clone_with_increased_indirection(), new_type_def)
|
||||||
new_type_def->type_def.variables.add(ast_declaration_statement_ptr(closed_ident, null<ast_node>()))
|
new_type_def->type_def.variables.add(ast_declaration_statement_ptr(closed_ident, null<ast_node>()))
|
||||||
add_to_scope(v->identifier.name, closed_ident, new_type_def)
|
add_to_scope(v->identifier.name, closed_ident, new_type_def)
|
||||||
})
|
})
|
||||||
@@ -157,14 +166,15 @@ fun function_value_lower(name_ast_map: *map<string, pair<*tree<symbol>,*ast_node
|
|||||||
body->code_block.children.add(ast_assignment_statement_ptr(access_expression(ident, "func"), l))
|
body->code_block.children.add(ast_assignment_statement_ptr(access_expression(ident, "func"), l))
|
||||||
body->code_block.children.add(ast_assignment_statement_ptr(access_expression(ident, "func_closure"), l))
|
body->code_block.children.add(ast_assignment_statement_ptr(access_expression(ident, "func_closure"), l))
|
||||||
if (l->function.closed_variables.size()) {
|
if (l->function.closed_variables.size()) {
|
||||||
|
var closure_lambda_param = ast_identifier_ptr("closure_data_pass", closure_struct_type, l)
|
||||||
|
l->function.parameters.add(0, closure_lambda_param)
|
||||||
var closure_param = ast_identifier_ptr("closure", closure_struct_type, body)
|
var closure_param = ast_identifier_ptr("closure", closure_struct_type, body)
|
||||||
lambda_creation_funcs[l]->function.parameters.add(closure_param)
|
lambda_creation_funcs[l]->function.parameters.add(closure_param)
|
||||||
body->code_block.children.add(ast_assignment_statement_ptr(access_expression(ident, "data"), closure_param))
|
body->code_block.children.add(ast_assignment_statement_ptr(access_expression(ident, "data"), closure_param))
|
||||||
l->function.closed_variables.for_each(fun(v: *ast_node) {
|
l->function.closed_variables.for_each(fun(v: *ast_node) {
|
||||||
var closed_param = ast_identifier_ptr("closed_param", v->identifier.type->clone_with_increased_indirection(), l)
|
var closed_param = ast_identifier_ptr("closed_param", v->identifier.type->clone_with_increased_indirection(), l)
|
||||||
lambda_creation_funcs[l]->function.parameters.add(closed_param)
|
lambda_creation_funcs[l]->function.parameters.add(closed_param)
|
||||||
/*body->code_block.children.add(ast_assignment_statement_ptr(access_expression(closure_param, v->identifier.name), closed_param))*/
|
body->code_block.children.add(ast_assignment_statement_ptr(access_expression(closure_param, v->identifier.name), closed_param))
|
||||||
body->code_block.children.add(ast_assignment_statement_ptr(closure_param, closed_param))
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
body->code_block.children.add(ast_assignment_statement_ptr(access_expression(ident, "data"), ast_value_ptr(string("0"), type_ptr(base_type::void_return(), 1))))
|
body->code_block.children.add(ast_assignment_statement_ptr(access_expression(ident, "data"), ast_value_ptr(string("0"), type_ptr(base_type::void_return(), 1))))
|
||||||
@@ -202,5 +212,12 @@ fun function_value_lower(name_ast_map: *map<string, pair<*tree<symbol>,*ast_node
|
|||||||
if (lambda_type_to_struct_type_and_call_func.contains_key(*t))
|
if (lambda_type_to_struct_type_and_call_func.contains_key(*t))
|
||||||
*t = *lambda_type_to_struct_type_and_call_func[*t].first
|
*t = *lambda_type_to_struct_type_and_call_func[*t].first
|
||||||
})
|
})
|
||||||
|
closed_over_uses.for_each(fun(p: pair<*ast_node, pair<*ast_node, *ast_node>>) {
|
||||||
|
var variable = p.first
|
||||||
|
var parent = p.second.first
|
||||||
|
var lambda = p.second.second
|
||||||
|
var closure_param = lambda->function.parameters[0]
|
||||||
|
replace_with_in(variable, make_operator_call("*", vector(access_expression(closure_param, variable->identifier.name))), parent)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user