import symbol:* import tree:* import vector:* import stack:* import map:* import util:* import string:* import mem:* import io:* import importer:* import ast_nodes:* import type:* /*Importer * importer;*/ /*NodeTree* builtin_trans_unit; // the top scope for language level stuff*/ /*std::map*>> languageLevelReservedWords;*/ /*std::map*>> languageLevelOperators;*/ /*std::map*, NodeTree*> this_map; // used to map implicit "this" variables to their type*/ /*NodeTree* topScope; //maintained for templates that need to add themselves to the top scope no matter where they are instantiated*/ /*int lambdaID = 0;*/ obj ast_transformation (Object) { var ast_to_syntax: map<*ast_node, *tree> fun construct(): *ast_transformation { ast_to_syntax.construct() return this } fun copy_construct(old: *ast_transformation) { ast_to_syntax.copy_construct(&old->ast_to_syntax) } fun operator=(old: ref ast_transformation) { destruct() copy_construct(&old) } fun destruct() { ast_to_syntax.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): *ast_node { var translation_unit = ast_translation_unit_ptr(file_name) importer->register(file_name, parse_tree, translation_unit) parse_tree->children.for_each(fun(child: *tree) { if (child->data.name == "type_def") { var name = concat_symbol_tree(get_node("identifier", child)) var type_def_node = ast_type_def_ptr(name) translation_unit->translation_unit.children.add(type_def_node) ast_to_syntax.set(type_def_node, child) add_to_scope("~enclosing_scope", translation_unit, type_def_node) add_to_scope(name, type_def_node, translation_unit) // set up type - self-referential, traits, template, etc } 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) 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) add_to_scope(name, adt_def_node, translation_unit) } else if (child->data.name == "if_comp") { var if_comp_node = transform_if_comp(child, translation_unit) translation_unit->translation_unit.children.add(if_comp_node) ast_to_syntax.set(if_comp_node, child) } }) // now do all imports (done second so that if it imports this translation_unit, // this one already has all its types defined parse_tree->children.for_each(fun(child: *tree) { if (child->data.name == "import") { var import_identifier_children = get_nodes("identifier", child) var name = concat_symbol_tree(import_identifier_children[0]) var outside_translation_unit = importer->import_first_pass(name + ".krak") add_to_scope(name, outside_translation_unit, translation_unit) var import_node = ast_import_ptr(name, outside_translation_unit) translation_unit->translation_unit.children.add(import_node) ast_to_syntax.set(import_node, child) add_to_scope("~enclosing_scope", translation_unit, import_node) import_node->import.imported = from_vector(import_identifier_children.slice(1,-1).map(fun(ident: *tree):string return concat_symbol_tree(ident);)) } }) return translation_unit } // defines inside of objects + ADTs, outside declaration statements, and function prototypes fun second_pass(parse_tree: *tree, translation_unit: *ast_node) { println(string("Second Pass for ") + translation_unit->translation_unit.name) parse_tree->children.for_each(fun(child: *tree) { if (child->data.name == "type_def") { // second pass class stuff // class insides calls into second_pass_declaration and second_pass_function... } else if (child->data.name == "adt_def") { // set up options and all the generated functions (operator==, operator!=, copy_construct, operator=, destruct) } else if (child->data.name == "function") { var function_node = second_pass_function(child, translation_unit, map()) translation_unit->translation_unit.children.add(function_node) ast_to_syntax.set(function_node, child) } else if (child->data.name == "declaration_statement") { // second pass declaration can actually just call a normal transform (but maybe should be it's own method to do so because typedef has to do it too?)... } }) } fun second_pass_function(node: *tree, translation_unit: *ast_node, template_replacements: map): *ast_node { var function_name = concat_symbol_tree(get_node("func_identifier", node)) // check to see if it is a template // figure out return type var typed_return_node = get_node("typed_return", node) // darn no ternary yet var return_type = null() if (typed_return_node) return_type = transform_type(get_node("type", typed_return_node), translation_unit, template_replacements) else return_type = type_ptr(base_type::void_return()) // transform parameters var parameters = vector<*ast_node>() get_nodes("typed_parameter", node).for_each(fun(child: *tree) { parameters.add(ast_identifier_ptr(concat_symbol_tree(get_node("identifier", child)), transform_type(get_node("type", child), translation_unit, template_replacements))) }) // figure out function type and make function_node var function_node = ast_function_ptr(function_name, type_ptr(parameters.map(fun(parameter: *ast_node): *type return parameter->identifier.type;), return_type), parameters) // add to scope (translation_unit) add_to_scope(function_name, function_node, translation_unit) add_to_scope("~enclosing_scope", translation_unit, function_node) // add parameters to scope of function parameters.for_each(fun(parameter: *ast_node) add_to_scope(parameter->identifier.name, parameter, function_node);) return function_node } // The third pass finishes up by doing all function bodies (top level and methods in objects) fun third_pass(parse_tree: *tree, translation_unit: *ast_node) { println(string("Third Pass for ") + translation_unit->translation_unit.name) translation_unit->translation_unit.children.for_each(fun(node: *ast_node) { match(*node) { ast_node::type_def(backing) do_nothing() // actually go through and do methods inside ast_node::function(backing) { // make sure not a template // huh, I guess I can't actually assign to the backing. // This is actually a little bit of a problem, maybe these should be pointers also. All the pointers! node->function.body_statement = transform_statement(get_node("statement", ast_to_syntax[node]), translation_unit) } } }) } // The fourth pass generates the class templates that have not yet been generated in a "chaotic iteration" loop fun fourth_pass(parse_tree: *tree, translation_unit: *ast_node) { println(string("Fourth Pass for ") + translation_unit->translation_unit.name) } fun transform_type(node: *tree, scope: *ast_node, template_replacements: map): *type { // check for references and step down // always get to pre-reffed level var real_node = get_node("pre_reffed", node) // check for indirection and step down var indirection = 0 while (get_node("pre_reffed", real_node)) { real_node = get_node("pre_reffed", real_node) indirection++ } var type_syntax_str = concat_symbol_tree(real_node) println(type_syntax_str + " *************************") // should take into account indirection and references... if (type_syntax_str == "void") return type_ptr(base_type::void_return(), indirection) else if (type_syntax_str == "bool") return type_ptr(base_type::boolean(), indirection) else if (type_syntax_str == "int") return type_ptr(base_type::integer(), indirection) else if (type_syntax_str == "float") return type_ptr(base_type::floating(), indirection) else if (type_syntax_str == "double") return type_ptr(base_type::double_precision(), indirection) else if (type_syntax_str == "char") return type_ptr(base_type::character(), indirection) else if (/* check for function type*/ false) return type_ptr(base_type::function(), indirection) else { // do lookup for objects, ADTs, templates, etc return type_ptr(base_type::none(), indirection) } } /*NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree* scope, std::vector types, bool limitToFunction, std::map templateTypeReplacements) {*/ fun transform(node: *tree, scope: *ast_node): *ast_node { var name = node->data.name if (name == "identifier" || name == "scoped_identifier") { return transform_identifier(node, scope) } else if (name == "code_block") { return transform_code_block(node, scope) } else if (name == "if_comp") { return transform_if_comp(node, scope) } else if (name == "simple_passthrough") { return transform_simple_passthrough(node, scope) } else if (name == "statement") { return transform_statement(node, scope) } else if (name == "return_statement") { return transform_return_statement(node, scope) } else if (name == "function_call") { return transform_function_call(node, scope) } else if (name == "boolean_expression" || name == "and_boolean_expression" || name == "bool_exp" || name == "expression" || name == "shiftand" || name == "term" || name == "factor" || name == "unarad" ) { // for now, assume passthrough and just transform underneath return transform_expression(node, scope) } else if (name == "bool" || name == "string" || name == "character" || name == "number" ) { println(string("transforming value: ") + name) return transform_value(node, scope) } print("FAILED TO TRANSFORM: "); println(concat_symbol_tree(node)) return null() } fun transform_all(nodes: vector<*tree>, scope: *ast_node): vector<*ast_node> { return nodes.map(fun(node: *tree): *ast_node return transform(node, scope);) } fun transform_identifier(node: *tree, scope: *ast_node): *ast_node { // for identifier we have to do scope lookup, etc, and maybe limit to function // NOT THIS var name = concat_symbol_tree(node) /*return ast_identifier_ptr(name, type_ptr(base_type::void_return()))*/ return identifier_lookup(name, scope) } fun transform_value(node: *tree, scope: *ast_node): *ast_node { var value_str = concat_symbol_tree(node) var value_type = null() if (value_str[0] == '"') value_type = type_ptr(base_type::character(), 1) else if (value_str[0] == '\'') //' lol, comment hack for vim syntax highlighting (my fault, of course) value_type = type_ptr(base_type::character()) else { // should differentiate between float and double... var contains_dot = false for (var i = 0; i < value_str.length(); i++;) { if (value_str[i] == '.') { contains_dot = true break } } if (contains_dot) value_type = type_ptr(base_type::floating()) else value_type = type_ptr(base_type::integer()) } return ast_value_ptr(value_str, value_type) } fun transform_expression(node: *tree, scope: *ast_node): *ast_node { // figure out what the expression is, handle overloads, or you know // ignore everything and do a passthrough /*println(string("passing through: ") + node->data.name)*/ return transform(node->children[0], scope) } fun transform_code_block(node: *tree, scope: *ast_node): *ast_node { var new_block = ast_code_block_ptr() add_to_scope("~enclosing_scope", scope, new_block) new_block->code_block.children = transform_all(node->children, new_block) return new_block } fun transform_if_comp(node: *tree, scope: *ast_node): *ast_node { var new_if_comp = ast_if_comp_ptr() new_if_comp->if_comp.wanted_generator = concat_symbol_tree(get_node("identifier", node)) new_if_comp->if_comp.statement = transform_statement(get_node("statement", node), scope) return new_if_comp } fun transform_simple_passthrough(node: *tree, scope: *ast_node): *ast_node { var new_passthrough = ast_simple_passthrough_ptr() // setup passthrough params and string new_passthrough->simple_passthrough.passthrough_str = concat_symbol_tree(get_node("triple_quoted_string", node)).slice(3,-4) return new_passthrough } fun transform_statement(node: *tree, scope: *ast_node): *ast_node { var new_statement = ast_statement_ptr() new_statement->statement.child = transform(node->children[0], scope) return new_statement } fun transform_return_statement(node: *tree, scope: *ast_node): *ast_node { return ast_return_statement_ptr(transform(node->children[0], scope)) } fun transform_function_call(node: *tree, scope: *ast_node): *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);) var parameter_types = parameters.map(fun(param: *ast_node): *type return get_ast_type(param);) /*return ast_function_call_ptr(function_lookup(concat_symbol_tree(get_node("unarad", node)), scope), parameters)*/ var f = ast_function_call_ptr(function_lookup(concat_symbol_tree(get_node("unarad", node)), scope, parameter_types), parameters) print("function call function ") println(f->function_call.func) print("function call parameters ") f->function_call.parameters.for_each(fun(param: *ast_node) print(param);) return f } fun identifier_lookup(name: string, scope: *ast_node): *ast_node { var results = scope_lookup(name, scope) if (!results.size) { println(string("identifier lookup failed for ") + name) return null() } return results[0] } fun function_lookup(name: string, scope: *ast_node, param_types: vector<*type>): *ast_node { var results = scope_lookup(name, scope) if (!results.size) { println(string("identifier lookup failed for ") + name) return null() } return results[0] } fun scope_lookup(name: string, scope: *ast_node): vector<*ast_node> { // need to do properly scopded lookups // prevent re-checking the same one... print("scope is: ") get_ast_scope(scope)->for_each(fun(key: string, value: vector<*ast_node>) print(key + " ");) println() var results = vector<*ast_node>() if (get_ast_scope(scope)->contains_key(name)) { println(name + " is in scope, adding to results") results += get_ast_scope(scope)->get(name) } if (get_ast_scope(scope)->contains_key(string("~enclosing_scope"))) results += scope_lookup(name, get_ast_scope(scope)->get(string("~enclosing_scope"))[0]) if (is_translation_unit(scope)) { scope->translation_unit.children.for_each(fun(child: *ast_node) { if (is_import(child) && child->import.imported.contains(name)) { println(name + " is indeed imported") results += scope_lookup(name, child->import.translation_unit) } else println(name + " is not imported (this time)") }) } return results } } fun concat_symbol_tree(node: *tree): string { var str.construct(): string if (node->data.data != "no_value") str += node->data.data node->children.for_each(fun(child: *tree) str += concat_symbol_tree(child);) return str } fun get_node(lookup: *char, parent: *tree): *tree { return get_node(string(lookup), parent) } fun get_node(lookup: string, parent: *tree): *tree { var results = get_nodes(lookup, parent) if (results.size > 1) println("too many results!") if (results.size) return results[0] return null>() } fun get_nodes(lookup: *char, parent: *tree): vector<*tree> { return get_nodes(string(lookup), parent) } fun get_nodes(lookup: string, parent: *tree): vector<*tree> { return parent->children.filter(fun(node: *tree):bool return node->data.name == lookup;) } fun add_to_scope(name: *char, to_add: *ast_node, add_to: *ast_node) { add_to_scope(string(name), to_add, add_to) } fun add_to_scope(name: string, to_add: *ast_node, add_to: *ast_node) { var add_to_map = get_ast_scope(add_to) if (add_to_map->contains_key(name)) (*add_to_map)[name].add(to_add) else add_to_map->set(name, vector(to_add)) }