diff --git a/stdlib/ast_nodes.krak b/stdlib/ast_nodes.krak index 3c0543c..1c6baac 100644 --- a/stdlib/ast_nodes.krak +++ b/stdlib/ast_nodes.krak @@ -246,25 +246,40 @@ fun is_adt_def(node: *ast_node): bool { obj adt_def (Object) { var scope: map> var name: string + var self_type: *type + var options: vector<*ast_node> + var option_funcs: vector<*ast_node> + var regular_funcs: vector<*ast_node> fun construct(nameIn: string): *adt_def { scope.construct() name.copy_construct(&nameIn) + self_type = null() + options.construct() + option_funcs.construct() + regular_funcs.construct() return this } fun copy_construct(old: *adt_def) { scope.copy_construct(&old->scope) name.copy_construct(&old->name) + self_type = old->self_type + options.copy_construct(&old->options) + option_funcs.copy_construct(&old->option_funcs) + regular_funcs.copy_construct(&old->regular_funcs) } fun destruct() { scope.destruct() name.destruct() + options.destruct() + option_funcs.destruct() + regular_funcs.destruct() } fun operator=(other: ref adt_def) { destruct() copy_construct(&other) } fun operator==(other: ref adt_def): bool { - return name == other.name + return name == other.name && self_type == other.self_type && options == other.options && option_funcs == other.option_funcs && regular_funcs == other.regular_funcs } } fun ast_function_ptr(name: string, type: *type, parameters: vector<*ast_node>): *ast_node { @@ -491,8 +506,8 @@ obj if_statement (Object) { return condition == other.condition && then_part == other.then_part && else_part == other.else_part } } -fun ast_match_statement_ptr(): *ast_node { - var to_ret.construct(): match_statement +fun ast_match_statement_ptr(value: *ast_node): *ast_node { + var to_ret.construct(value): match_statement var ptr = new() ptr->copy_construct(&ast_node::match_statement(to_ret)) return ptr @@ -505,22 +520,29 @@ fun is_match_statement(node: *ast_node): bool { } obj match_statement (Object) { var scope: map> - fun construct(): *match_statement { + var value: *ast_node + var cases: vector<*ast_node> + fun construct(value_in: *ast_node): *match_statement { scope.construct() + value = value_in + cases.construct() return this } fun copy_construct(old: *match_statement) { scope.copy_construct(&old->scope) + value = old->value + cases.copy_construct(&old->cases) } fun destruct() { scope.destruct() + cases.destruct() } fun operator=(other: ref match_statement) { destruct() copy_construct(&other) } fun operator==(other: ref match_statement): bool { - return true + return value == other.value && cases == other.cases && scope == other.scope } } fun ast_case_statement_ptr(): *ast_node { @@ -537,12 +559,21 @@ fun is_case_statement(node: *ast_node): bool { } obj case_statement (Object) { var scope: map> + var option: *ast_node + var unpack_ident: *ast_node + var statement: *ast_node fun construct(): *case_statement { scope.construct() + option = null() + unpack_ident = null() + statement = null() return this } fun copy_construct(old: *case_statement) { scope.copy_construct(&old->scope) + option = old->option + unpack_ident = old->unpack_ident + statement = old->statement } fun destruct() { scope.destruct() @@ -552,7 +583,7 @@ obj case_statement (Object) { copy_construct(&other) } fun operator==(other: ref case_statement): bool { - return true + return option == other.option && unpack_ident == other.unpack_ident && statement == other.statement } } fun ast_while_loop_ptr(condition: *ast_node): *ast_node { @@ -974,14 +1005,14 @@ fun get_ast_children(node: *ast_node): vector<*ast_node> { ast_node::import(backing) return vector<*ast_node>() ast_node::identifier(backing) return vector<*ast_node>() ast_node::type_def(backing) return backing.variables + backing.methods - ast_node::adt_def(backing) return vector<*ast_node>() + ast_node::adt_def(backing) return backing.options + backing.option_funcs ast_node::function(backing) return backing.parameters + backing.body_statement ast_node::template(backing) return backing.instantiated 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(backing.condition, backing.then_part, backing.else_part) - ast_node::match_statement(backing) return vector<*ast_node>() - ast_node::case_statement(backing) return vector<*ast_node>() + ast_node::match_statement(backing) return vector(backing.value) + backing.cases + ast_node::case_statement(backing) return vector(backing.option, backing.unpack_ident, backing.statement) ast_node::while_loop(backing) return vector(backing.condition, backing.statement) ast_node::for_loop(backing) return vector(backing.init, backing.condition, backing.update, backing.body) ast_node::return_statement(backing) return vector(backing.return_value) @@ -1018,9 +1049,10 @@ fun get_ast_name(node: *ast_node): string { ast_node::declaration_statement(backing) return string("declaration_statement") ast_node::if_comp(backing) return string("if_comp: ") + backing.wanted_generator ast_node::simple_passthrough(backing) return string("simple_passthrough: , string:") + backing.passthrough_str - ast_node::function_call(backing) return string("function_call:(") + backing.parameters.size + ")" + ast_node::function_call(backing) return string("function_call:") + get_ast_name(backing.func) + "(" + backing.parameters.size + ")" ast_node::value(backing) return string("value: ") + backing.string_value + ": " + backing.value_type->to_string() } + return string("impossible adt type") } fun get_ast_scope(node: *ast_node): *map> { match (*node) { diff --git a/stdlib/ast_transformation.krak b/stdlib/ast_transformation.krak index e3c980c..b58c81c 100644 --- a/stdlib/ast_transformation.krak +++ b/stdlib/ast_transformation.krak @@ -51,6 +51,7 @@ obj ast_transformation (Object) { } else if (child->data.name == "adt_def") { var name = concat_symbol_tree(get_node("identifier", child)) var adt_def_node = ast_adt_def_ptr(name) + adt_def_node->adt_def.self_type = type_ptr(adt_def_node, set(string("Object"))) 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) @@ -129,7 +130,7 @@ obj ast_transformation (Object) { translation_unit->translation_unit.children.for_each(fun(node: *ast_node) { match(*node) { ast_node::type_def(backing) second_pass_type_def(ast_to_syntax[node], node, translation_unit, map()) - ast_node::adt_def(backing) do_nothing() // actually go through and do methods inside + ast_node::adt_def(backing) second_pass_adt_def(ast_to_syntax[node], node, translation_unit, map()) } }) } @@ -147,6 +148,51 @@ obj ast_transformation (Object) { } }) } + fun second_pass_adt_def(adt_def_syntax: *tree, node: *ast_node, scope: *ast_node, template_replacements: map) { + get_nodes("adt_option", adt_def_syntax).for_each(fun(adt_option: *tree) { + var ident_type: *type + var type_syntax = get_node("type", adt_option) + if (type_syntax) + ident_type = transform_type(type_syntax, scope, template_replacements) + else + ident_type = type_ptr(base_type::no_type_adt_option()) + var option_name = concat_symbol_tree(get_node("identifier", adt_option)) + var identifier = ast_identifier_ptr(option_name, ident_type, node) + node->adt_def.options.add(identifier) + // we add the identifier first so that it's found before the function when doing option.thingy + add_to_scope(option_name, identifier, node) + add_to_scope("~enclosing_scope", node, identifier) + ast_to_syntax.set(identifier, adt_option) + + var function_node = null() + if (type_syntax) + function_node = ast_function_ptr(option_name, type_ptr(vector(get_ast_type(identifier)), node->adt_def.self_type), vector(identifier)) + else + function_node = ast_function_ptr(option_name, type_ptr(vector<*type>(), node->adt_def.self_type), vector<*ast_node>()) + add_to_scope(option_name, function_node, node) + add_to_scope("~enclosing_scope", node, function_node) + node->adt_def.option_funcs.add(function_node) + }) + // we fake operator==, operator!=, copy_construct, operator=, and destruct like so + // note they don't even have real parameters (but the type has them correctly) or bodies + + // I'm not sure this is the correct enclosing scope, but I'm not sure how to do it with the function either + var equals_param = ast_identifier_ptr(string("in"), node->adt_def.self_type->clone_with_indirection(0,true), node) + var nequals_param = ast_identifier_ptr(string("in"), node->adt_def.self_type->clone_with_indirection(0,true), node) + var copy_construct_param = ast_identifier_ptr(string("in"), node->adt_def.self_type->clone_with_indirection(1,false), node) + var assign_param = ast_identifier_ptr(string("in"), node->adt_def.self_type->clone_with_indirection(0,true), node) + vector( + make_pair("operator==", ast_function_ptr(string("operator=="), type_ptr(vector(equals_param->identifier.type), type_ptr(base_type::boolean())), vector(equals_param))), + make_pair("operator!=", ast_function_ptr(string("operator!="), type_ptr(vector(nequals_param->identifier.type), type_ptr(base_type::boolean())), vector(nequals_param))), + make_pair("copy_construct", ast_function_ptr(string("copy_construct"), type_ptr(vector(copy_construct_param->identifier.type), type_ptr(base_type::void_return())), vector(copy_construct_param))), + make_pair("operator=", ast_function_ptr(string("operator="), type_ptr(vector(assign_param->identifier.type), type_ptr(base_type::void_return())), vector(assign_param))), + make_pair("destruct", ast_function_ptr(string("destruct"), type_ptr(vector<*type>(), type_ptr(base_type::void_return())), vector<*ast_node>())) + ).for_each(fun(func_pair: pair<*char, *ast_node>) { + node->adt_def.regular_funcs.add(func_pair.second) + add_to_scope(string(func_pair.first), func_pair.second, node) + add_to_scope("~enclosing_scope", node, func_pair.second) + }) + } fun second_pass_function(node: *tree, scope: *ast_node, template_replacements: map, do_raw_template: bool): *ast_node { var func_identifier_node = get_node("func_identifier", node) var function_name = string("lambda") @@ -340,6 +386,7 @@ obj ast_transformation (Object) { for (var i = 0; i < possibilities.size; i++;) { match(*possibilities[i]) { ast_node::type_def(backing) return backing.self_type->clone_with_indirection(indirection, is_ref) + ast_node::adt_def(backing) return backing.self_type->clone_with_indirection(indirection, is_ref) } } println("No objects in lookup, returning none") @@ -375,6 +422,8 @@ obj ast_transformation (Object) { return transform_branching_statement(node, scope) } else if (name == "defer_statement") { return transform_defer_statement(node, scope, template_replacements) + } else if (name == "match_statement") { + return transform_match_statement(node, scope, template_replacements) } else if (name == "function_call") { return transform_function_call(node, scope, template_replacements) } else if (name == "lambda") { @@ -629,6 +678,31 @@ obj ast_transformation (Object) { fun transform_defer_statement(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { return ast_defer_statement_ptr(transform(node->children[0], scope, template_replacements)) } + fun transform_match_statement(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { + var to_ret = ast_match_statement_ptr(transform(get_node("boolean_expression", node), scope, template_replacements)) + get_nodes("case_statement", node).for_each(fun(syntax: *tree) to_ret->match_statement.cases.add(transform_case_statement(syntax, scope, template_replacements));) + return to_ret + } + fun transform_case_statement(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { + var to_ret = ast_case_statement_ptr() + var the_adts = scope_lookup(concat_symbol_tree(get_node("scoped_identifier", get_node("scoped_identifier", node))), scope) + if (the_adts.size != 1) + error(string("the adts too large for ") + concat_symbol_tree(get_node("scoped_identifier", node))) + var the_adt = the_adts[0] + var the_option_name = concat_symbol_tree(get_node("identifier", get_node("scoped_identifier", node))) + var the_option = the_adt->adt_def.options.find_first_satisfying(fun(option: *ast_node): bool return option->identifier.name == the_option_name;) + to_ret->case_statement.option = the_option + var possible_ident = get_node("identifier", node) + if (possible_ident) { + var ident = ast_identifier_ptr(concat_symbol_tree(possible_ident), the_option->identifier.type, scope) + to_ret->case_statement.unpack_ident = ident + add_to_scope(ident->identifier.name, ident, to_ret) + } + //add to scope + add_to_scope("~enclosing_scope", scope, to_ret) + to_ret->case_statement.statement = transform(get_node("statement", node), to_ret, template_replacements) + return to_ret + } fun transform_function_call(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { // don't bother with a full transform for parameters with their own function, just get the boolean expression and transform it var parameters = get_nodes("parameter", node).map(fun(child: *tree): *ast_node return transform(get_node("boolean_expression", child), scope, template_replacements);) @@ -826,7 +900,7 @@ obj ast_transformation (Object) { fun find_and_make_any_operator_overload_call(func_name: string, parameters: vector<*ast_node>, scope: *ast_node, template_replacements: map): *ast_node { var parameter_types = parameters.map(fun(param: *ast_node): *type return get_ast_type(param);) var possible_overload = null() - if (parameter_types[0]->is_object() && parameter_types[0]->indirection == 0) { + if ((parameter_types[0]->is_adt() || parameter_types[0]->is_object()) && parameter_types[0]->indirection == 0) { possible_overload = function_lookup(string("operator")+func_name, parameter_types.first()->type_def, parameter_types.slice(1,-1)) if (!possible_overload) possible_overload = find_or_instantiate_template_function(string("operator")+func_name, null>(), parameter_types.first()->type_def, parameter_types.slice(1,-1), template_replacements, map()) @@ -952,6 +1026,7 @@ fun has_method(object: *ast_node, name: string, parameter_types: vector<*type>): fun make_method_call(object_ident: *ast_node, name: *char, parameters: vector<*ast_node>): *ast_node return make_method_call(object_ident, string(name), parameters); fun make_method_call(object_ident: *ast_node, name: string, parameters: vector<*ast_node>): *ast_node { println("MAKE METHOD CALL OUT:") + // note that this type_def is the adt_def if this is an adt type var method = function_lookup(name, get_ast_type(object_ident)->type_def, parameters.map(fun(param: *ast_node): *type return get_ast_type(param);)) print("Here is the Method: ") println(method) @@ -1061,7 +1136,7 @@ fun function_lookup(name: string, scope: *ast_node, param_types: vector<*type>): var results = scope_lookup(name, scope) print(results.size); println(" number of results") for (var i = 0; i < results.size; i++;) { - if ((is_function(results[i]) || is_identifier(results[i])) && function_satisfies_params(results[i], param_types)) { + if ((is_function(results[i]) || (is_identifier(results[i]) && get_ast_type(results[i])->is_function())) && function_satisfies_params(results[i], param_types)) { return results[i] } } diff --git a/stdlib/c_generator.krak b/stdlib/c_generator.krak index 22c0ae5..f61e1c5 100644 --- a/stdlib/c_generator.krak +++ b/stdlib/c_generator.krak @@ -160,6 +160,38 @@ obj c_generator (Object) { replacement_map.destruct() } fun get_id(): string return to_string(id_counter++); + fun generate_function_prototype_and_header(child: *ast_node, enclosing_object: *ast_node, is_lambda: bool, defer_stack: *stack>>):pair { + var backing = child->function + + var parameter_types = string() + var parameters = string() + // lambdas can have the enclosing object too, if it's needed (lambda in a method) + if (enclosing_object && !is_lambda) { + parameter_types = type_to_c(enclosing_object->type_def.self_type) + "*" + parameters = type_to_c(enclosing_object->type_def.self_type) + "* this" + } + if (backing.closed_variables.size()) { + println("HAS CLOSED VARIABLES") + if (parameter_types != "") { parameter_types += ", "; parameters += ", ";} + var closed_type_name = get_closure_struct_type(backing.closed_variables) + parameter_types += closed_type_name + "*" + parameters += closed_type_name + "* closure_data" + } + + var decorated_name = generate_function(child, enclosing_object, null(), false, false).one_string() + backing.parameters.for_each(fun(parameter: *ast_node) { + if (parameter_types != "") { parameter_types += ", "; parameters += ", ";} + parameter_types += type_to_c(parameter->identifier.type) + parameters += type_to_c(parameter->identifier.type) + " " + get_name(parameter) + + // add parameters to destructor thingy (for returns)? Or should that be a different pass? + var parameter_type = parameter->identifier.type + if (!parameter_type->is_ref && parameter_type->indirection == 0 && (parameter_type->is_adt() || (parameter_type->is_object() && has_method(parameter_type->type_def, "destruct", vector<*type>())))) + defer_stack->top().second.push(ast_statement_ptr(make_method_call(parameter, "destruct", vector<*ast_node>()))) + }) + return make_pair(type_to_c(backing.type->return_type) + " " + decorated_name + "(" + parameter_types + ");\n", + type_to_c(backing.type->return_type) + " " + decorated_name + "(" + parameters + ")") + } fun generate_c(name_ast_map: map,*ast_node>>): pair { var linker_string:string = "" var prequal: string = "#include \n#include \n#include \n" @@ -176,42 +208,49 @@ obj c_generator (Object) { // moved out from below so that it can be used for methods as well as regular functions (and eventually lambdas...) var generate_function_definition = fun(child: *ast_node, enclosing_object: *ast_node, is_lambda: bool) { var backing = child->function - - var parameter_types = string() - var parameters = string() - // lambdas can have the enclosing object too, if it's needed (lambda in a method) - if (enclosing_object && !is_lambda) { - parameter_types = type_to_c(enclosing_object->type_def.self_type) + "*" - parameters = type_to_c(enclosing_object->type_def.self_type) + "* this" - } - if (backing.closed_variables.size()) { - println("HAS CLOSED VARIABLES") - if (parameter_types != "") { parameter_types += ", "; parameters += ", ";} - var closed_type_name = get_closure_struct_type(backing.closed_variables) - parameter_types += closed_type_name + "*" - parameters += closed_type_name + "* closure_data" - } - // stack-stack thing // this could be a stack of strings too, maybe // start out with one stack on the stack var defer_stack = stack>>(make_pair(false, stack<*ast_node>())) - - var decorated_name = generate_function(child, enclosing_object, null(), false, false).one_string() - backing.parameters.for_each(fun(parameter: *ast_node) { - if (parameter_types != "") { parameter_types += ", "; parameters += ", ";} - parameter_types += type_to_c(parameter->identifier.type) - parameters += type_to_c(parameter->identifier.type) + " " + get_name(parameter) - - // add parameters to destructor thingy (for returns)? Or should that be a different pass? - var parameter_type = parameter->identifier.type - if (!parameter_type->is_ref && parameter_type->indirection == 0 && parameter_type->is_object() && has_method(parameter_type->type_def, "destruct", vector<*type>())) - defer_stack.top().second.push(ast_statement_ptr(make_method_call(parameter, "destruct", vector<*ast_node>()))) - }) - function_prototypes += type_to_c(backing.type->return_type) + " " + decorated_name + "(" + parameter_types + ");\n" - function_definitions += type_to_c(backing.type->return_type) + " " + decorated_name + "(" + parameters + ") {\n" + generate_statement(backing.body_statement, enclosing_object, child, &defer_stack).one_string() - // emit parameter destructors? - function_definitions += generate_from_defer_stack(&defer_stack, -1, enclosing_object, child).one_string() - function_definitions += "}\n" + var prototype_and_header = generate_function_prototype_and_header(child, enclosing_object, is_lambda, &defer_stack) + function_prototypes += prototype_and_header.first + function_definitions += prototype_and_header.second + if (backing.body_statement) { + function_definitions += string(" {\n") + generate_statement(backing.body_statement, enclosing_object, child, &defer_stack).one_string() + function_definitions += generate_from_defer_stack(&defer_stack, -1, enclosing_object, child).one_string() + function_definitions += "}\n" + } else { + // adt constructor + // wow. no pass in for no this + enclosing_object = get_ast_scope(child)->get(string("~enclosing_scope"))[0] + // if this is an option constructor + if (enclosing_object->adt_def.options.any_true(fun(opt: *ast_node): bool return opt->identifier.name == backing.name;)) { + var option_ident = enclosing_object->adt_def.options.find_first_satisfying(fun(opt: *ast_node): bool return opt->identifier.name == backing.name;) + function_definitions += " { \n" + function_definitions += type_to_c(enclosing_object->adt_def.self_type) + " to_ret;\n" + function_definitions += string("to_ret.flag = ") + string("enum_opt_") + get_name(option_ident) + ";\n" + if (option_ident->identifier.type->is_empty_adt_option()) + function_definitions += "/*no inner data*/\n" + else + function_definitions += string("to_ret.data.") + get_name(option_ident) + " = " + get_name(option_ident) + ";\n" + function_definitions += "return to_ret;\n" + function_definitions += "}\n" + } else { + // this is one of the other functions instead + function_definitions += "{" + if (backing.name == "operator==") { + function_definitions += "/*operator==*/" + } else if (backing.name == "operator!=") { + function_definitions += "/*operator!=*/" + } else if (backing.name == "copy_construct") { + function_definitions += "/*copy_construct*/" + } else if (backing.name == "operator=") { + function_definitions += "/*operator=*/" + } else if (backing.name == "destruct") { + function_definitions += "/*destruct*/" + } + function_definitions += "}\n" + } + } } var type_poset = poset<*ast_node>() @@ -225,7 +264,7 @@ obj c_generator (Object) { 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)) + if (enclosing_object_traverse && is_type_def(enclosing_object_traverse)) generate_function_definition(child, enclosing_object_traverse, true) else generate_function_definition(child, null(), true) @@ -266,6 +305,14 @@ obj c_generator (Object) { type_poset.add_relationship(child, var_type->type_def) }) } + ast_node::adt_def(backing) { + type_poset.add_vertex(child) + backing.options.for_each(fun(i: *ast_node) { + var var_type = get_ast_type(i) + if (!var_type->indirection && var_type->type_def) + type_poset.add_relationship(child, var_type->type_def) + }) + } } }) }) @@ -274,15 +321,37 @@ obj c_generator (Object) { var base_name = get_name(vert) plain_typedefs += string("typedef struct ") + base_name + "_dummy " + base_name + ";\n" structs += string("struct ") + base_name + "_dummy {\n" - vert->type_def.variables.for_each(fun(variable_declaration: *ast_node) structs += generate_declaration_statement(variable_declaration, null(), null(), null>>>(), false).one_string() + ";\n";) // also no defer stack + if (is_type_def(vert)) { + vert->type_def.variables.for_each(fun(variable_declaration: *ast_node) structs += generate_declaration_statement(variable_declaration, null(), null(), null>>>(), false).one_string() + ";\n";) // also no defer stack + // generate the methods (note some of these may be templates) + vert->type_def.methods.for_each(fun(method: *ast_node) { + if (is_template(method)) + method->template.instantiated.for_each(fun(m: *ast_node) generate_function_definition(m, vert, false);) + else + generate_function_definition(method, vert, false); + }) + } else { + // adt + var add_to_structs = string() + var add_to_enum = string() + vert->adt_def.options.for_each(fun(option: *ast_node) { + add_to_enum += string("enum_opt_") + get_name(option) + "," + if (!option->identifier.type->is_empty_adt_option()) + add_to_structs += generate_declaration_statement(ast_declaration_statement_ptr(option, null()), null(), null(), null>>>(), false).one_string() + ";\n" + }) + structs += string("enum { ") + add_to_enum + " } flag;\n" + structs += string("union { ") + add_to_structs + " } data;\n" + // now do methods and generation functions + vert->adt_def.option_funcs.for_each(fun(option_func: *ast_node) { + // no vert so no this + generate_function_definition(option_func, null(), false); + }) + vert->adt_def.regular_funcs.for_each(fun(regular_func: *ast_node) { + // want the this this time + generate_function_definition(regular_func, vert, false); + }) + } structs += "};\n" - // generate the methods (note some of these may be templates) - vert->type_def.methods.for_each(fun(method: *ast_node) { - if (is_template(method)) - method->template.instantiated.for_each(fun(m: *ast_node) generate_function_definition(m, vert, false);) - else - generate_function_definition(method, vert, false); - }) }) return make_pair(prequal+plain_typedefs+top_level_c_passthrough+variable_extern_declarations+structs+function_typedef_string+closure_struct_definitions+function_prototypes+variable_declarations+function_definitions + "\n", linker_string) @@ -337,7 +406,7 @@ obj c_generator (Object) { // we only make it first if it's a function type though, so that global levels still work var to_ret = code_triple(type_to_c(identifier->identifier.type) + " " + get_name(identifier), string(), string()) if (node->declaration_statement.expression) { - if (ident_type->is_object() && has_method(ident_type->type_def, "copy_construct", vector(get_ast_type(node->declaration_statement.expression)->clone_with_increased_indirection()))) { + if (ident_type->is_adt() || (ident_type->is_object() && has_method(ident_type->type_def, "copy_construct", vector(get_ast_type(node->declaration_statement.expression)->clone_with_increased_indirection())))) { to_ret.pre += ";\n" to_ret += generate(ast_statement_ptr(make_method_call(identifier, "copy_construct", vector(make_operator_call("&", vector(node->declaration_statement.expression))))), enclosing_object, enclosing_func, defer_stack, false) } else { @@ -357,7 +426,7 @@ obj c_generator (Object) { to_ret.pre += ";\n" to_ret += code_triple() + generate(node->declaration_statement.init_method_call, enclosing_object, enclosing_func, null>>>(), false) } - if (add_to_defer && ident_type->is_object() && ident_type->indirection == 0 && has_method(ident_type->type_def, "destruct", vector<*type>())) + if (add_to_defer && ident_type->indirection == 0 && (ident_type->is_adt() || (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 } @@ -431,7 +500,7 @@ obj c_generator (Object) { 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 to_ret.pre = generate_declaration_statement(declaration, enclosing_object, enclosing_func, defer_stack, false).one_string() + ";\n" - if (return_value_type->is_object() && !function_return_type->is_ref && return_value_type->indirection == 0 && has_method(return_value_type->type_def, "copy_construct", vector(return_value_type->clone_with_indirection(1)))) { + if (!function_return_type->is_ref && return_value_type->indirection == 0 && (return_value_type->is_adt() || (return_value_type->is_object() && has_method(return_value_type->type_def, "copy_construct", vector(return_value_type->clone_with_indirection(1)))))) { to_ret.pre += generate_statement(ast_statement_ptr(make_method_call(temp_ident, "copy_construct", vector(make_operator_call("&", vector(return_value))))), enclosing_object, enclosing_func, defer_stack).one_string() } else { var refamp = string() @@ -447,7 +516,7 @@ obj c_generator (Object) { to_ret += code_triple(" ") + generate(return_value, enclosing_object, enclosing_func, null>>>(), false) // generate all in stack by passing -1, make sure added after we calculate the return value to_ret.pre += generate_from_defer_stack(defer_stack, -1, enclosing_object, enclosing_func).one_string() - + return to_ret } fun generate_branching_statement(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node, defer_stack: *stack>>): code_triple { @@ -478,6 +547,25 @@ obj c_generator (Object) { defer_stack->top().second.push(node->defer_statement.statement) return code_triple("/*defer wanna know what*/") } + fun generate_match_statement(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node, defer_stack: *stack>>): code_triple { + var to_ret = code_triple("/* begin match */") + var matching_value = generate(node->match_statement.value, enclosing_object, enclosing_func, defer_stack, true) + to_ret.pre += matching_value.pre + to_ret.post += matching_value.post + node->match_statement.cases.for_each(fun(case_node: *ast_node) { + var option_str = generate(case_node->case_statement.option, enclosing_object, enclosing_func, defer_stack, false).one_string() + var to_ret_case = code_triple("/*case ") + option_str + "*/ if(" + matching_value.value + ".flag == " + string("enum_opt_") + option_str + ") {\n" + if (case_node->case_statement.unpack_ident) { + to_ret_case += generate_declaration_statement(ast_declaration_statement_ptr(case_node->case_statement.unpack_ident, null()), null(), null(), null>>>(), false).one_string() + to_ret_case += string(" = ") + matching_value.value + ".data." + option_str + ";\n" + } else { + to_ret_case += "/*no unpack_ident*/\n" + } + to_ret_case += generate(case_node->case_statement.statement, enclosing_object, enclosing_func, defer_stack, false).one_string() + "\n}\n" + to_ret += to_ret_case.one_string() + }) + return to_ret + } fun generate_value(node: *ast_node, need_variable: bool): code_triple { var value = node->value.string_value var to_ret = string() @@ -487,7 +575,7 @@ obj c_generator (Object) { to_ret = string("\"") if (value.slice(0,3) == "\"\"\"") value = value.slice(3,-4) - else + else value = value.slice(1,-2) value.for_each(fun(c: char) { if (c == '\n') @@ -553,7 +641,9 @@ obj c_generator (Object) { is_function(node->function_call.func->function_call.parameters[1]) && (is_type_def(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(string("~enclosing_scope"))[0]) || // or if it's a templated method (yes, this has gotten uuuuugly) - is_type_def(get_ast_scope(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(string("~enclosing_scope"))[0])->get(string("~enclosing_scope"))[0])) + is_type_def(get_ast_scope(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(string("~enclosing_scope"))[0])->get(string("~enclosing_scope"))[0]) || + // or it's in an adt + is_adt_def(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(string("~enclosing_scope"))[0])) // should get uglier when we have to figure out if it's just an inside lambda if (dot_style_method_call) { @@ -611,8 +701,13 @@ obj c_generator (Object) { } // don't propegate enclosing function down right of access // XXX what about enclosing object? should it be the thing on the left? - if (func_name == "." || func_name == "->") - return code_triple("(") + generate(parameters[0], enclosing_object, enclosing_func, null>>>(), false) + func_name + generate(parameters[1], null(), null(), null>>>(), false) + string(")") + if (func_name == "." || func_name == "->") { + // special case right hand side is an adt to access inside of adt + var in_between = string() + if (get_ast_type(parameters[0])->is_adt()) + in_between = "data." + return code_triple("(") + generate(parameters[0], enclosing_object, enclosing_func, null>>>(), false) + func_name + in_between + generate(parameters[1], null(), null(), null>>>(), false) + string(")") + } if (func_name == "[]") return code_triple("(") + generate(parameters[0], enclosing_object, enclosing_func, null>>>(), false) + "[" + generate(parameters[1], enclosing_object, enclosing_func, null>>>(), false) + string("])") // the post ones need to be post-ed specifically, and take the p off @@ -633,12 +728,12 @@ obj c_generator (Object) { var in_function_param_type = func_type->parameter_types[i] if (call_string != "") call_string += ", " - + if (in_function_param_type->is_ref) call_string += "&" 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)))) { + if (!in_function_param_type->is_ref && param_type->indirection == 0 && (param_type->is_adt() || (param_type->is_object() && 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->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 @@ -650,13 +745,8 @@ obj c_generator (Object) { } } var pre_call = string() - // we now have temporary return variables for all objects, even without destruct so we can do chained method calls - // actually all non-ref returns, for chained any calls - // well, now only if we also pass in true for need_variable - // XXX this should change to only if we know we need it by having an enum or bool passed down to this call... - // if (func_return_type->is_object() && !func_return_type->is_ref && func_return_type->indirection == 0 && has_method(func_return_type->type_def, "destruct", vector<*type>())) { - // if (func_return_type->is_object() && !func_return_type->is_ref && func_return_type->indirection == 0) { - var needs_temp_for_destruct = func_return_type->is_object() && func_return_type->indirection == 0 && has_method(func_return_type->type_def, "destruct", vector<*type>()) + // temporary returns if we're asked for them or we need them for destruct + var needs_temp_for_destruct = func_return_type->indirection == 0 && (func_return_type->is_adt() || (func_return_type->is_object() && has_method(func_return_type->type_def, "destruct", vector<*type>()))) if (!func_return_type->is_ref && (needs_temp_for_destruct || (!func_return_type->is_void() && need_variable)) ) { // kind of ugly combo here of var temp_ident = ast_identifier_ptr(string("temporary_return")+get_id(), func_return_type, null()) @@ -676,6 +766,7 @@ obj c_generator (Object) { } 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 + println(get_ast_name(node->function_call.func) + " is not a function! must be a lambda or something") if (!dot_style_method_call) { // lambda if (pre_call == "" && (!func_return_type->is_void() || func_return_type->indirection)) { @@ -739,6 +830,7 @@ obj c_generator (Object) { ast_node::return_statement(backing) return generate_return_statement(node, enclosing_object, enclosing_func, defer_stack) ast_node::branching_statement(backing) return generate_branching_statement(node, enclosing_object, enclosing_func, defer_stack) ast_node::defer_statement(backing) return generate_defer_statement(node, enclosing_object, enclosing_func, defer_stack) + ast_node::match_statement(backing) return generate_match_statement(node, enclosing_object, enclosing_func, defer_stack) ast_node::value(backing) return generate_value(node, need_variable) ast_node::identifier(backing) return generate_identifier(node, enclosing_object, enclosing_func) } @@ -759,9 +851,8 @@ obj c_generator (Object) { base_type::integer() return indirection + string("int") base_type::floating() return indirection + string("float") base_type::double_precision() return indirection + string("double") - base_type::object() { - return type->type_def->type_def.name - } + base_type::object() return type->type_def->type_def.name + base_type::adt() return type->type_def->adt_def.name base_type::function() { var temp = indirection + string("function_") type->parameter_types.for_each(fun(parameter_type: *type) temp += type_decoration(parameter_type) + "_";) @@ -784,9 +875,8 @@ obj c_generator (Object) { base_type::integer() return string("int") + indirection base_type::floating() return string("float") + indirection base_type::double_precision() return string("double") + indirection - base_type::object() { - return get_name(type->type_def) + indirection - } + base_type::object() return get_name(type->type_def) + indirection + base_type::adt() return get_name(type->type_def) + indirection base_type::function() { // maybe disregard indirection in the future? if (function_type_map.contains_key(*type)) @@ -815,11 +905,14 @@ obj c_generator (Object) { var upper = backing.scope[string("~enclosing_scope")][0] result = backing.name if (is_template(upper)) - upper->template.instantiated_map.reverse_get(node).for_each(fun(t: ref type) result += string("_") + type_decoration(&t);) + upper->template.instantiated_map.reverse_get(node).for_each(fun(t: ref type) result += string("_") + type_decoration(&t);) + } + ast_node::adt_def(backing) { + result = backing.name } ast_node::function(backing) { - // be careful, operators like . come through this - if (!backing.body_statement) + // be careful, operators like . come through this, but so do adt constructor funcs + if (!backing.body_statement && !backing.scope.contains_key(string("~enclosing_scope"))) return backing.name if (backing.name == "main") return backing.name diff --git a/stdlib/type.krak b/stdlib/type.krak index 2bda26e..4586dc7 100644 --- a/stdlib/type.krak +++ b/stdlib/type.krak @@ -10,6 +10,8 @@ import io:* adt base_type { none, object, + adt, + no_type_adt_option, template, template_type, void_return, @@ -82,7 +84,10 @@ obj type (Object) { return this } fun construct(type_def_in: *ast_node, traits_in: set): *type { - base.copy_construct(&base_type::object()) + if (is_type_def(type_def_in)) + base.copy_construct(&base_type::object()) + else + base.copy_construct(&base_type::adt()) parameter_types.construct() indirection = 0 return_type = null() @@ -143,6 +148,8 @@ obj type (Object) { match (base) { base_type::none() return all_string + string("none") base_type::object() return all_string + type_def->type_def.name + base_type::adt() return all_string + type_def->adt_def.name + base_type::no_type_adt_option() return all_string + "no_type_adt_option" base_type::template() return all_string + string("template") base_type::template_type() return all_string + string("template_type") base_type::void_return() return all_string + string("void_return") @@ -189,6 +196,12 @@ obj type (Object) { } return false } + fun is_adt(): bool { + match (base) { + base_type::adt() return true + } + return false + } fun is_function(): bool { match (base) { base_type::function() return true @@ -201,5 +214,11 @@ obj type (Object) { } return false } + fun is_empty_adt_option(): bool { + match (base) { + base_type::no_type_adt_option() return true + } + return false + } } diff --git a/stdlib/vector.krak b/stdlib/vector.krak index eb00f01..2bd0229 100644 --- a/stdlib/vector.krak +++ b/stdlib/vector.krak @@ -258,6 +258,7 @@ obj vector (Object, Serializable) { } return newVec } + fun find_first_satisfying(func: fun(T):bool): T return filter(func)[0] fun filter(func: fun(T):bool):vector { var newVec.construct(): vector for (var i = 0; i < size; i++;)