import io:* import mem:* import map:* import hash_map:* import stack:* import str:* import util:* import tree:* import symbol:* import ast_nodes:* // for error with syntax tree import pass_common:* import poset:* obj c_generator (Object) { var id_counter: int var ast_name_map: hash_map<*ast_node, str> var used_names: hash_set var function_type_map: map var replacement_map: map var longest_replacement: int var function_typedef_string: str var linker_string: str fun construct(): *c_generator { id_counter = 0 ast_name_map.construct() used_names.construct() // to avoid using c keywords used_names.add(str("extern")) used_names.add(str("register")) function_type_map.construct() function_typedef_string.construct() linker_string.construct() replacement_map.construct() replacement_map[str("+")] = str("plus") replacement_map[str("-")] = str("minus") replacement_map[str("*")] = str("star") replacement_map[str("/")] = str("div") replacement_map[str("%")] = str("mod") replacement_map[str("^")] = str("carat") replacement_map[str("&")] = str("amprsd") replacement_map[str("|")] = str("pipe") replacement_map[str("~")] = str("tilde") replacement_map[str("!")] = str("exlmtnpt") replacement_map[str(",")] = str("comma") replacement_map[str("=")] = str("eq") replacement_map[str("++")] = str("dbplus") replacement_map[str("--")] = str("dbminus") replacement_map[str("<<")] = str("dbleft") replacement_map[str(">>")] = str("dbright") replacement_map[str("::")] = str("scopeop") replacement_map[str(":")] = str("colon") replacement_map[str("==")] = str("dbq") replacement_map[str("!=")] = str("notequals") replacement_map[str("&&")] = str("doubleamprsnd") replacement_map[str("||")] = str("doublepipe") replacement_map[str("+=")] = str("plusequals") replacement_map[str("-=")] = str("minusequals") replacement_map[str("/=")] = str("divequals") replacement_map[str("%=")] = str("modequals") replacement_map[str("^=")] = str("caratequals") replacement_map[str("&=")] = str("amprsdequals") replacement_map[str("|=")] = str("pipeequals") replacement_map[str("*=")] = str("starequals") replacement_map[str("<<=")] = str("doublerightequals") replacement_map[str("<")] = str("lt") replacement_map[str(">")] = str("gt") replacement_map[str(">>=")] = str("doubleleftequals") replacement_map[str("(")] = str("openparen") replacement_map[str(")")] = str("closeparen") replacement_map[str("[")] = str("obk") replacement_map[str("]")] = str("cbk") replacement_map[str(" ")] = str("_") replacement_map[str(".")] = str("dot") replacement_map[str("->")] = str("arrow") longest_replacement = 0 replacement_map.for_each(fun(key: str, value: str) { if (key.length() > longest_replacement) longest_replacement = key.length() }) return this } fun copy_construct(old: *c_generator) { id_counter = old->id_counter ast_name_map.copy_construct(&old->ast_name_map) used_names.copy_construct(&old->used_names) function_type_map.copy_construct(&old->function_type_map) function_typedef_string.copy_construct(&old->function_typedef_string) replacement_map.copy_construct(&old->replacement_map) longest_replacement = old->longest_replacement linker_string.copy_construct(&old->linker_string) } fun operator=(other: ref c_generator) { destruct() copy_construct(&other) } fun destruct() { ast_name_map.destruct() used_names.destruct() function_type_map.destruct() function_typedef_string.destruct() replacement_map.destruct() linker_string.destruct() } fun get_id(): str return to_string(id_counter++); fun generate_function_prototype_and_header(child: *ast_node):pair { var backing = child->function var parameter_types = str() var parameters = str() var decorated_name = str() if (backing.is_extern) decorated_name = backing.name else decorated_name = generate_function(child) 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) }) if (backing.is_variadic) { parameter_types += ", ..." parameters += ", ..." } 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>>, ast_to_syntax_in: map<*ast_node, *tree> ): pair { var prequal: str = "#include \n" var plain_typedefs: str = "\n/**Plain Typedefs**/\n" var top_level_c_passthrough: str = "" var variable_extern_declarations: str = "" var structs: str = "\n/**Type Structs**/\n" function_typedef_string = "\n/**Typedefs**/\n" var function_prototypes: str = "\n/**Function Prototypes**/\n" var function_definitions: str = "\n/**Function Definitions**/\n" var variable_declarations: str = "\n/**Variable Declarations**/\n" // 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) { var backing = child->function var prototype_and_header = generate_function_prototype_and_header(child) function_prototypes += prototype_and_header.first if (!backing.is_extern) function_definitions += prototype_and_header.second if (backing.body_statement) { function_definitions += " {\n" + generate(backing.body_statement) function_definitions += ";\n}\n" } } var type_poset = poset<*ast_node>() // iterate through asts name_ast_map.for_each(fun(name: str, tree_pair: pair<*tree,*ast_node>) { // iterate through children for each ast // 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) { generate_function_definition(child) }) 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 removed") ast_node::declaration_statement(backing) variable_declarations += generate_declaration_statement(child) + ";\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) { // check for and add to parameters if a closure generate_function_definition(child) } ast_node::template(backing) { backing.instantiated.for_each(fun(node: *ast_node) { match (*node) { ast_node::function(backing) generate_function_definition(node) ast_node::type_def(backing) { type_poset.add_job(node) backing.variables.for_each(fun(i: *ast_node) { var var_type = get_ast_type(i->declaration_statement.identifier) if (!var_type->indirection && var_type->type_def) type_poset.add_open_dep(node, var_type->type_def) }) } } }) } ast_node::type_def(backing) { type_poset.add_job(child) backing.variables.for_each(fun(i: *ast_node) { var var_type = get_ast_type(i->declaration_statement.identifier) if (!var_type->indirection && var_type->type_def) type_poset.add_open_dep(child, var_type->type_def) }) } ast_node::adt_def(backing) error("ADT remaining!") } }) }) type_poset.get_sorted().for_each(fun(vert: *ast_node) { var base_name = get_name(vert) plain_typedefs += str("typedef ") if (vert->type_def.is_union) { plain_typedefs += "union " structs += "union " } else { plain_typedefs += "struct " structs += "struct " } plain_typedefs += base_name + "_dummy " + base_name + ";\n" structs += base_name + "_dummy {\n" vert->type_def.variables.for_each(fun(variable_declaration: *ast_node) structs += generate_declaration_statement(variable_declaration) + ";\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);) else generate_function_definition(method); }) structs += "};\n" }) return make_pair(prequal+plain_typedefs+function_typedef_string+top_level_c_passthrough+variable_extern_declarations+structs+function_prototypes+variable_declarations+function_definitions + "\n", linker_string) } fun generate_declaration_statement(node: *ast_node): str { var identifier = node->declaration_statement.identifier var ident_type = identifier->identifier.type 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) { // 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)*/ to_ret += " = " + generate(node->declaration_statement.expression) } if (node->declaration_statement.init_method_call) { error("init_method_call remaining") } return to_ret } fun generate_assignment_statement(node: *ast_node): str { return generate(node->assignment_statement.to) + " = " + generate(node->assignment_statement.from) } fun generate_if_statement(node: *ast_node): str { var if_str = "if (" + generate(node->if_statement.condition) + ") {\n" + generate(node->if_statement.then_part) + "}" if (node->if_statement.else_part) if_str += " else {\n" + generate(node->if_statement.else_part) + "}" return if_str + "\n" } fun generate_while_loop(node: *ast_node): str { return "while (" + generate(node->while_loop.condition) + ")\n" + generate(node->while_loop.statement) } fun generate_for_loop(node: *ast_node): str { var init = str(";") if (node->for_loop.init) init = generate(node->for_loop.init) var cond = str(";") if (node->for_loop.condition) cond = generate(node->for_loop.condition) // gotta take off last semicolon var update = str() if (node->for_loop.update) { update = generate(node->for_loop.update) if (update.length() < 2) error("update less than 2! Likely legal, but need easy compiler mod here") update = update.slice(0,-2) } return "for (" + init + cond + "; " + update + ")\n" + generate(node->for_loop.body) } fun generate_identifier(node: *ast_node): str { if (get_ast_type(node)->is_ref) error("still existin ref in identifier") return get_name(node) } fun generate_return_statement(node: *ast_node): str { if (node->return_statement.return_value) return "return " + generate(node->return_statement.return_value) return str("return") } fun generate_branching_statement(node: *ast_node): str { match(node->branching_statement.b_type) { branching_type::break_stmt() return str("break") branching_type::continue_stmt() return str("continue") } } fun generate_cast(node: *ast_node): str { return "((" + type_to_c(node->cast.to_type) + ")(" + generate(node->cast.value) + "))" } fun generate_value(node: *ast_node): str { var value = node->value.string_value if (node->value.value_type->base == base_type::character() && node->value.value_type->indirection == 0) return "'" + value + "'" if (node->value.value_type->base != base_type::character() || node->value.value_type->indirection != 1) return value var to_ret = str("\"") //" value.for_each(fun(c: char) { if (c == '\n') to_ret += "\\n" else if (c == '\\') to_ret += "\\\\" else if (c == '"') to_ret += "\\\"" else to_ret += c }) return to_ret + "\"" } fun generate_code_block(node: *ast_node): str { var to_ret = str("{\n") node->code_block.children.for_each(fun(child: *ast_node) to_ret += generate(child) + ";\n";) return to_ret + "}" } // this generates the function as a value, not the actual function fun generate_function(node: *ast_node): str { return get_name(node) } fun generate_function_call(node: *ast_node): str { var func_name = generate(node->function_call.func) var call_string = str() var func_return_type = get_ast_type(node) var parameters = node->function_call.parameters if ( parameters.size == 2 && (func_name == "+" || func_name == "-" || func_name == "*" || func_name == "/" || func_name == "<" || func_name == ">" || func_name == "<=" || func_name == ">=" || func_name == "==" || func_name == "!=" || func_name == "%" || func_name == "^" || func_name == "|" || func_name == "&" || func_name == ">>" || func_name == "<<" )) return "(" + generate(parameters[0]) + func_name + generate(parameters[1]) + ")" 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]) + func_name + generate(parameters[1]) + ")" if (func_name == "[]") return "(" + generate(parameters[0]) + "[" + generate(parameters[1]) + "])" // 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]) + ")" + func_name.slice(0,-2) // So we don't end up copy_constructing etc, we just handle the unary operators right here if (func_name == "*" || func_name == "&") return "(" + func_name + generate(parameters[0]) + ")" var func_type = get_ast_type(node->function_call.func) // regular parameter generation for (var i = 0; i < parameters.size; i++;) { var param = parameters[i] var in_function_param_type = null() // grab type from param itself if we're out of param types (because variadic function) if (i < func_type->parameter_types.size) in_function_param_type = func_type->parameter_types[i] else in_function_param_type = get_ast_type(param)->clone_without_ref() if (call_string != "") call_string += ", " call_string += generate(param) } call_string = func_name + "(" + call_string + ")" return call_string } fun generate_compiler_intrinsic(node: *ast_node): str { if (node->compiler_intrinsic.intrinsic == "sizeof") { if (node->compiler_intrinsic.parameters.size || node->compiler_intrinsic.type_parameters.size != 1) error("wrong parameters to sizeof compiler intrinsic") return "sizeof(" + type_to_c(node->compiler_intrinsic.type_parameters[0]) + ")" } else if (node->compiler_intrinsic.intrinsic == "link") { node->compiler_intrinsic.parameters.for_each(fun(value: *ast_node) { linker_string += str("-l") + value->value.string_value + " " }) return str() } error(node->compiler_intrinsic.intrinsic + ": unknown intrinsic") return str("ERROR") } fun generate(node: *ast_node): str { if (!node) return str("/*NULL*/") match (*node) { ast_node::declaration_statement(backing) return generate_declaration_statement(node) ast_node::assignment_statement(backing) return generate_assignment_statement(node) ast_node::if_statement(backing) return generate_if_statement(node) ast_node::while_loop(backing) return generate_while_loop(node) ast_node::for_loop(backing) return generate_for_loop(node) ast_node::function(backing) return generate_function(node) ast_node::function_call(backing) return generate_function_call(node) ast_node::compiler_intrinsic(backing) return generate_compiler_intrinsic(node) ast_node::code_block(backing) return generate_code_block(node) ast_node::return_statement(backing) return generate_return_statement(node) ast_node::branching_statement(backing) return generate_branching_statement(node) ast_node::defer_statement(backing) error("unremoved defer") ast_node::match_statement(backing) error("unremoved match") ast_node::cast(backing) return generate_cast(node) ast_node::value(backing) return generate_value(node) ast_node::identifier(backing) return generate_identifier(node) } error(str("COULD NOT GENERATE ") + get_ast_name(node)) return str("/* COULD NOT GENERATE */") } fun type_to_c(type: *type): str { var indirection = str() if (type->is_ref) error("still ref in type_to_c") //indirection += "/*ref*/ *" for (var i = 0; i < type->indirection; i++;) indirection += "*" match (type->base) { base_type::none() return str("none") + indirection base_type::template() return str("template") + indirection base_type::template_type() return str("template_type") + indirection base_type::void_return() return str("void") + indirection base_type::boolean() return str("bool") + indirection base_type::character() return str("char") + indirection base_type::ucharacter() return str("unsigned char") + indirection base_type::short_int() return str("short") + indirection base_type::ushort_int() return str("unsigned short") + indirection base_type::integer() return str("int") + indirection base_type::uinteger() return str("unsigned int") + indirection base_type::long_int() return str("long") + indirection base_type::ulong_int() return str("unsigned long") + indirection base_type::floating() return str("float") + indirection base_type::double_precision() return str("double") + indirection base_type::object() return get_name(type->type_def) + indirection base_type::function() { type = type->clone_with_indirection(0,false) if (!function_type_map.contains_key(*type)) { var temp_name = str("function") + get_id() var temp = str() type->parameter_types.for_each(fun(parameter_type: *type) { temp += str(", ") + type_to_c(parameter_type) + " " temp_name += "_" + cify_name(type_to_c(parameter_type)) }) if (type->is_raw) function_typedef_string += str("typedef ") + type_to_c(type->return_type) + " (*" + temp_name + ")(" + temp.slice(1,-1) + ");\n" else error(type->to_string() + " is not raw!") // again, the indirection function_type_map[*type] = temp_name } return function_type_map[*type] + indirection } } return str("impossible type") + indirection } fun type_decoration(type: *type): str { return cify_name(type->to_string()) } fun get_name(node: *ast_node): str { var maybe_it = ast_name_map.get_ptr_or_null(node); if (maybe_it) return *maybe_it var result = str("impossible name") var make_unique = true match (*node) { ast_node::type_def(backing) { var upper = backing.scope[str("~enclosing_scope")][0] result = cify_name(backing.name) if (is_template(upper)) upper->template.instantiated_map.reverse_get(node).for_each(fun(t: ref type) result += str("_") + type_decoration(&t);) } ast_node::function(backing) { // be careful, operators like . come through this if (backing.name == "main" || backing.is_extern || !backing.body_statement) { result = backing.name make_unique = false } else { result = "fun_" var upper = backing.scope.get_with_default(str("~enclosing_scope"), vec(null()))[0] if (upper && is_type_def(upper)) result += get_name(upper) + "_" result += cify_name(node->function.name) node->function.parameters.for_each(fun(param: *ast_node) result += str("_") + type_decoration(param->identifier.type);) } } ast_node::identifier(backing) { if (backing.name == "this" || backing.is_extern) make_unique = false result = backing.name } } if (result == "impossible name") error("HUGE PROBLEMS") if (make_unique && used_names.contains(result)) result += get_id() ast_name_map.set(node, result) used_names.add(result) return result } fun cify_name(name: str): str { var to_ret = str() for (var i = 0; i < name.length(); i++;) { var replaced = false for (var j = longest_replacement; j > 0; j--;) { if (i + j <= name.length() && replacement_map.contains_key(name.slice(i,i+j))) { to_ret += replacement_map[name.slice(i,i+j)] replaced = true i += j-1; break } } if (!replaced) to_ret += name[i] } return to_ret } }