From 13f1e9df89ced073b273acaef45f47c201f3c893 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 23 Oct 2017 01:08:25 -0400 Subject: [PATCH] More clean up; need to add return type checking pass so that can clean up c_generator more. --- kraken.krak | 38 +++++------ stdlib/ast_transformation.krak | 2 +- stdlib/c_generator.krak | 79 +++++++++------------- stdlib/importer.krak | 117 ++++++++++++--------------------- 4 files changed, 93 insertions(+), 143 deletions(-) diff --git a/kraken.krak b/kraken.krak index 35456c3..b16d8d0 100644 --- a/kraken.krak +++ b/kraken.krak @@ -10,6 +10,7 @@ import serialize:* import interpreter:* import os:* import ast_transformation:* +import importer:* import adt_lower:* import obj_lower:* import defer_lower:* @@ -138,52 +139,51 @@ fun main(argc: int, argv: **char):int { var executable_name = string(".").join(kraken_file_name.split('.').slice(0,-2)) if (positional_args.size > 1) executable_name = positional_args[1] - var importer.construct(parsers, ast_pass, vector(string(), base_dir + "/stdlib/")): importer - importer.import(kraken_file_name) + var name_ast_map = import(kraken_file_name, parsers, ast_pass, vector(string(), base_dir + "/stdlib/")) // Passes /*printlnerr("Counting Nodes")*/ - /*node_counter(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)*/ + /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ printlnerr("Lowering ADTs") - adt_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) + adt_lower(&name_ast_map, &ast_pass.ast_to_syntax) /*printlnerr("Counting Nodes")*/ - /*node_counter(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)*/ + /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ printlnerr("Lowering Objects") - obj_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) + obj_lower(&name_ast_map, &ast_pass.ast_to_syntax) /*printlnerr("Counting Nodes")*/ - /*node_counter(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)*/ + /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ printlnerr("Lowering Defer") - defer_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) + defer_lower(&name_ast_map, &ast_pass.ast_to_syntax) /*printlnerr("Counting Nodes")*/ - /*node_counter(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)*/ + /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ // Should come after lowering of ADTs and before lowering of Refs printlnerr("Lowering Function Values (Lambdas, etc)") - function_value_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) + function_value_lower(&name_ast_map, &ast_pass.ast_to_syntax) /*printlnerr("Counting Nodes")*/ - /*node_counter(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)*/ + /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ printlnerr("Lowering Ref") - ref_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) + ref_lower(&name_ast_map, &ast_pass.ast_to_syntax) /*printlnerr("Counting Nodes")*/ - /*node_counter(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)*/ + /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ // Lowers #ctce and the current #ctce_pass printlnerr("Lowering CTCE") - ctce_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) + ctce_lower(&name_ast_map, &ast_pass.ast_to_syntax) /*printlnerr("Counting Nodes")*/ - /*node_counter(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)*/ + /*node_counter(&name_ast_map, &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) + address_of_ensure_variable_lower(&name_ast_map, &ast_pass.ast_to_syntax) if (interpret_instead) { printlnerr("Interpreting!") - call_main(importer.name_ast_map) + call_main(name_ast_map) } else { if (line_ctrl) { printlnerr("running C-specific passes") printlnerr("running #line") - c_line_control(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) + c_line_control(&name_ast_map, &ast_pass.ast_to_syntax) } printlnerr("Generating C") var c_generator.construct(): c_generator - var c_output_pair = c_generator.generate_c(importer.name_ast_map, importer.ast_pass.ast_to_syntax) + var c_output_pair = c_generator.generate_c(name_ast_map, ast_pass.ast_to_syntax) var kraken_c_output_name = kraken_file_name + ".c" write_file(kraken_c_output_name, c_output_pair.first) if (compile_c) { diff --git a/stdlib/ast_transformation.krak b/stdlib/ast_transformation.krak index 1e63f55..8c73c6b 100644 --- a/stdlib/ast_transformation.krak +++ b/stdlib/ast_transformation.krak @@ -44,7 +44,7 @@ obj ast_transformation (Object) { fourth_pass_worklist.destruct() } // first pass defines all type_defs (objects and aliases), ADTs, and top-level if-comps/passthroughs - fun first_pass(file_name: string, parse_tree: *tree, importer: *importer): pair<*ast_node, vector<*ast_node>> { + fun first_pass(file_name: string, parse_tree: *tree): pair<*ast_node, vector<*ast_node>> { var translation_unit = ast_translation_unit_ptr(file_name) parse_tree->children.for_each(fun(child: *tree) { if (child->data.name == "type_def") { diff --git a/stdlib/c_generator.krak b/stdlib/c_generator.krak index 0d6f2f3..390d037 100644 --- a/stdlib/c_generator.krak +++ b/stdlib/c_generator.krak @@ -165,7 +165,7 @@ obj c_generator (Object) { if (!backing.is_extern) function_definitions += prototype_and_header.second if (backing.body_statement) { - function_definitions += " {\n" + generate(backing.body_statement, enclosing_object, child, false) + function_definitions += " {\n" + generate(backing.body_statement, enclosing_object, child) function_definitions += ";\n}\n" } else if (!backing.is_extern) { error("Empty function statement and not extern - no ADTs anymore!") @@ -190,7 +190,7 @@ obj c_generator (Object) { tree_pair.second->translation_unit.children.for_each(fun(child: *ast_node) { match (*child) { ast_node::if_comp(backing) error("if_comp not currently supported") - ast_node::simple_passthrough(backing) error("simple_passthrough deprecated") + ast_node::simple_passthrough(backing) error("simple_passthrough removed") ast_node::declaration_statement(backing) variable_declarations += generate_declaration_statement(child, null(), null()) + ";\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) @@ -221,9 +221,7 @@ obj c_generator (Object) { type_poset.add_relationship(child, var_type->type_def) }) } - ast_node::adt_def(backing) { - error("ADT remaining!") - } + ast_node::adt_def(backing) error("ADT remaining!") } }) }) @@ -257,57 +255,48 @@ obj c_generator (Object) { fun generate_declaration_statement(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): string { 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 to_ret = type_to_c(identifier->identifier.type) + " " + get_name(identifier) if (identifier->identifier.is_extern) to_ret = "extern " + to_ret if (node->declaration_statement.expression) { - if (ident_type->is_function()) { - to_ret += ";\n" - to_ret += get_name(identifier) + " = " + generate(node->declaration_statement.expression, enclosing_object, enclosing_func, false) - } else { - // some shifting around to get it to work in all cases - // what cases? - to_ret += " = " + generate(node->declaration_statement.expression, enclosing_object, enclosing_func, false) - } + // in case of recursive closures, make sure variable is declared before assignment + to_ret += ";\n" + to_ret += get_name(identifier) + " = " + generate(node->declaration_statement.expression, enclosing_object, enclosing_func) } if (node->declaration_statement.init_method_call) { to_ret += ";\n" - to_ret += 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) } return to_ret } fun generate_assignment_statement(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): string { - return generate(node->assignment_statement.to, enclosing_object, enclosing_func, false) + " = " + generate(node->assignment_statement.from, enclosing_object, enclosing_func, false) + return generate(node->assignment_statement.to, enclosing_object, enclosing_func) + " = " + generate(node->assignment_statement.from, enclosing_object, enclosing_func) } fun generate_if_statement(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): string { - var if_str = "if (" + generate(node->if_statement.condition, enclosing_object, enclosing_func, false) + ") {\n" + generate(node->if_statement.then_part, enclosing_object, enclosing_func, false) + "}" + var if_str = "if (" + generate(node->if_statement.condition, enclosing_object, enclosing_func) + ") {\n" + generate(node->if_statement.then_part, enclosing_object, enclosing_func) + "}" if (node->if_statement.else_part) - if_str += " else {\n" + generate(node->if_statement.else_part, enclosing_object, enclosing_func, false) + "}" + if_str += " else {\n" + generate(node->if_statement.else_part, enclosing_object, enclosing_func) + "}" return if_str + "\n" } fun generate_while_loop(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): string { - return "while (" + generate(node->while_loop.condition, enclosing_object, enclosing_func, false) + ")\n" + generate(node->while_loop.statement, enclosing_object, enclosing_func, false) + return "while (" + generate(node->while_loop.condition, enclosing_object, enclosing_func) + ")\n" + generate(node->while_loop.statement, enclosing_object, enclosing_func) } fun generate_for_loop(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): string { - // gotta take off last semicolon var init = string(";") if (node->for_loop.init) - init = generate(node->for_loop.init, enclosing_object, enclosing_func, false) + init = generate(node->for_loop.init, enclosing_object, enclosing_func) var cond = string(";") if (node->for_loop.condition) - cond = generate(node->for_loop.condition, enclosing_object, enclosing_func, false) + cond = generate(node->for_loop.condition, enclosing_object, enclosing_func) + // gotta take off last semicolon var update = string() if (node->for_loop.update) { - update = generate(node->for_loop.update, enclosing_object, enclosing_func, false) + update = generate(node->for_loop.update, enclosing_object, enclosing_func) if (update.length() < 2) error("update less than 2! Likely legal, but need easy compiler mod here") update = update.slice(0,-2) } - var to_ret = string("for (") + init + cond + "; " + update + ")\n" + - generate(node->for_loop.body, enclosing_object, enclosing_func, false) - return to_ret + return "for (" + init + cond + "; " + update + ")\n" + generate(node->for_loop.body, enclosing_object, enclosing_func) } fun generate_identifier(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): string { if (get_ast_type(node)->is_ref) @@ -326,7 +315,7 @@ obj c_generator (Object) { error("still exsisting ref in return") if (return_value) - return "return " + generate(return_value, enclosing_object, enclosing_func, false) + return "return " + generate(return_value, enclosing_object, enclosing_func) return string("return") } fun generate_branching_statement(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): string { @@ -342,7 +331,7 @@ obj c_generator (Object) { error("remaining match") } fun generate_cast(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): string { - return "((" + type_to_c(node->cast.to_type) + ")(" + generate(node->cast.value, enclosing_object, enclosing_func, false) + "))" + return "((" + type_to_c(node->cast.to_type) + ")(" + generate(node->cast.value, enclosing_object, enclosing_func) + "))" } fun generate_value(node: *ast_node): string { var value = node->value.string_value @@ -370,14 +359,14 @@ obj c_generator (Object) { } fun generate_code_block(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): string { var to_ret = string("{\n") - node->code_block.children.for_each(fun(child: *ast_node) to_ret += generate(child, enclosing_object, enclosing_func, false) + ";\n";) + node->code_block.children.for_each(fun(child: *ast_node) to_ret += generate(child, enclosing_object, enclosing_func) + ";\n";) return to_ret + "}" } // this generates the function as a value, not the actual function fun generate_function(node: *ast_node): string { return get_name(node) } - fun generate_function_call(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node, need_variable: bool): string { + fun generate_function_call(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): string { var func_name = string() var call_string = string() var func_return_type = get_ast_type(node) @@ -390,9 +379,9 @@ obj c_generator (Object) { if (node->function_call.func->function_call.func->function.name == ".") call_string += "&" - call_string += generate(node->function_call.func->function_call.parameters[0], enclosing_object, enclosing_func, true) + call_string += generate(node->function_call.func->function_call.parameters[0], enclosing_object, enclosing_func) } else { - func_name = generate(node->function_call.func, enclosing_object, enclosing_func, false) + func_name = generate(node->function_call.func, enclosing_object, enclosing_func) // handle method call from inside method of same object if (enclosing_object && method_in_object(node->function_call.func, enclosing_object)) { @@ -406,25 +395,22 @@ obj c_generator (Object) { || func_name == "==" || func_name == "!=" || func_name == "%" || func_name == "^" || func_name == "|" || func_name == "&" || func_name == ">>" || func_name == "<<" )) - return "(" + generate(parameters[0], enclosing_object, enclosing_func, false) + func_name + generate(parameters[1], enclosing_object, enclosing_func, false) + ")" - if ( parameters.size == 2 && (func_name == "||" || func_name == "&&")) { + return "(" + generate(parameters[0], enclosing_object, enclosing_func) + func_name + generate(parameters[1], enclosing_object, enclosing_func) + ")" + if ( parameters.size == 2 && (func_name == "||" || func_name == "&&")) error("Remaining || or &&") - } // 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 "(" + generate(parameters[0], enclosing_object, enclosing_func, false) + func_name + generate(parameters[1], null(), null(), false) + ")" - } + if (func_name == "." || func_name == "->") + return "(" + generate(parameters[0], enclosing_object, enclosing_func) + func_name + generate(parameters[1], null(), null()) + ")" if (func_name == "[]") - return "(" + generate(parameters[0], enclosing_object, enclosing_func, false) + "[" + generate(parameters[1], enclosing_object, enclosing_func, false) + "])" + return "(" + generate(parameters[0], enclosing_object, enclosing_func) + "[" + generate(parameters[1], enclosing_object, enclosing_func) + "])" // the post ones need to be post-ed specifically, and take the p off if (func_name == "++p" || func_name == "--p") - return "(" + generate(parameters[0], enclosing_object, enclosing_func, false) + ")" + func_name.slice(0,-2) + return "(" + generate(parameters[0], enclosing_object, enclosing_func) + ")" + func_name.slice(0,-2) // So we don't end up copy_constructing etc, we just handle the unary operators right here - // note also the passing down need_variable for & if (func_name == "*" || func_name == "&") - return "(" + func_name + generate(parameters[0], enclosing_object, enclosing_func, func_name == "&") + ")" + return "(" + func_name + generate(parameters[0], enclosing_object, enclosing_func) + ")" var func_type = get_ast_type(node->function_call.func) // regular parameter generation @@ -443,8 +429,7 @@ obj c_generator (Object) { error(string("problem :") + (node->function_call.func) cast int + " " + get_fully_scoped_name(node->function_call.func) + ": still ref in function calling, func_type: " + func_type->to_string()) } - var param_type = get_ast_type(param) - call_string += generate(param, enclosing_object, enclosing_func, false) + call_string += generate(param, enclosing_object, enclosing_func) } call_string = func_name + "(" + call_string + ")" return call_string @@ -466,7 +451,7 @@ obj c_generator (Object) { } // for now, anyway - fun generate(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node, need_variable: bool): string { + fun generate(node: *ast_node, enclosing_object: *ast_node, enclosing_func: *ast_node): string { if (!node) return string("/*NULL*/") match (*node) { ast_node::declaration_statement(backing) return generate_declaration_statement(node, enclosing_object, enclosing_func) @@ -475,7 +460,7 @@ obj c_generator (Object) { ast_node::while_loop(backing) return generate_while_loop(node, enclosing_object, enclosing_func) ast_node::for_loop(backing) return generate_for_loop(node, enclosing_object, enclosing_func) ast_node::function(backing) return generate_function(node) - ast_node::function_call(backing) return generate_function_call(node, enclosing_object, enclosing_func, need_variable) + ast_node::function_call(backing) return generate_function_call(node, enclosing_object, enclosing_func) ast_node::compiler_intrinsic(backing) return generate_compiler_intrinsic(node) ast_node::code_block(backing) return generate_code_block(node, enclosing_object, enclosing_func) ast_node::return_statement(backing) return generate_return_statement(node, enclosing_object, enclosing_func) diff --git a/stdlib/importer.krak b/stdlib/importer.krak index 4bd53e7..2cbbb08 100644 --- a/stdlib/importer.krak +++ b/stdlib/importer.krak @@ -11,76 +11,49 @@ import ast_nodes:* import ast_transformation:* import parser:* -obj importer (Object) { - var parsers: vector - var ast_pass: ast_transformation - var name_ast_map: map,*ast_node>> - var import_paths: vector - fun construct(parsersIn: ref vector, ast_passIn: ref ast_transformation, import_paths_in: vector): *importer { - parsers.copy_construct(&parsersIn) - ast_pass.copy_construct(&ast_passIn) - name_ast_map.construct() - import_paths.copy_construct(&import_paths_in) - return this - } - fun copy_construct(old: *importer) { - parsers.copy_construct(&old->parsers) - ast_pass.copy_construct(&old->ast_pass) - name_ast_map.copy_construct(&old->name_ast_map) - import_paths.copy_construct(&old->import_paths) - } - fun operator=(old: ref importer) { - destruct() - copy_construct(&old) - } - fun destruct() { - parsers.destruct() - ast_pass.destruct() - name_ast_map.destruct() - import_paths.destruct() - } - fun import(file_name: string) { - // lambda closes over our fix-up list - var imports_to_fix = vector<*ast_node>() - var import_first_pass = fun(file_name_idx: pair) { - var file_name = file_name_idx.first - var file = string() - import_paths.for_each(fun(path: string) { - if (file_exists(path + file_name)) { - file = read_file(path + file_name) - } else { - } - }) - printerr(file_name + ", ") - var parse_tree = parsers[file_name_idx.second].parse_input(file, file_name) - trim(parse_tree) - var ast_and_imports = ast_pass.first_pass(file_name, parse_tree, this) - imports_to_fix += ast_and_imports.second - name_ast_map[file_name] = make_pair(parse_tree, ast_and_imports.first) - } - printlnerr("**First Pass**") - printerr("parsing: ") - import_first_pass(make_pair(file_name,0)) - for (var i = 0; i < imports_to_fix.size; i++;) { - var import_name = imports_to_fix[i]->import.name - var file_name = import_name + ".krak" - if (!name_ast_map.contains_key(file_name)) { - import_first_pass(make_pair(file_name,0)) +fun import(file_name: string, parsers: ref vector, ast_pass: ref ast_transformation, import_paths: vector): map,*ast_node>> { + var name_ast_map = map,*ast_node>>() + // lambda closes over our fix-up list + var imports_to_fix = vector<*ast_node>() + var import_first_pass = fun(file_name_idx: pair) { + var file_name = file_name_idx.first + var file = string() + import_paths.for_each(fun(path: string) { + if (file_exists(path + file_name)) { + file = read_file(path + file_name) + } else { } - var im = imports_to_fix[i] - var file_name = import_name + ".krak" - im->import.translation_unit = name_ast_map[file_name].second - add_to_scope(import_name, im->import.translation_unit, im->import.containing_translation_unit) - } - printlnerr() - printlnerr("**Second Pass**") - name_ast_map.for_each(fun(name: string, tree_pair: pair<*tree, *ast_node>) ast_pass.second_pass(tree_pair.first, tree_pair.second);) - printlnerr("**Third Pass**") - name_ast_map.for_each(fun(name: string, tree_pair: pair<*tree, *ast_node>) ast_pass.third_pass(tree_pair.first, tree_pair.second);) - // this needs to be modified to do chaotic iteration on instantiating template classes, based on what I see in the C++ version - printlnerr("**Fourth Pass**") - name_ast_map.for_each(fun(name: string, tree_pair: pair<*tree, *ast_node>) ast_pass.fourth_pass(tree_pair.first, tree_pair.second);) + }) + printerr(file_name + ", ") + var parse_tree = parsers[file_name_idx.second].parse_input(file, file_name) + trim(parse_tree) + var ast_and_imports = ast_pass.first_pass(file_name, parse_tree) + imports_to_fix += ast_and_imports.second + name_ast_map[file_name] = make_pair(parse_tree, ast_and_imports.first) } + printlnerr("**First Pass**") + printerr("parsing: ") + import_first_pass(make_pair(file_name,0)) + for (var i = 0; i < imports_to_fix.size; i++;) { + var import_name = imports_to_fix[i]->import.name + var file_name = import_name + ".krak" + if (!name_ast_map.contains_key(file_name)) { + import_first_pass(make_pair(file_name,0)) + } + var im = imports_to_fix[i] + var file_name = import_name + ".krak" + im->import.translation_unit = name_ast_map[file_name].second + add_to_scope(import_name, im->import.translation_unit, im->import.containing_translation_unit) + } + printlnerr() + printlnerr("**Second Pass**") + name_ast_map.for_each(fun(name: string, tree_pair: pair<*tree, *ast_node>) ast_pass.second_pass(tree_pair.first, tree_pair.second);) + printlnerr("**Third Pass**") + name_ast_map.for_each(fun(name: string, tree_pair: pair<*tree, *ast_node>) ast_pass.third_pass(tree_pair.first, tree_pair.second);) + printlnerr("**Fourth Pass**") + name_ast_map.for_each(fun(name: string, tree_pair: pair<*tree, *ast_node>) ast_pass.fourth_pass(tree_pair.first, tree_pair.second);) + + return name_ast_map } fun trim(parse_tree: *tree): *tree { @@ -134,17 +107,9 @@ fun remove_node(remove: symbol, parse_tree: *tree) { var node = to_process.pop() for (var i = 0; i < node->children.size; i++;) { if (!node->children[i] || node->children[i]->data.equal_wo_data(remove)) { - /* - if (!node->children[i]) - println("not because null") - else { - print("not because "); println(remove.name) - } - */ node->children.remove(i) i--; } else { - /*println(remove.to_string() + " not equal " + node->children[i]->data.to_string())*/ to_process.push(node->children[i]) } }