806 lines
49 KiB
Plaintext
806 lines
49 KiB
Plaintext
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<type>())
|
|
value::character(av) return do_basic_op_second_half(func_name, av, b, null<type>())
|
|
value::ucharacter(av) return do_basic_op_second_half(func_name, av, b, null<type>())
|
|
value::short_int(av) return do_basic_op_second_half(func_name, av, b, null<type>())
|
|
value::ushort_int(av) return do_basic_op_second_half(func_name, av, b, null<type>())
|
|
value::integer(av) return do_basic_op_second_half(func_name, av, b, null<type>())
|
|
value::uinteger(av) return do_basic_op_second_half(func_name, av, b, null<type>())
|
|
value::long_int(av) return do_basic_op_second_half(func_name, av, b, null<type>())
|
|
value::ulong_int(av) return do_basic_op_second_half(func_name, av, b, null<type>())
|
|
value::floating(av) return do_basic_floating_op_second_half(func_name, av, b, null<type>())
|
|
value::double_precision(av) return do_basic_floating_op_second_half(func_name, av, b, null<type>())
|
|
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<void>()
|
|
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<T>(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<T,U>(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<T>(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<T,U>(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<bool>(v)
|
|
base_type::character() return cast_value_second_half<char>(v)
|
|
base_type::ucharacter() return cast_value_second_half<uchar>(v)
|
|
base_type::short_int() return cast_value_second_half<short>(v)
|
|
base_type::ushort_int() return cast_value_second_half<ushort>(v)
|
|
base_type::integer() return cast_value_second_half<int>(v)
|
|
base_type::uinteger() return cast_value_second_half<uint>(v)
|
|
base_type::long_int() return cast_value_second_half<long>(v)
|
|
base_type::ulong_int() return cast_value_second_half<ulong>(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<T>(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<bool>
|
|
base_type::character() return #sizeof<char>
|
|
base_type::ucharacter() return #sizeof<uchar>
|
|
base_type::short_int() return #sizeof<short>
|
|
base_type::ushort_int() return #sizeof<ushort>
|
|
base_type::integer() return #sizeof<int>
|
|
base_type::uinteger() return #sizeof<uint>
|
|
base_type::long_int() return #sizeof<long>
|
|
base_type::ulong_int() return #sizeof<ulong>
|
|
base_type::floating() return #sizeof<float>
|
|
base_type::double_precision() return #sizeof<double>
|
|
}
|
|
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<map<string, value>>) {
|
|
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<symbol>>
|
|
var name_ast_map: map<string, pair<*tree<symbol>,*ast_node>>
|
|
fun construct(name_ast_map_in: map<string, pair<*tree<symbol>,*ast_node>>, ast_to_syntax_in: map<*ast_node, *tree<symbol>>): *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<symbol>,*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<map<string, value>>()
|
|
var defer_stack = stack<*ast_node>()
|
|
var result = call_function(results[0], vector<value>(), 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<map<string, value>>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair<value, control_flow> {
|
|
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<void>()
|
|
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<value>()
|
|
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<type>()), 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<value>, parameter_sources: vector<*ast_node>, var_stack: *stack<map<string, value>>, 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<map<string, value>>()
|
|
// 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<string,value>())
|
|
/*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<string,value>())
|
|
/*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>): 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<map<string, value>>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair<value, control_flow> {
|
|
return interpret(stmt->statement.child, var_stack, enclosing_object, defer_stack)
|
|
}
|
|
fun interpret_if_statement(if_stmt: *ast_node, var_stack: *stack<map<string, value>>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair<value, control_flow> {
|
|
var_stack->push(map<string,value>())
|
|
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<map<string, value>>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair<value, control_flow> {
|
|
var_stack->push(map<string,value>())
|
|
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<map<string, value>>, enclosing_object: value): pair<value, control_flow> {
|
|
var defer_stack = stack<*ast_node>()
|
|
var_stack->push(map<string,value>())
|
|
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<map<string, value>>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair<value, control_flow> {
|
|
var_stack->push(map<string,value>())
|
|
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<map<string, value>>, 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<map<string, value>>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair<value, control_flow> {
|
|
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<map<string, value>>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair<value, control_flow> {
|
|
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<map<string, value>>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair<value, control_flow> {
|
|
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<map<string, value>>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair<value, control_flow> {
|
|
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<map<string, value>>, enclosing_object: value): pair<value, control_flow> {
|
|
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<map<string, value>>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair<value, control_flow> {
|
|
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<map<string, value>>): pair<value, control_flow> {
|
|
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<value, control_flow>
|
|
return make_pair(wrap_value(val), control_flow::nor())
|
|
fun interpret(node: *ast_node, var_stack: *stack<map<string, value>>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair<value, control_flow> {
|
|
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))
|
|
}
|
|
}
|
|
|