import io:* import mem:* import map:* import stack:* import string:* import util:* import tree:* import symbol:* import ast_nodes:* import type:* import ast_transformation:* // for is_dot_style_method_call import c_generator:* // there is never an object literal/primitive // they remain wrapped in a variable value adt value { boolean: bool, character: char, ucharacter: uchar, short_int: short, ushort_int: ushort, integer: int, uinteger: uint, long_int: long, ulong_int: ulong, floating: float, double_precision: double, void_nothing, pointer: pair<*void,*type>, object_like: pair<*void,*type>, variable: pair<*void,*type> } adt control_flow { nor, con, bre, ret } // note that there is not object_like, variable, or pointer raw_to_value fun raw_to_value(data:bool): value return value::boolean(data) fun raw_to_value(data:char): value return value::character(data) fun raw_to_value(data:uchar): value return value::ucharacter(data) fun raw_to_value(data:short): value return value::short_int(data) fun raw_to_value(data:ushort): value return value::ushort_int(data) fun raw_to_value(data:int): value return value::integer(data) fun raw_to_value(data:uint): value return value::uinteger(data) fun raw_to_value(data:long): value return value::long_int(data) fun raw_to_value(data:ulong): value return value::ulong_int(data) fun raw_to_value(data:float): value return value::floating(data) fun raw_to_value(data:double): value return value::double_precision(data) fun wrap_value(val: *ast_node): value { var value_str = val->value.string_value if (value_str[0] == '"') { // " // Comment hack for emacs now var to_ret = string() value_str = value_str.slice(1,-2) for (var i = 0; i < value_str.length()-1; i++;) { if (value_str[i] == '\\' && value_str[i+1] == 'n') { to_ret += '\n' i++ } else if (value_str[i] == '\\' && value_str[i+1] == 't') { to_ret += '\t' i++ } else if (i == value_str.length()-2) { to_ret += value_str[i] to_ret += value_str[i+1] } else { to_ret += value_str[i] } } // if there was only one character if (value_str.length() == 1) to_ret = value_str return value::pointer(make_pair((to_ret.toCharArray()) cast *void, get_ast_type(val))) } else if (value_str[0] == '\'') //'// lol, comment hack for vim syntax highlighting (my fault, of course) return value::character(value_str[1]) else if (value_str == "true") return value::boolean(true) else if (value_str == "false") return value::boolean(false) 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') return value::floating((string_to_double(value_str.slice(0,-2))) cast float) else return value::double_precision(string_to_double(value_str)) else return value::integer(string_to_int(value_str)) } error("Could not wrap value") return value::void_nothing() } fun is_boolean(it: value): bool { match(it) { value::boolean(var) return true; } return false; } fun is_character(it: value): bool { match(it) { value::character(var) return true; } return false; } fun is_ucharacter(it: value): bool { match(it) { value::ucharacter(var) return true; } return false; } fun is_short_int(it: value): bool { match(it) { value::short_int(var) return true; } return false; } fun is_ushort_int(it: value): bool { match(it) { value::ushort_int(var) return true; } return false; } fun is_integer(it: value): bool { match(it) { value::integer(var) return true; } return false; } fun is_uinteger(it: value): bool { match(it) { value::uinteger(var) return true; } return false; } fun is_long_int(it: value): bool { match(it) { value::long_int(var) return true; } return false; } fun is_ulong_int(it: value): bool { match(it) { value::ulong_int(var) return true; } return false; } fun is_floating(it: value): bool { match(it) { value::floating(var) return true; } return false; } fun is_double_precision(it: value): bool { match(it) { value::double_precision(var) return true; } return false; } fun is_void_nothing(it: value): bool { match(it) { value::void_nothing() return true; } return false; } fun is_pointer(it: value): bool { match(it) { value::pointer(var) return true; } return false; } fun is_object_like(it: value): bool { match(it) { value::object_like(var) return true; } return false; } fun is_variable(it: value): bool { match(it) { value::variable(var) return true; } return false; } fun print_value(v: ref value) { match (get_real_value(v)) { value::boolean(data) println(data) value::character(data) println(data) value::ucharacter(data) println(data) value::short_int(data) println(data) value::ushort_int(data) println(data) value::integer(data) println(data) value::uinteger(data) println(data) value::long_int(data) println(data) value::ulong_int(data) println(data) value::floating(data) println(data) value::double_precision(data) println(data) value::void_nothing() println("void") value::pointer(var) println("pointer") value::object_like(var) println("object_like") value::variable(var) println("variable") } } fun truthy(v: ref value):bool { match (get_real_value(v)) { value::boolean(data) return data value::character(data) return data != 0 value::ucharacter(data) return data != 0 value::short_int(data) return data != 0 value::ushort_int(data) return data != 0 value::integer(data) return data != 0 value::uinteger(data) return data != 0 value::long_int(data) return data != 0 value::ulong_int(data) return data != 0 value::floating(data) return data != 0 value::double_precision(data) return data != 0 value::pointer(data) return data.first != 0 } error("untruthy value") } fun do_basic_op(func_name: string, a: value, b: value): value { match (get_real_value(a)) { value::boolean(av) return do_basic_op_second_half(func_name, av, b, null()) value::character(av) return do_basic_op_second_half(func_name, av, b, null()) value::ucharacter(av) return do_basic_op_second_half(func_name, av, b, null()) value::short_int(av) return do_basic_op_second_half(func_name, av, b, null()) value::ushort_int(av) return do_basic_op_second_half(func_name, av, b, null()) value::integer(av) return do_basic_op_second_half(func_name, av, b, null()) value::uinteger(av) return do_basic_op_second_half(func_name, av, b, null()) value::long_int(av) return do_basic_op_second_half(func_name, av, b, null()) value::ulong_int(av) return do_basic_op_second_half(func_name, av, b, null()) value::floating(av) return do_basic_floating_op_second_half(func_name, av, b, null()) value::double_precision(av) return do_basic_floating_op_second_half(func_name, av, b, null()) value::pointer(av) { var inc_in_bytes = cast_value(b, type_ptr(base_type::ulong_int())).ulong_int * type_size(av.second->clone_with_decreased_indirection()) var ptr = null() if (func_name == "+") { ptr = ((av.first) cast *char + inc_in_bytes) cast *void } else if (func_name == "-") { ptr = ((av.first) cast *char - inc_in_bytes) cast *void } else { error("pointer arithmatic is not + or -") } return value::pointer(make_pair(ptr, av.second)) } value::void_nothing() error(string("basic op called with void_nothing as first param: ") + func_name) value::object_like() error(string("basic op called with object_like as first param: ") + func_name) } error(string("basic op called with something wrong as first param: ") + func_name) } fun do_basic_op_second_half(func_name: string, av: T, b: value, ptr_type: *type): value { // because of the trickery in do_basic_op, if either param is a pointer, it's b match (get_real_value(b)) { value::boolean(bv) return do_op(func_name, av, bv, ptr_type) value::character(bv) return do_op(func_name, av, bv, ptr_type) value::ucharacter(bv) return do_op(func_name, av, bv, ptr_type) value::short_int(bv) return do_op(func_name, av, bv, ptr_type) value::ushort_int(bv) return do_op(func_name, av, bv, ptr_type) value::integer(bv) return do_op(func_name, av, bv, ptr_type) value::uinteger(bv) return do_op(func_name, av, bv, ptr_type) value::long_int(bv) return do_op(func_name, av, bv, ptr_type) value::ulong_int(bv) return do_op(func_name, av, bv, ptr_type) value::floating(bv) return do_floating_op(func_name, av, bv, ptr_type) value::double_precision(bv) return do_floating_op(func_name, av, bv, ptr_type) value::void_nothing() error(string("basic op called with void_nothing as second param: ") + func_name) value::object_like() error(string("basic op called with object_like as second param: ") + func_name) // if one is a pointer, we want it to be a value::pointer(bv) return do_basic_op(func_name, b, raw_to_value(av)) } print_value(b) error(string("basic op called with something wrong as second param: ") + func_name) } fun do_op(op: string, a: T, b: U, ptr_type: *type): value { if (op == "+") return raw_to_value(a + b) if (op == "-") return raw_to_value(a - b) if (op == "*") return raw_to_value(a * b) if (op == "/") return raw_to_value(a / b) if (op == "<") return raw_to_value(a < b) if (op == ">") return raw_to_value(a > b) if (op == "<=") return raw_to_value(a <= b) if (op == ">=") return raw_to_value(a >= b) if (op == "==") return raw_to_value(a == b) if (op == "!=") return raw_to_value(a != b) if (op == "%") return raw_to_value(a % b) if (op == "^") return raw_to_value(a ^ b) if (op == "|") return raw_to_value(a | b) if (op == "&") return raw_to_value(a & b) error(("Invalid op: ") + op) } fun do_basic_floating_op_second_half(func_name: string, av: T, b: value, ptr_type: *type): value { // because of the trickery in do_basic_op, if either param is a pointer, it's b match (get_real_value(b)) { value::boolean(bv) return do_floating_op(func_name, av, bv, ptr_type) value::character(bv) return do_floating_op(func_name, av, bv, ptr_type) value::ucharacter(bv) return do_floating_op(func_name, av, bv, ptr_type) value::short_int(bv) return do_floating_op(func_name, av, bv, ptr_type) value::ushort_int(bv) return do_floating_op(func_name, av, bv, ptr_type) value::integer(bv) return do_floating_op(func_name, av, bv, ptr_type) value::uinteger(bv) return do_floating_op(func_name, av, bv, ptr_type) value::long_int(bv) return do_floating_op(func_name, av, bv, ptr_type) value::ulong_int(bv) return do_floating_op(func_name, av, bv, ptr_type) value::floating(bv) return do_floating_op(func_name, av, bv, ptr_type) value::double_precision(bv) return do_floating_op(func_name, av, bv, ptr_type) value::void_nothing() error(string("basic op called with void_nothing as second param: ") + func_name) value::object_like() error(string("basic op called with object_like as second param: ") + func_name) // if one is a pointer, we want it to be a value::pointer(bv) return do_basic_op(func_name, b, raw_to_value(av)) } print_value(b) error(string("basic op called with something wrong as second param: ") + func_name) } fun do_floating_op(op: string, a: T, b: U, ptr_type: *type): value { if (op == "+") return raw_to_value(a + b) if (op == "-") return raw_to_value(a - b) if (op == "*") return raw_to_value(a * b) if (op == "/") return raw_to_value(a / b) if (op == "<") return raw_to_value(a < b) if (op == ">") return raw_to_value(a > b) if (op == "<=") return raw_to_value(a <= b) if (op == ">=") return raw_to_value(a >= b) if (op == "==") return raw_to_value(a == b) if (op == "!=") return raw_to_value(a != b) error(("Invalid op: ") + op) } fun store_into_variable(to: value, from: value) { assert(is_variable(to), "trying to store into not variable") var variable = to.variable // check for indirection if (variable.second->indirection) { assert(is_pointer(from), "mismatching assignemnt types - from is not pointer") *(variable.first) cast **void = from.pointer.first return; } // TODO - check to make sure that we don't have to cast pre assign (perhaps alwyas send through the cast?) match (variable.second->base) { base_type::object() { assert(is_object_like(from), "mismatching assignemnt types - from is not object"); memmove(variable.first, from.object_like.first, type_size(from.object_like.second)); } base_type::adt() error(string("trying to store into an adt: ") + variable.second->to_string()) base_type::function() error(string("trying to store into a function: ") + variable.second->to_string()) base_type::boolean() { assert(is_boolean(from), "mismatching assignemnt types - from is not boolean"); *(variable.first) cast *bool = from.boolean; } base_type::character() { assert(is_character(from), "mismatching assignemnt types - from is not character"); *(variable.first) cast *char = from.character; } base_type::ucharacter() { assert(is_ucharacter(from), "mismatching assignemnt types - from is not ucharacter"); *(variable.first) cast *uchar = from.ucharacter; } base_type::short_int() { assert(is_short_int(from), "mismatching assignemnt types - from is not short_int"); *(variable.first) cast *short = from.short_int; } base_type::ushort_int() { assert(is_ushort_int(from), "mismatching assignemnt types - from is not ushort_int"); *(variable.first) cast *ushort = from.ushort_int; } base_type::integer() { assert(is_integer(from), "mismatching assignemnt types - from is not integer"); *(variable.first) cast *int = from.integer; } base_type::uinteger() { assert(is_uinteger(from), "mismatching assignemnt types - from is not uinteger"); *(variable.first) cast *uint = from.uinteger; } base_type::long_int() { assert(is_long_int(from), "mismatching assignemnt types - from is not long_int"); *(variable.first) cast *long = from.long_int; } base_type::ulong_int() { assert(is_ulong_int(from), "mismatching assignemnt types - from is not ulong_int"); *(variable.first) cast *ulong = from.ulong_int; } base_type::floating() { assert(is_floating(from), "mismatching assignemnt types - from is not floating"); *(variable.first) cast *float = from.floating; } base_type::double_precision() { assert(is_double_precision(from), "mismatching assignemnt types - from is not double"); *(variable.first) cast *double = from.double_precision; } } } fun get_real_value(v: value): value { if (!is_variable(v)) return v var variable = v.variable if (variable.second->indirection) return value::pointer(make_pair(*(variable.first) cast **void, variable.second)) match (variable.second->base) { // really this could just be make_pair(variable) base_type::object() return value::object_like(make_pair(variable.first, variable.second)) /*base_type::adt() return #sizeof<>*/ /*base_type::function() return #sizeof<>*/ base_type::boolean() return value::boolean(*(variable.first) cast *bool) base_type::character() return value::character(*(variable.first) cast *char) base_type::ucharacter() return value::ucharacter(*(variable.first) cast *uchar) base_type::short_int() return value::short_int(*(variable.first) cast *short) base_type::ushort_int() return value::ushort_int(*(variable.first) cast *ushort) base_type::integer() return value::integer(*(variable.first) cast *int) base_type::uinteger() return value::uinteger(*(variable.first) cast *uint) base_type::long_int() return value::long_int(*(variable.first) cast *long) base_type::ulong_int() return value::ulong_int(*(variable.first) cast *ulong) base_type::floating() return value::floating(*(variable.first) cast *float) base_type::double_precision() return value::double_precision(*(variable.first) cast *double) } error(string("Cannot get real value from variable: ") + variable.second->to_string()) } fun cast_value(v: value, to_type: *type): value { if (to_type->indirection) { match (get_real_value(v)) { value::boolean(data) return value::pointer(make_pair((data) cast *void, to_type)) value::character(data) return value::pointer(make_pair((data) cast *void, to_type)) value::ucharacter(data) return value::pointer(make_pair((data) cast *void, to_type)) value::short_int(data) return value::pointer(make_pair((data) cast *void, to_type)) value::ushort_int(data) return value::pointer(make_pair((data) cast *void, to_type)) value::integer(data) return value::pointer(make_pair((data) cast *void, to_type)) value::uinteger(data) return value::pointer(make_pair((data) cast *void, to_type)) value::long_int(data) return value::pointer(make_pair((data) cast *void, to_type)) value::ulong_int(data) return value::pointer(make_pair((data) cast *void, to_type)) // floats and anything object_like are illegal to cast from /*value::floating(data) return value::pointer(make_pair((data) cast *void, to_type))*/ /*value::double_precision(data) return value::pointer(make_pair((data) cast *void, to_type))*/ value::pointer(data) return value::pointer(make_pair(data.first, to_type)) } error("Bad cast to pointer") } match (to_type->base) { // object_like can't be casted /*base_type::object() return #sizeof<>*/ /*base_type::adt() return #sizeof<>*/ /*base_type::function() return #sizeof<>*/ base_type::boolean() return cast_value_second_half(v) base_type::character() return cast_value_second_half(v) base_type::ucharacter() return cast_value_second_half(v) base_type::short_int() return cast_value_second_half(v) base_type::ushort_int() return cast_value_second_half(v) base_type::integer() return cast_value_second_half(v) base_type::uinteger() return cast_value_second_half(v) base_type::long_int() return cast_value_second_half(v) base_type::ulong_int() return cast_value_second_half(v) // float and double need their own because it can't go from base_type::floating() match (get_real_value(v)) { value::boolean(data) return value::floating((data) cast float) value::character(data) return value::floating((data) cast float) value::ucharacter(data) return value::floating((data) cast float) value::short_int(data) return value::floating((data) cast float) value::ushort_int(data) return value::floating((data) cast float) value::integer(data) return value::floating((data) cast float) value::uinteger(data) return value::floating((data) cast float) value::long_int(data) return value::floating((data) cast float) value::ulong_int(data) return value::floating((data) cast float) value::floating(data) return get_real_value(v) value::double_precision(data) return value::floating((data) cast float) } base_type::double_precision() match (get_real_value(v)) { value::boolean(data) return value::double_precision((data) cast double) value::character(data) return value::double_precision((data) cast double) value::ucharacter(data) return value::double_precision((data) cast double) value::short_int(data) return value::double_precision((data) cast double) value::ushort_int(data) return value::double_precision((data) cast double) value::integer(data) return value::double_precision((data) cast double) value::uinteger(data) return value::double_precision((data) cast double) value::long_int(data) return value::double_precision((data) cast double) value::ulong_int(data) return value::double_precision((data) cast double) value::floating(data) return value::double_precision((data) cast double) value::double_precision(data) return get_real_value(v) } } error(string("Bad cast to ") + to_type->to_string()) } fun cast_value_second_half(v: value): value { match (get_real_value(v)) { // object_like can't be casted value::boolean(data) return raw_to_value((data) cast T) value::character(data) return raw_to_value((data) cast T) value::ucharacter(data) return raw_to_value((data) cast T) value::short_int(data) return raw_to_value((data) cast T) value::ushort_int(data) return raw_to_value((data) cast T) value::integer(data) return raw_to_value((data) cast T) value::uinteger(data) return raw_to_value((data) cast T) value::long_int(data) return raw_to_value((data) cast T) value::ulong_int(data) return raw_to_value((data) cast T) value::floating(data) return raw_to_value((data) cast T) value::double_precision(data) return raw_to_value((data) cast T) value::pointer(data) return raw_to_value((data.first) cast T) } error("Illegal type to cast cast from") } fun type_size(t: *type): ulong { if (t->indirection) return #sizeof<*void> match (t->base) { base_type::object() { var size = 0 t->type_def->type_def.variables.for_each(fun(i: *ast_node) size += type_size(i->declaration_statement.identifier->identifier.type);) return size } /*base_type::adt() return #sizeof<>*/ /*base_type::function() return #sizeof<>*/ base_type::boolean() return #sizeof base_type::character() return #sizeof base_type::ucharacter() return #sizeof base_type::short_int() return #sizeof base_type::ushort_int() return #sizeof base_type::integer() return #sizeof base_type::uinteger() return #sizeof base_type::long_int() return #sizeof base_type::ulong_int() return #sizeof base_type::floating() return #sizeof base_type::double_precision() return #sizeof } error(string("Invalid type for type_size: ") + t->to_string()) } fun offset_into_struct(struct_type: *type, ident: *ast_node): ulong { var size: ulong = 0 for (var i = 0; i < struct_type->type_def->type_def.variables.size; i++;) if (struct_type->type_def->type_def.variables[i]->declaration_statement.identifier == ident) break else size += type_size(struct_type->type_def->type_def.variables[i]->declaration_statement.identifier->identifier.type) return size } fun pop_and_free(var_stack: *stack>) { var_stack->pop().for_each(fun(k: string, v: value) { match(v) { value::variable(backing) { free(backing.first) } } }) } obj interpreter (Object) { var ast_to_syntax: map<*ast_node, *tree> var name_ast_map: map,*ast_node>> fun construct(name_ast_map_in: map,*ast_node>>, ast_to_syntax_in: map<*ast_node, *tree>): *interpreter { name_ast_map.copy_construct(&name_ast_map_in) ast_to_syntax.copy_construct(&ast_to_syntax_in) return this } fun operator=(old: ref interpreter) { destruct() copy_construct(&old) } fun copy_construct(old: *interpreter) { name_ast_map.copy_construct(&old->name_ast_map) ast_to_syntax.copy_construct(&old->ast_to_syntax) } fun destruct() { name_ast_map.destruct() ast_to_syntax.destruct() } fun call_main() { var results = vector<*ast_node>() name_ast_map.for_each(fun(key: string, value: pair<*tree,*ast_node>) { results += scope_lookup(string("main"), value.second) }) if (results.size != 1) error(string("wrong number of mains to call: ") + results.size) println("=============") println("calling main!") println("=============") var var_stack = stack>() var defer_stack = stack<*ast_node>() var result = call_function(results[0], vector(), vector<*ast_node>(), &var_stack, &defer_stack, value::void_nothing()) println("=============") println("Main returned: ") print_value(result) println("=============") } fun interpret_function_call(func_call: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { var func_call_parameters = func_call->function_call.parameters var func_call_func = func_call->function_call.func var new_enclosing_object = value::void_nothing() // note here also that this is likely not a foolproof method if (is_dot_style_method_call(func_call)) { new_enclosing_object = get_real_value(interpret(func_call_func->function_call.parameters[0], var_stack, enclosing_object, defer_stack).first) // do a dereference if (is_pointer(new_enclosing_object)) new_enclosing_object = get_real_value(value::variable(make_pair(new_enclosing_object.pointer.first, new_enclosing_object.pointer.second->clone_with_decreased_indirection()))) func_call_func = func_call_func->function_call.parameters[1] } else if (!is_void_nothing(enclosing_object)) { if (method_in_object(func_call_func, enclosing_object.object_like.second->type_def)) { // should maybe do something special for closure here // copy over old enclosing object new_enclosing_object = enclosing_object } } // check if it's a same method method call and do the right new_enclosing_object // new_enclosing_object = enclosing_object var func_name = func_call_func->function.name // some of these have to be done before parameters are evaluated (&&, ||, ., ->) if (func_name == "&&" || func_name == "||") { var p1true = truthy(get_real_value(interpret(func_call_parameters[0], var_stack, enclosing_object, defer_stack).first)) if ( (func_name == "&&" && !p1true) || (func_name == "||" && p1true) ) return make_pair(value::boolean(p1true), control_flow::nor()) return make_pair(value::boolean(truthy(get_real_value(interpret(func_call_parameters[1], var_stack, enclosing_object, defer_stack).first))), control_flow::nor()) } else if (func_name == "." || func_name == "->") { var left_side = get_real_value(interpret(func_call_parameters[0], var_stack, enclosing_object, defer_stack).first) var ret_ptr = null() if (func_name == "->") ret_ptr = ((left_side.pointer.first) cast *char + offset_into_struct(left_side.pointer.second->clone_with_decreased_indirection(), func_call_parameters[1])) cast *void else ret_ptr = ((left_side.object_like.first) cast *char + offset_into_struct(left_side.object_like.second, func_call_parameters[1])) cast *void return make_pair(value::variable(make_pair(ret_ptr, func_call_parameters[1]->identifier.type)), control_flow::nor()) } // so here we either do an operator, call call_func with value parameters, or call call_func with ast_expressions // (so we can properly copy_construct if necessary) var parameters = vector() var parameter_sources = vector<*ast_node>() // if we don't have to copy_construct params (is an operator, or has no object params) if (func_name == "&" || !func_call_parameters.any_true(fun(p: *ast_node): bool return get_ast_type(p)->is_object_like() && get_ast_type(p)->indirection == 0;)) { parameters = func_call_parameters.map(fun(p: *ast_node): value return interpret(p, var_stack, enclosing_object, defer_stack).first;) 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 == "&" )) return make_pair(do_basic_op(func_name, parameters[0], parameters[1]), control_flow::nor()) // do negate by subtracting from zero if (func_name == "-") return make_pair(do_basic_op_second_half(string("-"), 0, parameters[0], null()), control_flow::nor()) if (func_name == "++p" || func_name == "--p") { var to_ret = get_real_value(parameters[0]) store_into_variable(parameters[0], do_basic_op(func_name.slice(0,1), parameters[0], value::integer(1))) return make_pair(to_ret, control_flow::nor()) } if (func_name == "++" || func_name == "--") { store_into_variable(parameters[0], do_basic_op(func_name.slice(0,1), parameters[0], value::integer(1))) return make_pair(get_real_value(parameters[0]), control_flow::nor()) } if (func_name == "&") { if (!is_variable(parameters[0])) error("Trying to take address of not a variable") return make_pair(value::pointer(make_pair(parameters[0].variable.first, parameters[0].variable.second->clone_with_increased_indirection())), control_flow::nor()) } // to dereference, we basically take the pointer's value (maybe going through a variable to get it) // and re-wrap it up into a variable value (so it can be assigned to, etc) if (func_name == "*" || func_name == "[]") { var dereference_val = parameters[0] if (func_name == "[]") dereference_val = do_basic_op(string("+"), parameters[0], parameters[1]) if (!is_pointer(get_real_value(parameters[0]))) error("Trying to take dereference not a pointer") return make_pair(value::variable(make_pair(get_real_value(dereference_val).pointer.first, dereference_val.pointer.second->clone_with_decreased_indirection())), control_flow::nor()) } // check for built-in-ish externs (everything the standard library needs) if (func_name == "printf" || func_name == "malloc" || func_name == "free" || func_name == "fflush" || func_name == "snprintf") return make_pair(call_built_in_extern(func_name, parameters), control_flow::nor()) if (!func_call_func->function.body_statement) error(string("trying to call unsupported extern function: ") + func_name) } else { // not the operator & and at least one object like parameter parameter_sources = func_call_parameters } return make_pair(call_function(func_call_func, parameters, parameter_sources, var_stack, defer_stack, new_enclosing_object), control_flow::nor()) } // call_function can be called with either parameter values in parameters or ast expressions in parameter_sources // this is to allow easy function calling if we already have the values (for main, say, or to make our job if it's not // an operator easier), but we need to be able to be called with ast_expressions too so we can properly copy_construct once fun call_function(func: *ast_node, parameters: vector, parameter_sources: vector<*ast_node>, var_stack: *stack>, defer_stack: *stack<*ast_node>, enclosing_object: value): value { // will need adjustment var func_name = func->function.name // do regular function var new_var_stack = stack>() // the new defer stack takes care of destructing parameters that were copy_constructed var new_defer_stack = stack<*ast_node>() // if this is a value based call, pull from parameters if (parameter_sources.size == 0) { new_var_stack.push(map()) /*println(func_name + " being called with parameter values")*/ if (parameters.size != func->function.parameters.size) error(string("calling function ") + func->function.name + " with wrong number of parameters (values)") for (var i = 0; i < parameters.size; i++;) { var param_type = get_ast_type(func)->parameter_types[i] var param_ident = func->function.parameters[i] new_var_stack.top()[param_ident->identifier.name] = value::variable(make_pair(malloc(type_size(param_type)), param_type)) store_into_variable(new_var_stack.top()[param_ident->identifier.name], get_real_value(parameters[i])) } } else { // on this side we construct in the old var stack, then move it over to the new one so that references resolve correctly var_stack->push(map()) /*println(func_name + " being called with parameter sources")*/ // need to pull from parameter_sources instead if (parameter_sources.size != func->function.parameters.size) error(string("calling function ") + func->function.name + " with wrong number of parameters (sources)") for (var i = 0; i < parameter_sources.size; i++;) { var param_type = get_ast_type(func)->parameter_types[i] var param_ident = func->function.parameters[i] /*println(param_ident->identifier.name + " is the name of the identifier being added")*/ var_stack->top()[param_ident->identifier.name] = value::variable(make_pair(malloc(type_size(param_type)), param_type)) if (param_type->indirection == 0 && (param_type->is_adt() || (param_type->is_object() && has_method(param_type->type_def, "copy_construct", vector(param_type->clone_with_increased_indirection()))))) { interpret(ast_statement_ptr(make_method_call(param_ident, "copy_construct", vector(make_operator_call("&", vector(parameter_sources[i]))))), var_stack, enclosing_object, defer_stack) new_defer_stack.push(ast_statement_ptr(make_method_call(param_ident, "destruct", vector<*ast_node>()))) } else { store_into_variable(var_stack->top()[param_ident->identifier.name], get_real_value(interpret(parameter_sources[i], var_stack, enclosing_object, defer_stack).first)) } } // swap the params over new_var_stack.push(var_stack->pop()) } var to_ret = interpret(func->function.body_statement, &new_var_stack, enclosing_object, &new_defer_stack).first // handle destructing params interpret_from_defer_stack(&new_defer_stack, &new_var_stack, enclosing_object) // need to handle copying out object before pop_and_free deletes them pop_and_free(&new_var_stack) return to_ret } fun call_built_in_extern(func_name: string, parameters: vector): value { /*println(string("calling func: ") + func_name)*/ for (var i = 0; i < parameters.size; i++;) parameters[i] = get_real_value(parameters[i]) if (func_name == "printf") { assert(parameters.size == 2 && is_pointer(parameters[0]) && is_pointer(parameters[1]), "Calling printf with wrong params") printf((parameters[0].pointer.first) cast *char, (parameters[1].pointer.first) cast *char) return value::integer(0) } else if (func_name == "malloc") { assert(parameters.size == 1 && is_ulong_int(parameters[0]), "Calling malloc with wrong params") return value::pointer(make_pair(malloc(parameters[0].ulong_int), type_ptr(base_type::void_return())->clone_with_increased_indirection())) } else if (func_name == "free") { assert(parameters.size == 1 && is_pointer(parameters[0]), "Calling free with wrong params") free(parameters[0].pointer.first) } else if (func_name == "fflush") { assert(parameters.size == 1 && is_integer(parameters[0]), "Calling fflush with wrong params") fflush(parameters[0].integer) } else if (func_name == "snprintf") { assert(parameters.size == 4 && is_pointer(parameters[0]) && is_ulong_int(parameters[1]) && is_pointer(parameters[2]) && is_double_precision(parameters[3]), "Calling snprintf with wrong params") return value::integer(snprintf((parameters[0].pointer.first) cast *char, parameters[1].ulong_int, (parameters[2].pointer.first) cast *char, parameters[3].double_precision)) } else if (func_name == "exit") { assert(parameters.size == 1 && is_integer(parameters[0]), "Calling exit with wrong params") exit(parameters[0].integer) } else { error(string("trying to call invalid func: ") + func_name) } return value::void_nothing() } fun interpret_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { return interpret(stmt->statement.child, var_stack, enclosing_object, defer_stack) } fun interpret_if_statement(if_stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { var_stack->push(map()) if (truthy(interpret(if_stmt->if_statement.condition, var_stack, enclosing_object, defer_stack).first)) { interpret(if_stmt->if_statement.then_part, var_stack, enclosing_object, defer_stack) } else if (if_stmt->if_statement.else_part) { interpret(if_stmt->if_statement.else_part, var_stack, enclosing_object, defer_stack) } pop_and_free(var_stack) return make_pair(value::void_nothing(), control_flow::nor()) } fun interpret_while_loop(while_loop: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { var_stack->push(map()) while (truthy(interpret(while_loop->while_loop.condition, var_stack, enclosing_object, defer_stack).first)) { interpret(while_loop->while_loop.statement, var_stack, enclosing_object, defer_stack) } pop_and_free(var_stack) return make_pair(value::void_nothing(), control_flow::nor()) } fun interpret_for_loop(for_loop: *ast_node, var_stack: *stack>, enclosing_object: value): pair { var defer_stack = stack<*ast_node>() var_stack->push(map()) interpret(for_loop->for_loop.init, var_stack, enclosing_object, &defer_stack) while (truthy(interpret(for_loop->for_loop.condition, var_stack, enclosing_object, &defer_stack).first)) { var inner_defer_stack = stack<*ast_node>() interpret(for_loop->for_loop.body, var_stack, enclosing_object, &inner_defer_stack) interpret(for_loop->for_loop.update, var_stack, enclosing_object, &inner_defer_stack) interpret_from_defer_stack(&defer_stack, var_stack, enclosing_object) } pop_and_free(var_stack) return make_pair(value::void_nothing(), control_flow::nor()) } fun interpret_code_block(block: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { var_stack->push(map()) var defer_stack = stack<*ast_node>() for (var i = 0; i < block->code_block.children.size; i++;) { var statement = interpret(block->code_block.children[i], var_stack, enclosing_object, &defer_stack) match (statement.second) { control_flow::con() { interpret_from_defer_stack(&defer_stack, var_stack, enclosing_object) pop_and_free(var_stack) return make_pair(value::void_nothing(), control_flow::con()) } control_flow::bre() { interpret_from_defer_stack(&defer_stack, var_stack, enclosing_object) pop_and_free(var_stack) return make_pair(value::void_nothing(), control_flow::bre()) } control_flow::ret() { interpret_from_defer_stack(&defer_stack, var_stack, enclosing_object) pop_and_free(var_stack) return statement } } // if nor, continue on } interpret_from_defer_stack(&defer_stack, var_stack, enclosing_object) pop_and_free(var_stack) return make_pair(value::void_nothing(), control_flow::nor()) } fun interpret_from_defer_stack(defer_stack: *stack<*ast_node>, var_stack: *stack>, enclosing_object: value) { var new_defer_stack = stack<*ast_node>() defer_stack->for_each_reverse(fun(i: *ast_node) { interpret(i, var_stack, enclosing_object, &new_defer_stack) }) if (new_defer_stack.size()) interpret_from_defer_stack(&new_defer_stack, var_stack, enclosing_object) } fun interpret_return_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { return make_pair(get_real_value(interpret(stmt->return_statement.return_value, var_stack, enclosing_object, defer_stack).first), control_flow::ret()) } fun interpret_declaration_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { var ident = stmt->declaration_statement.identifier var ident_type = ident->identifier.type var ident_name = ident->identifier.name var_stack->top()[ident_name] = value::variable(make_pair(malloc(type_size(ident_type)),ident_type)) if (stmt->declaration_statement.expression) { if (ident_type->indirection == 0 && (ident_type->is_adt() || (ident_type->is_object() && has_method(ident_type->type_def, "copy_construct", vector(get_ast_type(stmt->declaration_statement.expression)->clone_with_increased_indirection()))))) interpret(ast_statement_ptr(make_method_call(ident, "copy_construct", vector(make_operator_call("&", vector(stmt->declaration_statement.expression))))), var_stack, enclosing_object, defer_stack) else store_into_variable(var_stack->top()[ident_name], get_real_value(interpret(stmt->declaration_statement.expression, var_stack, enclosing_object, defer_stack).first)) } else if (stmt->declaration_statement.init_method_call) { interpret(stmt->declaration_statement.init_method_call, var_stack, enclosing_object, defer_stack) } // defering destructs if (ident_type->indirection == 0 && (ident_type->is_adt() || (ident_type->is_object() && has_method(ident_type->type_def, "destruct", vector<*type>())))) defer_stack->push(ast_statement_ptr(make_method_call(ident, "destruct", vector<*ast_node>()))) return make_pair(value::void_nothing(), control_flow::nor()) } fun interpret_assignment_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { var to = interpret(stmt->assignment_statement.to, var_stack, enclosing_object, defer_stack).first var from = interpret(stmt->assignment_statement.from, var_stack, enclosing_object, defer_stack).first assert(is_variable(to), "assigning into not a variable") // first, we have to see if this is an object // always do cast now to make our best effort at assignment (assign into a double from a float, etc) store_into_variable(to, cast_value(get_real_value(from), to.variable.second)) return make_pair(value::void_nothing(), control_flow::nor()) } fun interpret_defer_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { defer_stack->push(stmt->defer_statement.statement) return make_pair(value::void_nothing(), control_flow::nor()) } fun interpret_identifier(ident: *ast_node, var_stack: *stack>, enclosing_object: value): pair { for (var i = 0; i < var_stack->size(); i++;) if (var_stack->from_top(i).contains_key(ident->identifier.name)) return make_pair(var_stack->from_top(i)[ident->identifier.name], control_flow::nor()) // check for object member / this if (is_object_like(enclosing_object)) { if (ident->identifier.name == "this") return make_pair(value::pointer(make_pair(enclosing_object.object_like.first, enclosing_object.object_like.second->clone_with_increased_indirection())), control_flow::nor()) var object_def = enclosing_object.object_like.second->type_def for (var i = 0; i < object_def->type_def.variables.size; i++;) { if (object_def->type_def.variables[i]->declaration_statement.identifier == ident) { var ret_ptr = ((enclosing_object.object_like.first) cast *char + offset_into_struct(enclosing_object.object_like.second, ident)) cast *void return make_pair(value::variable(make_pair(ret_ptr, ident->identifier.type)), control_flow::nor()) } } } error(string("Cannot find variable: ") + ident->identifier.name) } fun interpret_cast(node: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { return make_pair(cast_value(interpret(node->cast.value, var_stack, enclosing_object, defer_stack).first, node->cast.to_type), control_flow::nor()) } fun interpret_compiler_intrinsic(node: *ast_node, var_stack: *stack>): pair { var intrinsic_name = node->compiler_intrinsic.intrinsic if (intrinsic_name == "sizeof") return make_pair(value::ulong_int(type_size(node->compiler_intrinsic.type_parameters[0])), control_flow::nor()) error(string("bad intrinsic: ") + intrinsic_name) } fun interpret_value(val: *ast_node): pair return make_pair(wrap_value(val), control_flow::nor()) fun interpret(node: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { match (*node) { ast_node::function_call(backing) return interpret_function_call(node, var_stack, enclosing_object, defer_stack) ast_node::statement(backing) return interpret_statement(node, var_stack, enclosing_object, defer_stack) ast_node::if_statement(backing) return interpret_if_statement(node, var_stack, enclosing_object, defer_stack) ast_node::while_loop(backing) return interpret_while_loop(node, var_stack, enclosing_object, defer_stack) ast_node::for_loop(backing) return interpret_for_loop(node, var_stack, enclosing_object) ast_node::code_block(backing) return interpret_code_block(node, var_stack, enclosing_object, defer_stack) ast_node::return_statement(backing) return interpret_return_statement(node, var_stack, enclosing_object, defer_stack) ast_node::declaration_statement(backing) return interpret_declaration_statement(node, var_stack, enclosing_object, defer_stack) ast_node::assignment_statement(backing) return interpret_assignment_statement(node, var_stack, enclosing_object, defer_stack) ast_node::defer_statement(backing) return interpret_defer_statement(node, var_stack, enclosing_object, defer_stack) ast_node::identifier(backing) return interpret_identifier(node, var_stack, enclosing_object) ast_node::cast(backing) return interpret_cast(node, var_stack, enclosing_object, defer_stack) ast_node::compiler_intrinsic(backing) return interpret_compiler_intrinsic(node, var_stack) ast_node::value(backing) return interpret_value(node) } error(string("Cannot interpret node: ") + get_ast_name(node)) } }