diff --git a/kraken.krak b/kraken.krak index 7159205..35456c3 100644 --- a/kraken.krak +++ b/kraken.krak @@ -16,6 +16,7 @@ import defer_lower:* import function_value_lower:* import ref_lower:* import ctce_lower:* +import address_of_ensure_variable_lower:* import c_line_control:* import node_counter:* import c_generator:* @@ -168,6 +169,9 @@ fun main(argc: int, argv: **char):int { ctce_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) /*printlnerr("Counting Nodes")*/ /*node_counter(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)*/ + // Makes sure that & always takes reference to a variable + printlnerr("Lowering & to always have variable") + address_of_ensure_variable_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) if (interpret_instead) { printlnerr("Interpreting!") call_main(importer.name_ast_map) @@ -183,7 +187,7 @@ fun main(argc: int, argv: **char):int { var kraken_c_output_name = kraken_file_name + ".c" write_file(kraken_c_output_name, c_output_pair.first) if (compile_c) { - var compile_string = "cc -g " + opt_str + " -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -std=c99 " + c_output_pair.second + " " + kraken_c_output_name + " -o " + executable_name + var compile_string = "cc -g " + opt_str + " -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -Wno-incompatible-pointer-types -std=c99 " + c_output_pair.second + " " + kraken_c_output_name + " -o " + executable_name printlnerr(compile_string) system(compile_string) } diff --git a/kraken_minimal.krak b/kraken_minimal.krak deleted file mode 100644 index 66ad920..0000000 --- a/kraken_minimal.krak +++ /dev/null @@ -1,37 +0,0 @@ -import io:* -import grammer:* -import parser:* -import ast_transformation:* -import string:* -import util:* -import symbol:* -import tree:* -import serialize:* -import c_generator:* -import os:* - -fun main(argc: int, argv: **char):int { - var gram: grammer - var base_dir = string("/").join(string(argv[0]).split('/').slice(0,-2)) - var file_name = base_dir + "/krakenGrammer.kgm" - var file_contents = read_file(file_name) - gram.copy_construct(&load_grammer(file_contents)) - gram.calculate_first_set() - gram.calculate_state_automaton() - var kraken_file_name = string(argv[1]) - var parse.construct(gram): parser - var ast_pass.construct(): ast_transformation - var importer.construct(parse, ast_pass, vector(string(), base_dir + "/stdlib/")): importer - importer.import(kraken_file_name) - var c_generator.construct(): c_generator - var c_output_pair = c_generator.generate_c(importer.name_ast_map) - var kraken_c_output_name = kraken_file_name + ".c" - write_file(kraken_c_output_name, c_output_pair.first) - var executable_name = string(".").join(kraken_file_name.split('.').slice(0,-2)) - if (argc == 3) - executable_name = string(argv[2]) - var compile_string = "cc -g -O3 -std=c99 " + c_output_pair.second + " " + kraken_c_output_name + " -o " + executable_name - system(compile_string) - return 0 -} - diff --git a/stdlib/address_of_ensure_variable_lower.krak b/stdlib/address_of_ensure_variable_lower.krak new file mode 100644 index 0000000..693dfe3 --- /dev/null +++ b/stdlib/address_of_ensure_variable_lower.krak @@ -0,0 +1,51 @@ +import symbol:* +import tree:* +import map:* +import util:* +import string:* +import io:* +import ast_nodes:* +import ast_transformation:* +import pass_common:* + +fun address_of_ensure_variable_lower(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { + var visited = hash_set<*ast_node>() + 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::function_call(backing) { + if (is_function(backing.func) && backing.func->function.name == "&") { + var addresse = backing.parameters[0] + // Identifier is always fine. The other options are + // function call, value, or cast. The only fine one here + // is a function call of * + if ( (is_function_call(addresse) && + !(is_function(addresse->function_call.func) && + (addresse->function_call.func->function.name == "*" || + addresse->function_call.func->function.name == "." || + addresse->function_call.func->function.name == "->" || + addresse->function_call.func->function.name == "[]"))) || + is_value(addresse) || is_cast(addresse) ) { + // so we're a function call that's not * or a cast or value + // so make a temp variable for us + // Note that we don't have to worry about destruction because + // all object stuff has already ran, so this isn't an object + + var enclosing_block_idx = parent_chain->index_from_top_satisfying(is_code_block) + var enclosing_block = parent_chain->from_top(enclosing_block_idx) + var before_block_parent = parent_chain->from_top(enclosing_block_idx-1) + var ident = ast_identifier_ptr("for_address_of_temp", + backing.func->function.type->parameter_types[0], + enclosing_block) + var decl = ast_declaration_statement_ptr(ident, addresse) + add_before_in(decl, before_block_parent, enclosing_block) + replace_with_in(addresse, ident, node) + } + } + } + } + } + run_on_tree(helper_before, empty_pass_second_half(), syntax_ast_pair.second, &visited) + }) +} + diff --git a/stdlib/c_generator.krak b/stdlib/c_generator.krak index cfc45e8..d2f2253 100644 --- a/stdlib/c_generator.krak +++ b/stdlib/c_generator.krak @@ -73,6 +73,12 @@ obj code_triple (Object) { return pre+value+post } } +fun operator+(first: *char, second: ref code_triple): code_triple { + return code_triple(first) + second +} +fun operator+(first: ref string, second: ref code_triple): code_triple { + return code_triple(first) + second +} obj c_generator (Object) { var id_counter: int var ast_to_syntax: map<*ast_node, *tree> @@ -94,10 +100,8 @@ obj c_generator (Object) { linker_string.construct() c_keyword_avoid.construct() c_keyword_avoid.add(string("extern")) - replacement_map.construct() - // IMPORTANT - longest_replacement = 3 + replacement_map.construct() replacement_map[string("+")] = string("plus") replacement_map[string("-")] = string("minus") replacement_map[string("*")] = string("star") @@ -140,6 +144,12 @@ obj c_generator (Object) { replacement_map[string(".")] = string("dot") replacement_map[string("->")] = string("arrow") + longest_replacement = 0 + replacement_map.for_each(fun(key: string, value: string) { + if (key.length() > longest_replacement) + longest_replacement = key.length() + }) + return this } fun copy_construct(old: *c_generator) { @@ -217,14 +227,12 @@ 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 - // stack-stack thing // this could be a stack of strings too, maybe - // start out with one stack on the stack var prototype_and_header = generate_function_prototype_and_header(child, enclosing_object, is_lambda) function_prototypes += prototype_and_header.first if (!backing.is_extern) function_definitions += prototype_and_header.second if (backing.body_statement) { - function_definitions += string(" {\n") + generate(backing.body_statement, enclosing_object, child, false).one_string() + function_definitions += " {\n" + generate(backing.body_statement, enclosing_object, child, false).one_string() function_definitions += ";\n}\n" } else if (!backing.is_extern) { error("Empty function statement and not extern - no ADTs anymore!") @@ -235,7 +243,6 @@ obj c_generator (Object) { // iterate through asts name_ast_map.for_each(fun(name: string, tree_pair: pair<*tree,*ast_node>) { // iterate through children for each ast - // assert translation_unit? // 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 @@ -249,13 +256,9 @@ obj c_generator (Object) { }) tree_pair.second->translation_unit.children.for_each(fun(child: *ast_node) { match (*child) { - // should really check the genrator - ast_node::if_comp(backing) { - if (is_simple_passthrough(backing.statement)) - top_level_c_passthrough += generate_simple_passthrough(backing.statement, true) - } - ast_node::simple_passthrough(backing) top_level_c_passthrough += generate_simple_passthrough(child, true) - ast_node::declaration_statement(backing) variable_declarations += generate_declaration_statement(child, null(), null(), false).one_string() + ";\n" // false - don't do defer + ast_node::if_comp(backing) error("if_comp not currently supported") + ast_node::simple_passthrough(backing) error("simple_passthrough deprecated") + ast_node::declaration_statement(backing) variable_declarations += generate_declaration_statement(child, null(), null()).one_string() + ";\n" // false - don't do defer // shouldn't need to do anything with return, as the intrinsic should be something like link ast_node::compiler_intrinsic(backing) generate_compiler_intrinsic(child) ast_node::function(backing) { @@ -292,9 +295,11 @@ obj c_generator (Object) { }) }) type_poset.get_sorted().for_each(fun(vert: *ast_node) { + if (!is_type_def(vert)) + error("no adt, but how did we get this far?") var base_name = get_name(vert) plain_typedefs += string("typedef ") - if (is_type_def(vert) && vert->type_def.is_union) { + if (vert->type_def.is_union) { plain_typedefs += "union " structs += "union " } else { @@ -303,76 +308,43 @@ obj c_generator (Object) { } plain_typedefs += base_name + "_dummy " + base_name + ";\n" structs += base_name + "_dummy {\n" - if (is_type_def(vert)) { - vert->type_def.variables.for_each(fun(variable_declaration: *ast_node) structs += generate_declaration_statement(variable_declaration, 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 { - error("no adt, but how did we get this far?") - } + vert->type_def.variables.for_each(fun(variable_declaration: *ast_node) structs += generate_declaration_statement(variable_declaration, null(), null()).one_string() + ";\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); + }) structs += "};\n" }) 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 generate_if_comp(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): code_triple { - if (node->if_comp.wanted_generator == "__C__") - return generate(node->if_comp.statement, enclosing_object, enclosing_func, false) - return code_triple() - } - fun generate_simple_passthrough(node: *ast_node, is_top_level: bool): string { - // deal with all the passthrough params - var result = string() - var pre = string() - var post = string() - if (node->simple_passthrough.linker_str != "") - linker_string += node->simple_passthrough.linker_str + " " - node->simple_passthrough.in_params.for_each(fun(i: pair<*ast_node, string>) { - var wanted_name = i.second - var current_name = generate_identifier(i.first, null(), null()).one_string() - if (wanted_name != current_name) - result += type_to_c(i.first->identifier.type) + " " + wanted_name + " = " + current_name + ";\n" - }) - result += node->simple_passthrough.passthrough_str - node->simple_passthrough.out_params.for_each(fun(i: pair<*ast_node, string>) { - var temp_name = string("out_temp") + get_id() - pre += type_to_c(i.first->identifier.type) + " " + temp_name + ";\n" - result += temp_name + " = " + i.second + ";\n" - post += generate_identifier(i.first, null(), null()).one_string() + " = " + temp_name + ";\n" - }) - if (is_top_level) - return pre + result + post - return pre + "{" + result + "}" + post - } - fun generate_declaration_statement(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node, add_to_defer: bool): code_triple { + fun generate_declaration_statement(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): code_triple { var identifier = node->declaration_statement.identifier var ident_type = identifier->identifier.type // we do the declaration in the pre now so that we can take it's address to close over it for things like recursive closures // we only make it first if it's a function type though, so that global levels still work var pre_stuff = type_to_c(identifier->identifier.type) + " " + get_name(identifier) if (identifier->identifier.is_extern) - pre_stuff = string("extern ") + pre_stuff + pre_stuff = "extern " + pre_stuff var to_ret = code_triple(pre_stuff, string(), string()) if (node->declaration_statement.expression) { if (ident_type->is_function()) { - to_ret.pre += string(";\n") - to_ret += code_triple() + get_name(identifier) + " = " + generate(node->declaration_statement.expression, enclosing_object, enclosing_func, false) + to_ret.pre += ";\n" + to_ret += get_name(identifier) + " = " + generate(node->declaration_statement.expression, enclosing_object, enclosing_func, false).one_string() } else { // some shifting around to get it to work in all cases // what cases? to_ret.value = to_ret.pre to_ret.pre = "" - to_ret += code_triple() + string(" = ") + generate(node->declaration_statement.expression, enclosing_object, enclosing_func, false) + to_ret += " = " + generate(node->declaration_statement.expression, enclosing_object, enclosing_func, false).one_string() } } if (node->declaration_statement.init_method_call) { to_ret.pre += ";\n" - to_ret += code_triple() + generate(node->declaration_statement.init_method_call, enclosing_object, enclosing_func, false) + to_ret += generate(node->declaration_statement.init_method_call, enclosing_object, enclosing_func, false).one_string() } return to_ret } @@ -470,7 +442,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 var trip_ret = code_triple() - trip_ret.pre += generate_declaration_statement(declaration, null(), null(), false).one_string() + " = " + to_ret + ";\n" + trip_ret.pre += generate_declaration_statement(declaration, null(), null()).one_string() + " = " + to_ret + ";\n" trip_ret.value = generate_identifier(temp_ident, null(), null()).one_string() return trip_ret } @@ -555,20 +527,7 @@ obj c_generator (Object) { var param_type = get_ast_type(param) call_string += generate(param, enclosing_object, enclosing_func, false) } - // temporary returns if we're asked for them or we need them for destruct - if (!func_return_type->is_void() && need_variable) { - var pre_call = string() - // kind of ugly combo here of - var temp_ident = ast_identifier_ptr(string("temporary_return") + get_id(), func_return_type, 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, false).one_string() + ";\n" - pre_call = generate_identifier(temp_ident, enclosing_object, enclosing_func).one_string() - call_string.pre += pre_call + " = " + func_name + "(" + call_string.value + ");" - call_string.value = pre_call - } else { - call_string.value = func_name + "(" + call_string.value + ")" - } + call_string.value = func_name + "(" + call_string.value + ")" return call_string } @@ -591,9 +550,7 @@ obj c_generator (Object) { fun generate(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node, need_variable: bool): code_triple { if (!node) return code_triple("/*NULL*/") match (*node) { - ast_node::if_comp(backing) return generate_if_comp(node, enclosing_object, enclosing_func) - ast_node::simple_passthrough(backing) return code_triple() + generate_simple_passthrough(node, false) - ast_node::declaration_statement(backing) return generate_declaration_statement(node, enclosing_object, enclosing_func, true) + ast_node::declaration_statement(backing) return generate_declaration_statement(node, enclosing_object, enclosing_func) ast_node::assignment_statement(backing) return generate_assignment_statement(node, enclosing_object, enclosing_func) ast_node::if_statement(backing) return generate_if_statement(node, enclosing_object, enclosing_func) ast_node::while_loop(backing) return generate_while_loop(node, enclosing_object, enclosing_func) diff --git a/stdlib/obj_lower.krak b/stdlib/obj_lower.krak index a522a6e..87862f4 100644 --- a/stdlib/obj_lower.krak +++ b/stdlib/obj_lower.krak @@ -155,12 +155,15 @@ fun obj_lower(name_ast_map: *map,*ast_node>>, ast_to_ } } var func_return_type = func_type->return_type - if (!func_return_type->is_ref && func_return_type->indirection == 0 && (func_return_type->is_object() && has_method(func_return_type->type_def, "destruct", vector<*type>()))) { + /*if (!func_return_type->is_ref && func_return_type->indirection == 0 && (func_return_type->is_object() && has_method(func_return_type->type_def, "destruct", vector<*type>()))) {*/ + if (!func_return_type->is_ref && func_return_type->indirection == 0 && func_return_type->is_object()) { var temp_return = ast_identifier_ptr("temporary_return_boomchaka", func_return_type, null()) var declaration = ast_declaration_statement_ptr(temp_return, node) add_before_in(declaration, replace_before, replace_in) - add_before_in(ast_defer_statement_ptr(make_method_call(temp_return, "destruct", vector<*ast_node>())), - replace_before, replace_in) + if (has_method(func_return_type->type_def, "destruct", vector<*type>())) { + add_before_in(ast_defer_statement_ptr(make_method_call(temp_return, "destruct", vector<*ast_node>())), + replace_before, replace_in) + } replace_with_in(node, temp_return, parent_chain) } } diff --git a/stdlib/stack.krak b/stdlib/stack.krak index d1bc878..ed6f05d 100644 --- a/stdlib/stack.krak +++ b/stdlib/stack.krak @@ -83,6 +83,10 @@ obj stack (Object, Serializable) { } fun reverse_vector(): vector::vector return data.reverse() + fun index_from_top_satisfying(func_raw: run(T):bool): int { + var temp_lambda = fun(i: T):bool { return func_raw(i); } + return index_from_top_satisfying(temp_lambda); + } fun index_from_top_satisfying(func: fun(T):bool): int { for (var i = 0; i < data.size; i++;) if (func(from_top(i)))