873 lines
50 KiB
Plaintext
873 lines
50 KiB
Plaintext
import symbol:*
|
|
import tree:*
|
|
import vector:*
|
|
import stack:*
|
|
import map:*
|
|
import util:*
|
|
import string:*
|
|
import mem:*
|
|
import io:*
|
|
import os:*
|
|
import importer:*
|
|
import ast_nodes:*
|
|
import type:*
|
|
|
|
adt search_type {
|
|
none,
|
|
function: vector<*type>
|
|
}
|
|
|
|
obj ast_transformation (Object) {
|
|
var ast_to_syntax: map<*ast_node, *tree<symbol>>
|
|
var fourth_pass_worklist: queue<*ast_node>
|
|
fun construct(): *ast_transformation {
|
|
ast_to_syntax.construct()
|
|
fourth_pass_worklist.construct()
|
|
return this
|
|
}
|
|
fun copy_construct(old: *ast_transformation) {
|
|
ast_to_syntax.copy_construct(&old->ast_to_syntax)
|
|
fourth_pass_worklist.copy_construct(&old->fourth_pass_worklist)
|
|
}
|
|
fun operator=(old: ref ast_transformation) {
|
|
destruct()
|
|
copy_construct(&old)
|
|
}
|
|
fun destruct() {
|
|
ast_to_syntax.destruct()
|
|
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<symbol>, 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<symbol>) {
|
|
if (child->data.name == "type_def") {
|
|
translation_unit->translation_unit.children.add(first_pass_type_def(child, translation_unit, false))
|
|
} 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<symbol>) {
|
|
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<symbol>):string return concat_symbol_tree(ident);))
|
|
if (get_node("\"\\*\"", child))
|
|
import_node->import.starred = true
|
|
}
|
|
})
|
|
return translation_unit
|
|
}
|
|
fun first_pass_type_def(child: *tree<symbol>, scope: *ast_node, instantiate_template: bool): *ast_node {
|
|
var name = concat_symbol_tree(get_node("identifier", child))
|
|
var template_dec = get_node("template_dec", child)
|
|
if (template_dec && !instantiate_template) {
|
|
var template_types = vector<string>()
|
|
var template_type_replacements = map<string, *type>()
|
|
// XXX add traits
|
|
get_nodes("template_param", template_dec).for_each(fun(template_param: *tree<symbol>) {
|
|
template_types.add(concat_symbol_tree(get_node("identifier", template_param)))
|
|
template_type_replacements.set(template_types.last(), type_ptr(vector<string>()))
|
|
})
|
|
var template = ast_template_ptr(name, child, template_types, template_type_replacements, false)
|
|
add_to_scope("~enclosing_scope", scope, template)
|
|
add_to_scope(name, template, scope)
|
|
return template
|
|
} else {
|
|
var type_def_node = ast_type_def_ptr(name)
|
|
type_def_node->type_def.self_type = type_ptr(type_def_node)
|
|
ast_to_syntax.set(type_def_node, child)
|
|
add_to_scope("~enclosing_scope", scope, type_def_node)
|
|
add_to_scope(name, type_def_node, scope)
|
|
return type_def_node
|
|
}
|
|
}
|
|
// defines inside of objects + ADTs, outside declaration statements, and function prototypes
|
|
fun second_pass(parse_tree: *tree<symbol>, translation_unit: *ast_node) {
|
|
println(string("Second Pass for ") + translation_unit->translation_unit.name)
|
|
// we go through the parse tree for getting functions, but we're going through the ast for the things we've already set up and using the ast_to_syntax map
|
|
parse_tree->children.for_each(fun(child: *tree<symbol>) {
|
|
if (child->data.name == "function") {
|
|
// also handles templated function
|
|
var function_node = second_pass_function(child, translation_unit, map<string, *type>(), true)
|
|
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?)...
|
|
translation_unit->translation_unit.children.add(transform_declaration_statement(child, translation_unit, map<string, *type>()))
|
|
}
|
|
})
|
|
// work on the ones already started
|
|
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<string, *type>())
|
|
ast_node::adt_def(backing) do_nothing() // actually go through and do methods inside
|
|
}
|
|
})
|
|
}
|
|
fun second_pass_type_def(type_def_syntax: *tree<symbol>, node: *ast_node, scope: *ast_node, template_replacements: map<string, *type>) {
|
|
type_def_syntax->children.for_each(fun(child: *tree<symbol>) {
|
|
if (child->data.name == "declaration_statement") {
|
|
var declaration_node = transform_declaration_statement(child, node, template_replacements)
|
|
node->type_def.variables.add(declaration_node)
|
|
ast_to_syntax.set(declaration_node, child)
|
|
} else if (child->data.name == "function") {
|
|
// again, also handles templates
|
|
var function_node = second_pass_function(child, node, template_replacements, true)
|
|
node->type_def.methods.add(function_node)
|
|
ast_to_syntax.set(function_node, child)
|
|
}
|
|
})
|
|
}
|
|
fun second_pass_function(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>, do_raw_template: bool): *ast_node {
|
|
var function_name = concat_symbol_tree(get_node("func_identifier", node))
|
|
var template_dec = get_node("template_dec", node)
|
|
if (do_raw_template && template_dec) {
|
|
var template_types = vector<string>()
|
|
var template_type_replacements = map<string, *type>()
|
|
// XXX add traits
|
|
get_nodes("template_param", template_dec).for_each(fun(template_param: *tree<symbol>) {
|
|
template_types.add(concat_symbol_tree(get_node("identifier", template_param)))
|
|
template_type_replacements.set(template_types.last(), type_ptr(vector<string>()))
|
|
})
|
|
template_type_replacements.for_each(fun(key: string, value: *type) println(string("MAP: ") + key + " : " + value->to_string());)
|
|
println("MAP DONE")
|
|
var template = ast_template_ptr(function_name, node, template_types, template_type_replacements, true)
|
|
add_to_scope(function_name, template, scope)
|
|
add_to_scope("~enclosing_scope", scope, template)
|
|
return template
|
|
}
|
|
// 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<type>()
|
|
if (typed_return_node) return_type = transform_type(get_node("type", typed_return_node), scope, 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<symbol>) {
|
|
parameters.add(ast_identifier_ptr(concat_symbol_tree(get_node("identifier", child)), transform_type(get_node("type", child), scope, 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
|
|
add_to_scope(function_name, function_node, scope)
|
|
add_to_scope("~enclosing_scope", scope, 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<symbol>, 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) {
|
|
// make sure not a template? or the method not a template?
|
|
// also same body problem as below
|
|
node->type_def.methods.for_each(fun(method: *ast_node) {
|
|
method->function.body_statement = transform_statement(get_node("statement", ast_to_syntax[method]), method, map<string, *type>())
|
|
})
|
|
}
|
|
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]), node, map<string, *type>())
|
|
}
|
|
}
|
|
})
|
|
}
|
|
// The fourth pass generates the class templates that have not yet been generated in a worklist loop
|
|
fun fourth_pass(parse_tree: *tree<symbol>, translation_unit: *ast_node) {
|
|
println(string("Fourth Pass for ") + translation_unit->translation_unit.name)
|
|
while (!fourth_pass_worklist.empty()) {
|
|
var partially_inst_type_def = fourth_pass_worklist.pop()
|
|
partially_inst_type_def->type_def.methods.for_each(fun(method: *ast_node) {
|
|
// if this is a templated method, we've either instantiatedit if we need it or not if we didn't, so we don't do anything with it here
|
|
if (is_template(method))
|
|
return
|
|
var template = partially_inst_type_def->type_def.scope[string("~enclosing_scope")][0]
|
|
var template_types = template->template.template_types
|
|
var real_types = template->template.instantiated_map.reverse_get(partially_inst_type_def)
|
|
var replacements = map<string, *type>()
|
|
for (var i = 0; i < template_types.size; i++;)
|
|
replacements.set(template_types[i], real_types[i].clone())
|
|
method->function.body_statement = transform_statement(get_node("statement", ast_to_syntax[method]), method, replacements)
|
|
})
|
|
}
|
|
}
|
|
fun transform_type(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *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 template_inst = get_node("template_inst", real_node)
|
|
if (template_inst) {
|
|
var name = concat_symbol_tree(get_node("scoped_identifier", real_node))
|
|
println(string("trying to instantiate a template object: ") + name)
|
|
var real_types = get_nodes("type", template_inst).map(fun(t: *tree<symbol>): *type return transform_type(t, scope, template_replacements);)
|
|
var real_types_deref = real_types.map(fun(t:*type):type return *t;)
|
|
var results = scope_lookup(name, scope)
|
|
for (var i = 0; i < results.size; i++;) {
|
|
if (!is_template(results[i]) || results[i]->template.is_function)
|
|
continue
|
|
println(to_string(i) + " is an object template!")
|
|
var template_types = results[i]->template.template_types
|
|
var template_type_replacements = results[i]->template.template_type_replacements
|
|
if (template_types.size != real_types.size)
|
|
continue
|
|
// check if already instantiated
|
|
var inst_type = null<ast_node>()
|
|
if (results[i]->template.instantiated_map.contains_key(real_types_deref)) {
|
|
println("USING CACHED TEMPLATE OBJECT")
|
|
inst_type = results[i]->template.instantiated_map[real_types_deref]
|
|
} else {
|
|
println("FOR FIND OR INSTATINTATE PREEEE")
|
|
template_type_replacements.for_each(fun(key: string, value: *type) println(string("MAP: ") + key + " : " + value->to_string());)
|
|
println("MAP DONE")
|
|
for (var j = 0; j < template_types.size; j++;) {
|
|
template_type_replacements[template_types[j]] = real_types[j]
|
|
println("Just made")
|
|
println(template_types[j])
|
|
println("equal to")
|
|
println(real_types[j]->to_string())
|
|
}
|
|
println("FOR FIND OR INSTATINTATE")
|
|
template_type_replacements.for_each(fun(key: string, value: *type) println(string("MAP: ") + key + " : " + value->to_string());)
|
|
println("MAP DONE")
|
|
|
|
inst_type = first_pass_type_def(results[i]->template.syntax_node, results[i], true)
|
|
// add to instantiated_map so we only instantiate with a paticular set of types once
|
|
// put in map first for recursive purposes
|
|
results[i]->template.instantiated_map.set(real_types_deref, inst_type)
|
|
results[i]->template.instantiated.add(inst_type)
|
|
second_pass_type_def(results[i]->template.syntax_node, inst_type, results[i], template_type_replacements)
|
|
fourth_pass_worklist.push(inst_type)
|
|
}
|
|
return inst_type->type_def.self_type->clone_with_indirection(indirection)
|
|
}
|
|
error("FREAK OUT AUTOMATON")
|
|
}
|
|
var type_syntax_str = concat_symbol_tree(real_node)
|
|
println(type_syntax_str + " *************************")
|
|
if (template_replacements.contains_key(type_syntax_str)) {
|
|
print("Is in template_replacements, returning: ")
|
|
var to_ret = template_replacements[type_syntax_str]->clone_with_increased_indirection(indirection)
|
|
println(to_ret->to_string())
|
|
return to_ret
|
|
}
|
|
// 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
|
|
var possibilities = scope_lookup(type_syntax_str, scope)
|
|
print("There are "); print(possibilities.size); println(" possibilites for this object type lookup")
|
|
for (var i = 0; i < possibilities.size; i++;) {
|
|
match(*possibilities[i]) {
|
|
ast_node::type_def(backing) return backing.self_type->clone_with_indirection(indirection)
|
|
}
|
|
}
|
|
println("No objects in lookup, returning none")
|
|
return type_ptr(base_type::none(), indirection)
|
|
}
|
|
}
|
|
fun transform(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *ast_node return transform(node, scope, search_type::none(), template_replacements)
|
|
fun transform(node: *tree<symbol>, scope: *ast_node, searching_for: search_type, template_replacements: map<string, *type>): *ast_node {
|
|
var name = node->data.name
|
|
if (name == "identifier" || name == "scoped_identifier") {
|
|
return transform_identifier(node, scope, searching_for)
|
|
} else if (name == "code_block") {
|
|
return transform_code_block(node, scope, template_replacements)
|
|
} 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, template_replacements)
|
|
} else if (name == "declaration_statement") {
|
|
return transform_declaration_statement(node, scope, template_replacements)
|
|
} else if (name == "assignment_statement") {
|
|
return transform_assignment_statement(node, scope, template_replacements)
|
|
} else if (name == "if_statement") {
|
|
return transform_if_statement(node, scope, template_replacements)
|
|
} else if (name == "while_loop") {
|
|
return transform_while_loop(node, scope, template_replacements)
|
|
} else if (name == "for_loop") {
|
|
return transform_for_loop(node, scope, template_replacements)
|
|
} else if (name == "return_statement") {
|
|
return transform_return_statement(node, scope, template_replacements)
|
|
} else if (name == "continue_statement" || name == "break_statement") {
|
|
return transform_branching_statement(node, scope)
|
|
} else if (name == "defer_statement") {
|
|
return transform_defer_statement(node, scope, template_replacements)
|
|
} else if (name == "function_call") {
|
|
return transform_function_call(node, scope, template_replacements)
|
|
} else if (name == "boolean_expression" || name == "and_boolean_expression"
|
|
|| name == "bool_exp" || name == "expression"
|
|
|| name == "shiftand" || name == "term"
|
|
|| name == "factor" || name == "unarad"
|
|
|| name == "access_operation"
|
|
) {
|
|
// for now, assume passthrough and just transform underneath
|
|
return transform_expression(node, scope, searching_for, template_replacements)
|
|
} else if (name == "bool" || name == "string"
|
|
|| name == "character" || name == "number"
|
|
) {
|
|
println(string("transforming value: ") + name)
|
|
return transform_value(node, scope)
|
|
}
|
|
print("FAILED TO TRANSFORM: "); print(name + ": "); println(concat_symbol_tree(node))
|
|
return null<ast_node>()
|
|
}
|
|
fun transform_all(nodes: vector<*tree<symbol>>, scope: *ast_node, template_replacements: map<string, *type>): vector<*ast_node> {
|
|
return nodes.map(fun(node: *tree<symbol>): *ast_node return transform(node, scope, template_replacements);)
|
|
}
|
|
fun transform_identifier(node: *tree<symbol>, scope: *ast_node, searching_for: search_type): *ast_node {
|
|
// first, we check for and generate this
|
|
var name = concat_symbol_tree(node)
|
|
if (name == "this") {
|
|
while (!is_type_def(scope)) scope = get_ast_scope(scope)->get(string("~enclosing_scope"))[0]
|
|
return ast_identifier_ptr("this", scope->type_def.self_type->clone_with_indirection(1))
|
|
}
|
|
match (searching_for) {
|
|
search_type::none() return identifier_lookup(name, scope)
|
|
search_type::function(type_vec) return function_lookup(name, scope, type_vec)
|
|
}
|
|
println("FAILED SEARCH FOR")
|
|
return null<ast_node>()
|
|
}
|
|
fun transform_value(node: *tree<symbol>, scope: *ast_node): *ast_node {
|
|
var value_str = concat_symbol_tree(node)
|
|
var value_type = null<type>()
|
|
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)
|
|
if (value_str[value_str.length()-1] == 'f')
|
|
value_type = type_ptr(base_type::floating()) //value_type = type_ptr(base_type::floating())
|
|
else
|
|
value_type = type_ptr(base_type::double_precision()) //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_code_block(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *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, template_replacements)
|
|
return new_block
|
|
}
|
|
fun transform_if_comp(node: *tree<symbol>, 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, map<string, *type>())
|
|
return new_if_comp
|
|
}
|
|
fun transform_simple_passthrough(node: *tree<symbol>, scope: *ast_node): *ast_node {
|
|
var new_passthrough = ast_simple_passthrough_ptr()
|
|
new_passthrough->simple_passthrough.passthrough_str = concat_symbol_tree(get_node("triple_quoted_string", node)).slice(3,-4)
|
|
// setup passthrough params and string
|
|
var passthrough_params = get_node("passthrough_params", node)
|
|
if (!passthrough_params)
|
|
return new_passthrough
|
|
var in_passthrough_params = get_node("in_passthrough_params", passthrough_params)
|
|
var out_passthrough_params = get_node("out_passthrough_params", passthrough_params)
|
|
if (in_passthrough_params)
|
|
get_nodes("param_assign", in_passthrough_params).for_each(fun(p: *tree<symbol>) {
|
|
var idents = get_nodes("identifier", p)
|
|
if (idents.size == 2)
|
|
new_passthrough->simple_passthrough.in_params.add(make_pair(transform_identifier(idents[0], scope, search_type::none()), concat_symbol_tree(idents[1])))
|
|
else
|
|
new_passthrough->simple_passthrough.in_params.add(make_pair(transform_identifier(idents[0], scope, search_type::none()), concat_symbol_tree(idents[0])))
|
|
})
|
|
if (out_passthrough_params)
|
|
get_nodes("param_assign", out_passthrough_params).for_each(fun(p: *tree<symbol>) {
|
|
var idents = get_nodes("identifier", p)
|
|
if (idents.size == 2)
|
|
new_passthrough->simple_passthrough.out_params.add(make_pair(transform_identifier(idents[0], scope, search_type::none()), concat_symbol_tree(idents[1])))
|
|
else
|
|
new_passthrough->simple_passthrough.out_params.add(make_pair(transform_identifier(idents[0], scope, search_type::none()), concat_symbol_tree(idents[0])))
|
|
})
|
|
return new_passthrough
|
|
}
|
|
fun transform_statement(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *ast_node return ast_statement_ptr(transform(node->children[0], scope, template_replacements));
|
|
fun transform_declaration_statement(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *ast_node {
|
|
// this might have an init position method call
|
|
var identifiers = get_nodes("identifier", node)
|
|
var name = concat_symbol_tree(identifiers[0])
|
|
// may have type, or an expression, or both
|
|
var type_syntax_node = get_node("type", node)
|
|
var expression_syntax_node = get_node("boolean_expression", node)
|
|
var ident_type = null<type>()
|
|
var expression = null<ast_node>()
|
|
if (type_syntax_node) ident_type = transform_type(type_syntax_node, scope, template_replacements)
|
|
if (expression_syntax_node) {
|
|
expression = transform(expression_syntax_node, scope, template_replacements)
|
|
if (!type_syntax_node)
|
|
ident_type = get_ast_type(expression)
|
|
}
|
|
if (!ident_type) error("declaration statement with no type or expression from which to inference type")
|
|
var identifier = ast_identifier_ptr(name, ident_type)
|
|
var declaration = ast_declaration_statement_ptr(identifier, expression)
|
|
// ok, deal with the possible init position method call
|
|
if (identifiers.size == 2) {
|
|
var method = transform(identifiers[1], ident_type->type_def, template_replacements)
|
|
var parameters = get_nodes("parameter", node).map(fun(child: *tree<symbol>): *ast_node return transform(get_node("boolean_expression", child), scope, template_replacements);)
|
|
declaration->declaration_statement.init_method_call = make_method_call(identifier, method, parameters)
|
|
}
|
|
add_to_scope(name, identifier, scope)
|
|
return declaration
|
|
}
|
|
fun transform_assignment_statement(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *ast_node {
|
|
var assign_to = transform(get_node("factor", node), scope, template_replacements)
|
|
var to_assign = transform(get_node("boolean_expression", node), scope, template_replacements)
|
|
if (get_node("\"\\+=\"", node)) to_assign = make_operator_call("+", vector(assign_to, to_assign))
|
|
else if (get_node("\"-=\"", node)) to_assign = make_operator_call("-", vector(assign_to, to_assign))
|
|
else if (get_node("\"\\*=\"", node)) to_assign = make_operator_call("*", vector(assign_to, to_assign))
|
|
else if (get_node("\"/=\"", node)) to_assign = make_operator_call("/", vector(assign_to, to_assign))
|
|
var assignment = ast_assignment_statement_ptr(assign_to, to_assign)
|
|
return assignment
|
|
}
|
|
fun transform_if_statement(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *ast_node {
|
|
var if_statement = ast_if_statement_ptr(transform_expression(get_node("boolean_expression", node), scope, template_replacements))
|
|
// one variable declarations might be in a code_block-less if statement
|
|
add_to_scope("~enclosing_scope", scope, if_statement)
|
|
var statements = transform_all(get_nodes("statement", node), if_statement, template_replacements)
|
|
if_statement->if_statement.then_part = statements[0]
|
|
// we have an else
|
|
if (statements.size == 2)
|
|
if_statement->if_statement.else_part = statements[1]
|
|
return if_statement
|
|
}
|
|
fun transform_while_loop(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *ast_node {
|
|
var while_loop = ast_while_loop_ptr(transform_expression(get_node("boolean_expression", node), scope, template_replacements))
|
|
add_to_scope("~enclosing_scope", scope, while_loop)
|
|
while_loop->while_loop.statement = transform(get_node("statement", node), while_loop, template_replacements)
|
|
return while_loop
|
|
}
|
|
fun transform_for_loop(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *ast_node {
|
|
var for_loop = ast_for_loop_ptr()
|
|
add_to_scope("~enclosing_scope", scope, for_loop)
|
|
var statements = get_nodes("statement", node)
|
|
for_loop->for_loop.init = transform(statements[0], for_loop, template_replacements)
|
|
for_loop->for_loop.condition = transform(get_node("boolean_expression", node), for_loop, template_replacements)
|
|
for_loop->for_loop.update = transform(statements[1], for_loop, template_replacements)
|
|
for_loop->for_loop.body = transform(statements[2], for_loop, template_replacements)
|
|
return for_loop
|
|
}
|
|
fun transform_return_statement(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *ast_node {
|
|
var return_value = get_node("boolean_expression", node)
|
|
if (return_value)
|
|
return ast_return_statement_ptr(transform(return_value, scope, template_replacements))
|
|
return ast_return_statement_ptr(null<ast_node>())
|
|
}
|
|
fun transform_branching_statement(node: *tree<symbol>, scope: *ast_node): *ast_node {
|
|
if (node->data.name == "break_statement")
|
|
return ast_branching_statement_ptr(branching_type::break_stmt())
|
|
return ast_branching_statement_ptr(branching_type::continue_stmt())
|
|
}
|
|
fun transform_defer_statement(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *ast_node {
|
|
return ast_defer_statement_ptr(transform(node->children[0], scope, template_replacements))
|
|
}
|
|
fun transform_function_call(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *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<symbol>): *ast_node return transform(get_node("boolean_expression", child), scope, template_replacements);)
|
|
var parameter_types = parameters.map(fun(param: *ast_node): *type return get_ast_type(param);)
|
|
var f = ast_function_call_ptr(transform(get_node("unarad", node), scope, search_type::function(parameter_types), template_replacements), 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 transform_expression(node: *tree<symbol>, scope: *ast_node, template_replacements: map<string, *type>): *ast_node return transform_expression(node, scope, search_type::none(), template_replacements)
|
|
fun transform_expression(node: *tree<symbol>, scope: *ast_node, searching_for: search_type, template_replacements: map<string, *type>): *ast_node {
|
|
var func_name = string()
|
|
var parameters = vector<*ast_node>()
|
|
if (node->children.size == 1) {
|
|
var possible_func = transform(node->children[0], scope, searching_for, template_replacements)
|
|
if (!possible_func) match (searching_for) {
|
|
search_type::function(type_vec) possible_func = find_or_instantiate_template_function(node->children[0], null<tree<symbol>>(), scope, type_vec, template_replacements, map<string, *type>());
|
|
}
|
|
if (!possible_func)
|
|
println(concat_symbol_tree(node) + ": HAS NO POSSIBLE FUNCTION OR FUNCTION TEMPLATE SOLUTIONS")
|
|
return possible_func
|
|
} else if (node->children.size == 2) {
|
|
var template_inst = get_node("template_inst", node)
|
|
if (template_inst) {
|
|
var identifier = get_node("scoped_identifier", node)
|
|
match (searching_for) {
|
|
// I guess this should never happen?
|
|
search_type::none() {
|
|
println("TE<PLATE LOOKUO MAKES NO SENSE")
|
|
return null<ast_node>()
|
|
}
|
|
search_type::function(type_vec) return find_or_instantiate_template_function(identifier, template_inst, scope, type_vec, template_replacements, map<string, *type>())
|
|
}
|
|
println("NEVER EVER HAPPEN")
|
|
}
|
|
var check_if_post = concat_symbol_tree(node->children[1])
|
|
if (check_if_post == "--" || check_if_post == "++") {
|
|
// give the post-operators a special suffix so the c_generator knows to emit them post
|
|
func_name = concat_symbol_tree(node->children[1]) + "p"
|
|
parameters = vector(transform(node->children[0], scope, template_replacements))
|
|
} else {
|
|
func_name = concat_symbol_tree(node->children[0])
|
|
parameters = vector(transform(node->children[1], scope, template_replacements))
|
|
}
|
|
} else {
|
|
func_name = concat_symbol_tree(node->children[1])
|
|
var first_param = transform(node->children[0], scope, template_replacements)
|
|
var second_param = null<ast_node>()
|
|
if (func_name == "." || func_name == "->") {
|
|
second_param = transform(node->children[2], get_ast_type(first_param)->type_def, searching_for, template_replacements)
|
|
// template member functions
|
|
// XXX add in template inst if it exists
|
|
if (!second_param) match (searching_for) {
|
|
search_type::function(type_vec) {
|
|
var template_inst = get_node("template_inst", node)
|
|
var inherited_replacements = map<string, *type>()
|
|
var parent = get_ast_scope(get_ast_type(first_param)->type_def)->get(string("~enclosing_scope"))[0]
|
|
if (is_template(parent)) {
|
|
for (var i = 0; i < parent->template.template_types.size; i++;)
|
|
inherited_replacements[parent->template.template_types[i]] = parent->template.instantiated_map.reverse_get(get_ast_type(first_param)->type_def)[i].clone()
|
|
}
|
|
if (template_inst)
|
|
second_param = find_or_instantiate_template_function(node->children[2], template_inst, get_ast_type(first_param)->type_def, type_vec, template_replacements, inherited_replacements);
|
|
else
|
|
second_param = find_or_instantiate_template_function(node->children[2], null<tree<symbol>>(), get_ast_type(first_param)->type_def, type_vec, template_replacements, inherited_replacements);
|
|
}
|
|
}
|
|
} else {
|
|
second_param = transform(node->children[2], scope, template_replacements)
|
|
}
|
|
parameters = vector(first_param, second_param)
|
|
}
|
|
var parameter_types = parameters.map(fun(param: *ast_node): *type return get_ast_type(param);)
|
|
return ast_function_call_ptr(get_builtin_function(func_name, parameter_types), parameters)
|
|
}
|
|
fun find_or_instantiate_template_function(identifier: *tree<symbol>, template_inst: *tree<symbol>, scope: *ast_node, param_types: vector<*type>, template_replacements: map<string, *type>, replacements_base: map<string, *type>): *ast_node {
|
|
// replacments base is for templated methods starting off with the replacements of their parent (possibly templated) object
|
|
var name = concat_symbol_tree(identifier)
|
|
println(string("trying to instantiate a template function: ") + name)
|
|
var results = scope_lookup(name, scope)
|
|
var real_types = vector<*type>()
|
|
var real_types_deref = vector<type>()
|
|
var had_real_types = false
|
|
if (template_inst) {
|
|
real_types = get_nodes("type", template_inst).map(fun(t: *tree<symbol>): *type return transform_type(t, scope, template_replacements);)
|
|
real_types_deref = real_types.map(fun(t:*type):type return *t;)
|
|
had_real_types = true
|
|
}
|
|
for (var i = 0; i < results.size; i++;) {
|
|
if (is_template(results[i]) && results[i]->template.is_function) {
|
|
println(string() + i + " is a template!")
|
|
var template_types = results[i]->template.template_types
|
|
var template_type_replacements = results[i]->template.template_type_replacements
|
|
if (!had_real_types) {
|
|
// reset the vars, cuz we might be iterating through multiple of them
|
|
real_types = vector<*type>()
|
|
real_types_deref = vector<type>()
|
|
// Template Function Instance Inference time
|
|
var typed_params = get_nodes("typed_parameter", results[i]->template.syntax_node).map(fun(t: *tree<symbol>): *tree<symbol> return get_node("type",t);)
|
|
if (param_types.size != typed_params.size)
|
|
continue
|
|
for (var j = 0; j < typed_params.size; j++;)
|
|
unify_type(typed_params[j], param_types[j], &template_type_replacements, template_replacements)
|
|
for (var j = 0; j < typed_params.size; j++;) {
|
|
var t = template_type_replacements[template_types[j]];
|
|
real_types.add(t)
|
|
real_types_deref.add(*t)
|
|
}
|
|
} else if (template_types.size != real_types.size)
|
|
continue
|
|
// check if already instantiated
|
|
var inst_func = null<ast_node>()
|
|
if (results[i]->template.instantiated_map.contains_key(real_types_deref)) {
|
|
println("USING CACHED TEMPLATE FUNCITON")
|
|
inst_func = results[i]->template.instantiated_map[real_types_deref]
|
|
} else {
|
|
println("FOR FIND OR INSTATINTATE PREEEE")
|
|
template_type_replacements.for_each(fun(key: string, value: *type) println(string("MAP: ") + key + " : " + value->to_string());)
|
|
println("MAP DONE")
|
|
for (var j = 0; j < template_types.size; j++;) {
|
|
template_type_replacements[template_types[j]] = real_types[j]
|
|
println("Just made")
|
|
println(template_types[j])
|
|
println("equal to")
|
|
println(real_types[j]->to_string())
|
|
}
|
|
replacements_base.for_each(fun(key: string, value: *type) {
|
|
template_type_replacements[key] = value
|
|
println("Just Inherited")
|
|
println(key)
|
|
println("equal to")
|
|
println(value->to_string())
|
|
})
|
|
println("FOR FIND OR INSTATINTATE")
|
|
template_type_replacements.for_each(fun(key: string, value: *type) println(string("MAP: ") + key + " : " + value->to_string());)
|
|
println("MAP DONE")
|
|
|
|
inst_func = second_pass_function(results[i]->template.syntax_node, results[i], template_type_replacements, false)
|
|
// add to instantiated_map so we only instantiate with a paticular set of types once
|
|
// put in map first for recursive purposes
|
|
results[i]->template.instantiated_map.set(real_types_deref, inst_func)
|
|
results[i]->template.instantiated.add(inst_func)
|
|
// and fully instantiate it
|
|
inst_func->function.body_statement = transform_statement(get_node("statement", results[i]->template.syntax_node), inst_func, template_type_replacements)
|
|
}
|
|
|
|
if (function_satisfies_params(inst_func, param_types))
|
|
return inst_func
|
|
else
|
|
println(string("this paticular ") + name + " did not satisfy params")
|
|
}
|
|
}
|
|
println("FREAK OUT MACHINE")
|
|
return null<ast_node>()
|
|
}
|
|
}
|
|
fun has_method(object: *ast_node, name: *char, parameter_types: vector<*type>): bool return has_method(object, string(name), parameter_types);
|
|
fun has_method(object: *ast_node, name: string, parameter_types: vector<*type>): bool {
|
|
println("HAS METHOD:")
|
|
var to_ret = function_lookup(name, object, parameter_types) || false
|
|
println("HAS METHOD result:")
|
|
println(to_ret)
|
|
return to_ret
|
|
}
|
|
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:")
|
|
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)
|
|
return make_method_call(object_ident, method, parameters)
|
|
}
|
|
fun make_method_call(object_ident: *ast_node, method: *ast_node, parameters: vector<*ast_node>): *ast_node {
|
|
println("MAKE METHOD CALL IN:")
|
|
var method_access = ast_function_call_ptr(get_builtin_function(string("."), vector(get_ast_type(object_ident), get_ast_type(method))), vector(object_ident, method))
|
|
return ast_function_call_ptr(method_access, parameters)
|
|
}
|
|
fun make_operator_call(func: *char, params: vector<*ast_node>): *ast_node return make_operator_call(string(func), params);
|
|
fun make_operator_call(func: string, params: vector<*ast_node>): *ast_node {
|
|
return ast_function_call_ptr(get_builtin_function(func, params.map(fun(p:*ast_node): *type return get_ast_type(p);)), params)
|
|
}
|
|
fun get_builtin_function(name: string, param_types: vector<*type>): *ast_node {
|
|
if (name == "==" || name == "!=" || name == ">" || name == "<" || name == "<=" || name == ">" || name == ">=" || name == "&&" || name == "||" || name == "!")
|
|
return ast_function_ptr(name, type_ptr(param_types, type_ptr(base_type::boolean())), vector<*ast_node>())
|
|
if (name == "." || name == "->" || name == "[")
|
|
return ast_function_ptr(name, type_ptr(param_types, param_types[1]), vector<*ast_node>())
|
|
if (name == "&")
|
|
return ast_function_ptr(name, type_ptr(param_types, param_types[0]->clone_with_increased_indirection()), vector<*ast_node>())
|
|
if (name == "\*")
|
|
return ast_function_ptr(name, type_ptr(param_types, param_types[0]->clone_with_decreased_indirection()), vector<*ast_node>())
|
|
if (param_types.size > 1 && param_types[1]->rank() > param_types[0]->rank())
|
|
return ast_function_ptr(name, type_ptr(param_types, param_types[1]), vector<*ast_node>())
|
|
return ast_function_ptr(name, type_ptr(param_types, param_types[0]), vector<*ast_node>())
|
|
}
|
|
fun unify_type(template_type: *tree<symbol>, param_type: *type, new_map: *map<string, *type>, template_replacements: map<string, *type>) {
|
|
println(string("Unifying type: ") + concat_symbol_tree(template_type))
|
|
// first get rid of the reference if we have it - we don't care for unification
|
|
if (get_node("pre_reffed", template_type))
|
|
template_type = get_node("pre_reffed", template_type)
|
|
// There are a couple options for the template parameter type here
|
|
// 1) template type - perfect, stick it in the map, that's what we're here for
|
|
// 2) basic type - stick it in the map, it won't get copied out so no worries
|
|
// 3) pointer type, go down a level
|
|
// 4) function type - fine, unify on all parameters and return types
|
|
// 5) instantiated template - fun stuff, have to figure out what it was origionally
|
|
// instantiated with, but we don't have to worry about it yet as I haven't gotten
|
|
// to object templates at all ;)
|
|
if (template_type->children.size == 1)
|
|
new_map->set(concat_symbol_tree(template_type), param_type)
|
|
else if (get_node("\"\\*\"", template_type))
|
|
unify_type(template_type->children[1], param_type->clone_with_decreased_indirection(), new_map, template_replacements)
|
|
else {
|
|
println(template_type->children[0]->data.name)
|
|
println(template_type->children[0]->data.data)
|
|
error("TYPE INFERENCE NOT GOOD ENOUGH")
|
|
}
|
|
}
|
|
fun function_satisfies_params(node: *ast_node, param_types: vector<*type>): bool {
|
|
var func_param_types = get_ast_type(node)->parameter_types
|
|
var param_string = string()
|
|
param_types.for_each(fun(t: *type) param_string += t->to_string() + ", ";)
|
|
if (func_param_types.size != param_types.size) {
|
|
println(string("type sizes don't match") + param_types.size + " with needed " + param_string)
|
|
return false
|
|
}
|
|
for (var j = 0; j < param_types.size; j++;) {
|
|
if (*func_param_types[j] != *param_types[j]) {
|
|
println(string("types don't match") + func_param_types[j]->to_string() + " with needed " + param_types[j]->to_string())
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
fun function_lookup(name: string, scope: *ast_node, param_types: vector<*type>): *ast_node {
|
|
println(string("doing function lookup for: ") + name)
|
|
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]) && function_satisfies_params(results[i], param_types)) {
|
|
return results[i]
|
|
}
|
|
}
|
|
println(string("function lookup failed for ") + name)
|
|
return null<ast_node>()
|
|
}
|
|
fun identifier_lookup(name: string, scope: *ast_node): *ast_node {
|
|
println(string("doing identifier lookup for: ") + name)
|
|
var results = scope_lookup(name, scope)
|
|
if (!results.size) {
|
|
println(string("identifier lookup failed for ") + name)
|
|
return null<ast_node>()
|
|
}
|
|
return results[0]
|
|
}
|
|
fun scope_lookup(name: string, scope: *ast_node): vector<*ast_node> {
|
|
println("*****Doing a name lookup for*****")
|
|
println(name)
|
|
var results = vector(scope)
|
|
name.split("::").for_each(fun(i: string) {
|
|
println(string("based on split, looking up: ") + i)
|
|
var next_results = vector<*ast_node>()
|
|
results.for_each(fun(s: *ast_node) {
|
|
print("looking in scope: ")
|
|
println(s)
|
|
next_results += scope_lookup_helper(i, s, set<*ast_node>())
|
|
})
|
|
results = next_results
|
|
})
|
|
return results
|
|
}
|
|
fun scope_lookup_helper(name: string, scope: *ast_node, visited: set<*ast_node>): vector<*ast_node> {
|
|
// need to do properly scopded lookups
|
|
print("scope is: ")
|
|
get_ast_scope(scope)->for_each(fun(key: string, value: vector<*ast_node>) print(key + " ");)
|
|
println()
|
|
var results = vector<*ast_node>()
|
|
// prevent re-checking the same one...
|
|
if (visited.contains(scope))
|
|
return results
|
|
visited.add(scope)
|
|
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_helper(name, get_ast_scope(scope)->get(string("~enclosing_scope"))[0], visited)
|
|
if (is_translation_unit(scope)) {
|
|
scope->translation_unit.children.for_each(fun(child: *ast_node) {
|
|
if (is_import(child)) {
|
|
if (child->import.imported.contains(name)) {
|
|
println(name + " is indeed imported")
|
|
results += scope_lookup_helper(name, child->import.translation_unit, visited)
|
|
} else if (child->import.starred) {
|
|
println("import has an import *, checking along it")
|
|
results += scope_lookup_helper(name, child->import.translation_unit, visited)
|
|
} else {
|
|
println(name + " is not imported (this time)")
|
|
print("import imports")
|
|
child->import.imported.for_each(fun(it: string) print(it + " ");)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
return results
|
|
}
|
|
|
|
fun concat_symbol_tree(node: *tree<symbol>): string {
|
|
var str.construct(): string
|
|
if (node->data.data != "no_value")
|
|
str += node->data.data
|
|
node->children.for_each(fun(child: *tree<symbol>) str += concat_symbol_tree(child);)
|
|
return str
|
|
}
|
|
|
|
fun get_node(lookup: *char, parent: *tree<symbol>): *tree<symbol> {
|
|
return get_node(string(lookup), parent)
|
|
}
|
|
fun get_node(lookup: string, parent: *tree<symbol>): *tree<symbol> {
|
|
var results = get_nodes(lookup, parent)
|
|
if (results.size > 1)
|
|
println("too many results!")
|
|
if (results.size)
|
|
return results[0]
|
|
return null<tree<symbol>>()
|
|
}
|
|
fun get_nodes(lookup: *char, parent: *tree<symbol>): vector<*tree<symbol>> {
|
|
return get_nodes(string(lookup), parent)
|
|
}
|
|
fun get_nodes(lookup: string, parent: *tree<symbol>): vector<*tree<symbol>> {
|
|
return parent->children.filter(fun(node: *tree<symbol>):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))
|
|
}
|
|
fun error(message: *char) error(string(message));
|
|
fun error(message: string) {
|
|
println("****ERROR****")
|
|
println(message)
|
|
exit(-1)
|
|
/*while (true){}*/
|
|
}
|
|
|