361 lines
18 KiB
Plaintext
361 lines
18 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:*
|
|
|
|
adt value {
|
|
integer: int,
|
|
floating: float,
|
|
double_precision: double,
|
|
void_nothing,
|
|
pointer: pair<*void,*type>,
|
|
variable: pair<*void,*type>
|
|
}
|
|
adt control_flow {
|
|
nor,
|
|
con,
|
|
bre,
|
|
ret
|
|
}
|
|
fun is_integer(it: value): bool { match(it) { value::integer(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_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::integer(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::variable(var) println("variable")
|
|
}
|
|
}
|
|
fun truthy(v: ref value):bool {
|
|
match (get_real_value(v)) {
|
|
value::integer(data) return data != 0
|
|
value::floating(data) return data != 0
|
|
value::double_precision(data) return data != 0
|
|
value::pointer(data) return data.first != 0
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
match (variable.second->base) {
|
|
/*base_type::object() return #sizeof<>*/
|
|
/*base_type::adt() return #sizeof<>*/
|
|
/*base_type::function() return #sizeof<>*/
|
|
/*base_type::boolean() return *(variable.first) cast bool*/
|
|
/*base_type::character() return *(variable.first) cast char*/
|
|
/*base_type::ucharacter() return *(variable.first) cast uchar*/
|
|
/*base_type::short_int() return *(variable.first) cast short*/
|
|
/*base_type::ushort_int() return *(variable.first) cast ushort*/
|
|
base_type::integer() { assert(is_integer(from), "mismatching assignemnt types - from is not integer"); *(variable.first) cast *int = from.integer; }
|
|
/*base_type::uinteger() return *(variable.first) cast uint*/
|
|
/*base_type::long_int() return *(variable.first) cast long*/
|
|
/*base_type::ulong_int() return *(variable.first) cast ulong*/
|
|
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) {
|
|
/*base_type::object() return #sizeof<>*/
|
|
/*base_type::adt() return #sizeof<>*/
|
|
/*base_type::function() return #sizeof<>*/
|
|
/*base_type::boolean() return *(variable.first) cast bool*/
|
|
/*base_type::character() return *(variable.first) cast char*/
|
|
/*base_type::ucharacter() return *(variable.first) cast uchar*/
|
|
/*base_type::short_int() return *(variable.first) cast short*/
|
|
/*base_type::ushort_int() return *(variable.first) cast ushort*/
|
|
base_type::integer() return value::integer(*(variable.first) cast *int)
|
|
/*base_type::uinteger() return *(variable.first) cast uint*/
|
|
/*base_type::long_int() return *(variable.first) cast long*/
|
|
/*base_type::ulong_int() return *(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("Cannot get real value from variable")
|
|
}
|
|
fun type_size(t: *type): ulong {
|
|
if (t->indirection)
|
|
return #sizeof<*void>
|
|
match (t->base) {
|
|
/*base_type::object() return #sizeof<>*/
|
|
/*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>
|
|
}
|
|
}
|
|
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("calling main!")
|
|
var var_stack = stack<map<string, value>>()
|
|
print_value(call_function(results[0], vector<value>(), &var_stack))
|
|
}
|
|
fun interpret_function_call(func_call: *ast_node, var_stack: *stack<map<string, value>>): pair<value, control_flow> {
|
|
// should handle dot style method call here
|
|
var parameters = func_call->function_call.parameters.map(fun(p: *ast_node): value return interpret(p, var_stack).first;)
|
|
return make_pair(call_function(func_call->function_call.func, parameters, var_stack), control_flow::nor())
|
|
}
|
|
fun call_function(func: *ast_node, parameters: vector<value>, var_stack: *stack<map<string, value>>): value {
|
|
// will need adjustment
|
|
var func_name = func->function.name
|
|
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 do_basic_op(func_name, parameters[0], parameters[1])
|
|
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 to_ret
|
|
}
|
|
if (func_name == "++" || func_name == "--") {
|
|
store_into_variable(parameters[0], do_basic_op(func_name.slice(0,1), parameters[0], value::integer(1)))
|
|
return get_real_value(parameters[0])
|
|
}
|
|
if (func_name == "&") {
|
|
if (!is_variable(parameters[0]))
|
|
error("Trying to take address of not a variable")
|
|
return value::pointer(make_pair(parameters[0].variable.first, parameters[0].variable.second->clone_with_increased_indirection()))
|
|
}
|
|
// 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 == "*") {
|
|
if (!is_pointer(get_real_value(parameters[0])))
|
|
error("Trying to take dereference not a pointer")
|
|
return value::variable(make_pair(get_real_value(parameters[0]).pointer.first, parameters[0].pointer.second->clone_with_decreased_indirection()))
|
|
}
|
|
var_stack->push(map<string,value>())
|
|
if (parameters.size != func->function.parameters.size)
|
|
error(string("calling function ") + func->function.name + " with wrong number of parameters")
|
|
for (var i = 0; i < parameters.size; i++;) {
|
|
var param_type = get_ast_type(func)->parameter_types[i]
|
|
var_stack->top()[func->function.parameters[i]->identifier.name] = value::variable(make_pair(malloc(type_size(param_type)), param_type))
|
|
store_into_variable(var_stack->top()[func->function.parameters[i]->identifier.name], get_real_value(parameters[i]))
|
|
}
|
|
var to_ret = interpret(func->function.body_statement, var_stack).first
|
|
pop_and_free(var_stack)
|
|
return to_ret
|
|
}
|
|
fun interpret_statement(stmt: *ast_node, var_stack: *stack<map<string, value>>): pair<value, control_flow> {
|
|
return interpret(stmt->statement.child, var_stack)
|
|
}
|
|
fun interpret_if_statement(if_stmt: *ast_node, var_stack: *stack<map<string, value>>): pair<value, control_flow> {
|
|
var_stack->push(map<string,value>())
|
|
if (truthy(interpret(if_stmt->if_statement.condition, var_stack).first)) {
|
|
interpret(if_stmt->if_statement.then_part, var_stack)
|
|
} else if (if_stmt->if_statement.else_part) {
|
|
interpret(if_stmt->if_statement.else_part, var_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>>): pair<value, control_flow> {
|
|
var_stack->push(map<string,value>())
|
|
while (truthy(interpret(while_loop->while_loop.condition, var_stack).first)) {
|
|
interpret(while_loop->while_loop.statement, var_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>>): pair<value, control_flow> {
|
|
var_stack->push(map<string,value>())
|
|
interpret(for_loop->for_loop.init, var_stack)
|
|
while (truthy(interpret(for_loop->for_loop.condition, var_stack).first)) {
|
|
interpret(for_loop->for_loop.body, var_stack)
|
|
interpret(for_loop->for_loop.update, var_stack)
|
|
}
|
|
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>>): pair<value, control_flow> {
|
|
var_stack->push(map<string,value>())
|
|
for (var i = 0; i < block->code_block.children.size; i++;) {
|
|
var statement = interpret(block->code_block.children[i], var_stack)
|
|
match (statement.second) {
|
|
control_flow::con() {
|
|
pop_and_free(var_stack)
|
|
return make_pair(value::void_nothing(), control_flow::con())
|
|
}
|
|
control_flow::bre() {
|
|
pop_and_free(var_stack)
|
|
return make_pair(value::void_nothing(), control_flow::bre())
|
|
}
|
|
control_flow::ret() {
|
|
pop_and_free(var_stack)
|
|
return statement
|
|
}
|
|
}
|
|
// if nor, continue on
|
|
}
|
|
pop_and_free(var_stack)
|
|
return make_pair(value::void_nothing(), control_flow::nor())
|
|
}
|
|
fun interpret_return_statement(stmt: *ast_node, var_stack: *stack<map<string, value>>): pair<value, control_flow> {
|
|
return make_pair(get_real_value(interpret(stmt->return_statement.return_value, var_stack).first), control_flow::ret())
|
|
}
|
|
fun interpret_declaration_statement(stmt: *ast_node, var_stack: *stack<map<string, value>>): pair<value, control_flow> {
|
|
var ident_type = stmt->declaration_statement.identifier->identifier.type
|
|
var ident_name = stmt->declaration_statement.identifier->identifier.name
|
|
var_stack->top()[ident_name] = value::variable(make_pair(malloc(type_size(ident_type)),ident_type))
|
|
if (stmt->declaration_statement.expression)
|
|
store_into_variable(var_stack->top()[ident_name], get_real_value(interpret(stmt->declaration_statement.expression, var_stack).first))
|
|
return make_pair(value::void_nothing(), control_flow::nor())
|
|
}
|
|
fun interpret_assignment_statement(stmt: *ast_node, var_stack: *stack<map<string, value>>): pair<value, control_flow> {
|
|
var to = interpret(stmt->assignment_statement.to, var_stack).first
|
|
var from = interpret(stmt->assignment_statement.from, var_stack).first
|
|
store_into_variable(to, get_real_value(from))
|
|
return make_pair(value::void_nothing(), control_flow::nor())
|
|
}
|
|
fun interpret_identifier(ident: *ast_node, var_stack: *stack<map<string, 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())
|
|
error("Cannot find variable")
|
|
}
|
|
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>>): pair<value, control_flow> {
|
|
match (*node) {
|
|
ast_node::function_call(backing) return interpret_function_call(node, var_stack)
|
|
ast_node::statement(backing) return interpret_statement(node, var_stack)
|
|
ast_node::if_statement(backing) return interpret_if_statement(node, var_stack)
|
|
ast_node::while_loop(backing) return interpret_while_loop(node, var_stack)
|
|
ast_node::for_loop(backing) return interpret_for_loop(node, var_stack)
|
|
ast_node::code_block(backing) return interpret_code_block(node, var_stack)
|
|
ast_node::return_statement(backing) return interpret_return_statement(node, var_stack)
|
|
ast_node::declaration_statement(backing) return interpret_declaration_statement(node, var_stack)
|
|
ast_node::assignment_statement(backing) return interpret_assignment_statement(node, var_stack)
|
|
ast_node::identifier(backing) return interpret_identifier(node, var_stack)
|
|
ast_node::value(backing) return interpret_value(node)
|
|
}
|
|
error(string("Cannot interpret node: ") + get_ast_name(node))
|
|
}
|
|
fun do_basic_op(func_name: string, a: value, b: value): value {
|
|
match (get_real_value(a)) {
|
|
value::integer(av) {
|
|
match (get_real_value(b)) {
|
|
value::integer(bv) return value::integer(do_op<int,int,int>(func_name, av, bv))
|
|
}
|
|
}
|
|
}
|
|
return value::integer(a.integer + b.integer)
|
|
}
|
|
fun do_op<T,U,W>(op: string, a: T, b: U): W {
|
|
if (op == "+") return a + b
|
|
if (op == "-") return a - b
|
|
if (op == "*") return a * b
|
|
if (op == "/") return a / b
|
|
if (op == "<") return a < b
|
|
if (op == ">") return a > b
|
|
if (op == "<=") return a <= b
|
|
if (op == ">=") return a >= b
|
|
if (op == "==") return a == b
|
|
if (op == "!=") return a != b
|
|
if (op == "%") return a % b
|
|
if (op == "^") return a ^ b
|
|
if (op == "|") return a | b
|
|
if (op == "&") return a & b
|
|
|
|
error(("Invalid op: ") + op)
|
|
}
|
|
fun wrap_value(val: *ast_node): value {
|
|
var value_str = val->value.string_value
|
|
if (value_str[0] == '"') // " // Comment hack for emacs now
|
|
return value::integer(1)
|
|
else if (value_str[0] == '\'') //'// lol, comment hack for vim syntax highlighting (my fault, of course)
|
|
return value::integer(1)
|
|
else if (value_str == "true" || value_str == "false")
|
|
return value::integer(1)
|
|
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(1.0f)
|
|
else
|
|
return value::double_precision(1.0)
|
|
else
|
|
return value::integer(string_to_int(value_str))
|
|
}
|
|
return value::void_nothing()
|
|
}
|
|
}
|
|
|