Files
kraken/stdlib/ast_transformation.krak

526 lines
28 KiB
Plaintext
Raw Normal View History

import symbol:*
import tree:*
import vector:*
import stack:*
import map:*
import util:*
import string:*
import mem:*
import io:*
2015-12-05 07:13:32 -05:00
import importer:*
import ast_nodes:*
import type:*
2015-12-05 07:13:32 -05:00
adt search_type {
none,
function: vector<*type>
}
obj ast_transformation (Object) {
var ast_to_syntax: map<*ast_node, *tree<symbol>>
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
2015-12-05 07:13:32 -05:00
fun first_pass(file_name: string, parse_tree: *tree<symbol>, importer: *importer): *ast_node {
2015-12-06 18:44:04 -05:00
var translation_unit = ast_translation_unit_ptr(file_name)
2015-12-05 07:13:32 -05:00
importer->register(file_name, parse_tree, translation_unit)
2015-12-06 15:15:33 -05:00
parse_tree->children.for_each(fun(child: *tree<symbol>) {
if (child->data.name == "type_def") {
var name = concat_symbol_tree(get_node("identifier", child))
2015-12-06 18:44:04 -05:00
var type_def_node = ast_type_def_ptr(name)
type_def_node->type_def.self_type = type_ptr(type_def_node)
2015-12-06 15:15:33 -05:00
translation_unit->translation_unit.children.add(type_def_node)
ast_to_syntax.set(type_def_node, child)
2015-12-07 13:43:22 -05:00
add_to_scope("~enclosing_scope", translation_unit, type_def_node)
add_to_scope(name, type_def_node, translation_unit)
2015-12-06 18:44:04 -05:00
// 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)
2015-12-07 13:43:22 -05:00
add_to_scope("~enclosing_scope", translation_unit, adt_def_node)
add_to_scope(name, adt_def_node, translation_unit)
2015-12-06 18:44:04 -05:00
} else if (child->data.name == "if_comp") {
var if_comp_node = transform_if_comp(child, translation_unit)
2015-12-06 18:44:04 -05:00
translation_unit->translation_unit.children.add(if_comp_node)
ast_to_syntax.set(if_comp_node, child)
2015-12-06 18:44:04 -05:00
}
})
// now do all imports (done second so that if it imports this translation_unit,
2015-12-06 18:44:04 -05:00
// this one already has all its types defined
parse_tree->children.for_each(fun(child: *tree<symbol>) {
if (child->data.name == "import") {
2015-12-28 03:34:40 -05:00
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)
2015-12-06 18:44:04 -05:00
translation_unit->translation_unit.children.add(import_node)
ast_to_syntax.set(import_node, child)
2015-12-07 13:43:22 -05:00
add_to_scope("~enclosing_scope", translation_unit, import_node)
2015-12-28 03:34:40 -05:00
import_node->import.imported = from_vector(import_identifier_children.slice(1,-1).map(fun(ident: *tree<symbol>):string return concat_symbol_tree(ident);))
2015-12-06 15:15:33 -05:00
}
})
2015-12-05 07:13:32 -05:00
return translation_unit
}
// 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") {
var function_node = second_pass_function(child, translation_unit, map<string, *type>())
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?)...
2016-01-15 19:10:52 -05:00
translation_unit->translation_unit.children.add(transform_declaration_statement(child, translation_unit))
}
})
// work on the ones already started
translation_unit->translation_unit.children.for_each(fun(node: *ast_node) {
match(*node) {
ast_node::type_def(backing) {
var type_def_syntax = ast_to_syntax[node]
type_def_syntax->children.for_each(fun(child: *tree<symbol>) {
if (child->data.name == "declaration_statement") {
var declaration_node = transform_declaration_statement(child, node)
node->type_def.variables.add(declaration_node)
ast_to_syntax.set(declaration_node, child)
} else if (child->data.name == "function") {
var function_node = second_pass_function(child, node, map<string, *type>())
node->type_def.methods.add(function_node)
ast_to_syntax.set(function_node, child)
}
})
}
ast_node::adt_def(backing) do_nothing() // actually go through and do methods inside
}
})
}
fun second_pass_function(node: *tree<symbol>, translation_unit: *ast_node, template_replacements: map<string, *type>): *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<type>()
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<symbol>) {
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<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)
})
}
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!
2016-01-24 01:02:56 -05:00
node->function.body_statement = transform_statement(get_node("statement", ast_to_syntax[node]), node)
}
}
})
}
// The fourth pass generates the class templates that have not yet been generated in a "chaotic iteration" loop
fun fourth_pass(parse_tree: *tree<symbol>, translation_unit: *ast_node) {
println(string("Fourth Pass for ") + translation_unit->translation_unit.name)
}
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 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
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]) {
2016-01-24 01:02:56 -05:00
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)
}
}
2015-12-28 03:34:40 -05:00
/*NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree<ASTData>* scope, std::vector<Type> types, bool limitToFunction, std::map<std::string, Type*> templateTypeReplacements) {*/
fun transform(node: *tree<symbol>, scope: *ast_node): *ast_node return transform(node, scope, search_type::none())
fun transform(node: *tree<symbol>, scope: *ast_node, searching_for: search_type): *ast_node {
2015-12-28 03:34:40 -05:00
var name = node->data.name
if (name == "identifier" || name == "scoped_identifier") {
return transform_identifier(node, scope, searching_for)
2015-12-28 03:34:40 -05:00
} 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)
2016-01-15 19:10:52 -05:00
} else if (name == "declaration_statement") {
return transform_declaration_statement(node, scope)
2016-01-16 22:14:59 -05:00
} else if (name == "assignment_statement") {
return transform_assignment_statement(node, scope)
2016-01-19 02:06:30 -05:00
} else if (name == "if_statement") {
return transform_if_statement(node, scope)
} else if (name == "while_loop") {
return transform_while_loop(node, scope)
2016-01-19 11:47:09 -05:00
} else if (name == "for_loop") {
return transform_for_loop(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"
2016-01-21 19:16:29 -05:00
|| name == "access_operation"
) {
// for now, assume passthrough and just transform underneath
return transform_expression(node, scope, searching_for)
} else if (name == "bool" || name == "string"
|| name == "character" || name == "number"
) {
println(string("transforming value: ") + name)
return transform_value(node, scope)
2015-12-28 03:34:40 -05:00
}
2016-01-21 19:16:29 -05:00
print("FAILED TO TRANSFORM: "); print(name + ": "); println(concat_symbol_tree(node))
2015-12-28 03:34:40 -05:00
return null<ast_node>()
}
fun transform_all(nodes: vector<*tree<symbol>>, scope: *ast_node): vector<*ast_node> {
return nodes.map(fun(node: *tree<symbol>): *ast_node return transform(node, scope);)
}
fun transform_identifier(node: *tree<symbol>, scope: *ast_node, searching_for: search_type): *ast_node {
2016-01-24 01:02:56 -05:00
// first, we check for and generate this
var name = concat_symbol_tree(node)
2016-01-24 01:02:56 -05:00
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))
}
/*return ast_identifier_ptr(name, type_ptr(base_type::void_return()))*/
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>()
}
2016-01-09 22:37:43 -05:00
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)
2016-01-09 22:37:43 -05:00
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_code_block(node: *tree<symbol>, 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<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)
return new_if_comp
}
fun transform_simple_passthrough(node: *tree<symbol>, 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<symbol>, scope: *ast_node): *ast_node {
var new_statement = ast_statement_ptr()
new_statement->statement.child = transform(node->children[0], scope)
return new_statement
}
2016-01-15 19:10:52 -05:00
fun transform_declaration_statement(node: *tree<symbol>, scope: *ast_node): *ast_node {
2016-01-16 22:14:59 -05:00
var name = concat_symbol_tree(get_node("identifier", node))
// 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, map<string, *type>())
if (expression_syntax_node) {
expression = transform(expression_syntax_node, scope)
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)
2016-01-16 22:14:59 -05:00
add_to_scope(name, identifier, scope)
2016-01-15 19:10:52 -05:00
return declaration
}
2016-01-16 22:14:59 -05:00
fun transform_assignment_statement(node: *tree<symbol>, scope: *ast_node): *ast_node {
var assignment = ast_assignment_statement_ptr(transform(get_node("factor", node), scope), transform(get_node("boolean_expression", node), scope))
return assignment
}
2016-01-19 02:06:30 -05:00
fun transform_if_statement(node: *tree<symbol>, scope: *ast_node): *ast_node {
var if_statement = ast_if_statement_ptr(transform_expression(get_node("boolean_expression", node), scope))
// 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)
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): *ast_node {
var while_loop = ast_while_loop_ptr(transform_expression(get_node("boolean_expression", node), scope))
add_to_scope("~enclosing_scope", scope, while_loop)
while_loop->while_loop.statement = transform(get_node("statement", node), while_loop)
return while_loop
}
2016-01-19 11:47:09 -05:00
fun transform_for_loop(node: *tree<symbol>, scope: *ast_node): *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)
for_loop->for_loop.condition = transform(get_node("boolean_expression", node), for_loop)
for_loop->for_loop.update = transform(statements[1], for_loop)
for_loop->for_loop.body = transform(statements[2], for_loop)
return for_loop
}
fun transform_return_statement(node: *tree<symbol>, scope: *ast_node): *ast_node {
return ast_return_statement_ptr(transform(node->children[0], scope))
}
fun transform_function_call(node: *tree<symbol>, 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<symbol>): *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)*/
var f = ast_function_call_ptr(transform(get_node("unarad", node), scope, search_type::function(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 transform_expression(node: *tree<symbol>, scope: *ast_node): *ast_node return transform_expression(node, scope, search_type::none())
fun transform_expression(node: *tree<symbol>, scope: *ast_node, searching_for: search_type): *ast_node {
// figure out what the expression is, handle overloads, or you know
// ignore everything and do a passthrough
var func_name = string()
var parameters = vector<*ast_node>()
if (node->children.size == 1)
return transform(node->children[0], scope, searching_for)
else if (node->children.size == 2) {
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))
} else {
func_name = concat_symbol_tree(node->children[0])
parameters = vector(transform(node->children[1], scope))
}
} else {
func_name = concat_symbol_tree(node->children[1])
2016-01-21 19:16:29 -05:00
var first_param = transform(node->children[0], scope)
var second_param = null<ast_node>()
if (func_name == "." || func_name == "->") {
println("Gonna do the internal scope thing")
second_param = transform(node->children[2], get_ast_type(first_param)->type_def, searching_for)
2016-01-21 19:16:29 -05:00
} else {
println("Gonna do regular scope thing")
second_param = transform(node->children[2], scope)
}
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 get_builtin_function(name: string, param_types: vector<*type>): *ast_node {
2016-01-21 19:16:29 -05:00
if (name == "." || name == "->")
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 function_lookup(name: string, scope: *ast_node, param_types: vector<*type>): *ast_node {
println(string("doing function lookup for: ") + name)
var param_string = string()
param_types.for_each(fun(t: *type) param_string += t->to_string() + ", ";)
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])) {
var func_param_types = get_ast_type(results[i])->parameter_types
if (func_param_types.size != param_types.size) {
println(string("type sizes don't match") + get_ast_type(results[i])->to_string() + " with needed " + param_string)
continue
}
var param_types_match = true
for (var j = 0; j < param_types.size; j++;) {
if (*func_param_types[j] != *param_types[j]) {
param_types_match = false
break
}
}
if (param_types_match)
return results[i]
}
println(string("either isn't function or types don't match ") + get_ast_type(results[i])->to_string() + " with needed " + param_string)
}
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> {
2016-01-21 19:16:29 -05:00
println("*****Doing a name lookup for*****")
println(name)
return scope_lookup_helper(name, scope)
}
fun scope_lookup_helper(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")))
2016-01-21 19:16:29 -05:00
results += scope_lookup_helper(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")
2016-01-21 19:16:29 -05:00
results += scope_lookup_helper(name, child->import.translation_unit)
} else println(name + " is not imported (this time)")
})
}
return results
}
}
2015-12-06 15:15:33 -05:00
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>>()
}
2015-12-28 03:34:40 -05:00
fun get_nodes(lookup: *char, parent: *tree<symbol>): vector<*tree<symbol>> {
return get_nodes(string(lookup), parent)
}
2015-12-06 15:15:33 -05:00
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;)
}
2015-12-07 13:43:22 -05:00
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)
while (true){}
}