Refactored interpreter into just functions, added a REPL to the main kraken.

This commit is contained in:
Nathan Braswell
2016-07-03 15:32:45 -07:00
parent 87c2b1d2c1
commit 6fee942756
8 changed files with 846 additions and 896 deletions

View File

@@ -16,19 +16,32 @@ import c_line_control:*
import c_generator:*
import compiler_version
fun main(argc: int, argv: **char):int {
// delay construction until we either load it or copy construct it
var gram: grammer
var base_dir = string("/").join(string(argv[0]).split('/').slice(0,-2))
var file_name = base_dir + "/krakenGrammer.kgm"
var compiled_name = file_name + string(".comp_new")
var compiled_version = 1
var file_contents = read_file(file_name)
var loaded_and_valid = false
var doing_repl = false
if (argc <= 1) {
error("No input file!\n Call with one argument (the input file), or two arguments (input file and output name)")
println("No input file!\n Call with one argument (the input file), or two arguments (input file and output name)\n Falling into REPL...")
compiled_name += ".expr"
file_contents = string("RealGoal = boolean_expression ;\n") + file_contents
doing_repl = true
} else if (string(argv[1]) == "-v" || string(argv[1]) == "--version") {
println(compiler_version::version_string)
exit(0)
}
var input_file_offset = 1
var interpret_instead = false
var argv1_str = string(argv[1])
var opt_str = string("-O3")
var line_ctrl = false
if (!doing_repl) {
var argv1_str = string(argv[1])
if (argv1_str == "-i") {
interpret_instead = true
input_file_offset++
@@ -39,31 +52,17 @@ fun main(argc: int, argv: **char):int {
line_ctrl = true
input_file_offset++
}
var kraken_file_name = string(argv[input_file_offset])
var executable_name = string(".").join(kraken_file_name.split('.').slice(0,-2))
if (argc == input_file_offset+2)
executable_name = string(argv[input_file_offset+1])
// delay construction until we either load it or copy construct it
var gram: grammer
var base_dir = string("/").join(string(argv[0]).split('/').slice(0,-2))
var file_name = base_dir + "/krakenGrammer.kgm"
var compiled_name = file_name + string(".comp_new")
var compiled_version = 1
var file_contents = read_file(file_name)
var loaded_and_valid = false
}
if (file_exists(compiled_name)) {
/*println("cached file exists")*/
var pos = 0
var binary = read_file_binary(compiled_name)
/*println("read file!")*/
var saved_version = 0
unpack(saved_version, pos) = unserialize<int>(binary, pos)
if (saved_version == compiled_version) {
var cached_contents = string()
unpack(cached_contents, pos) = unserialize<string>(binary, pos)
if (cached_contents == file_contents) {
/*println("loaded_and_valid, using cached version!")*/
loaded_and_valid = true
pos = gram.unserialize(binary, pos)
} else println("contents different")
@@ -73,7 +72,6 @@ fun main(argc: int, argv: **char):int {
}
if (!loaded_and_valid) {
println("Not loaded_and_valid, re-generating and writing out")
/*gram = load_grammer(file_contents)*/
// since we now don't construct before hand
gram.copy_construct(&load_grammer(file_contents))
println("grammer loaded, calculate_first_set")
@@ -98,6 +96,22 @@ fun main(argc: int, argv: **char):int {
/*var parsers = vector(parse1,parse2,parse3,parse4)*/
/*var parsers = vector(parse1,parse2,parse3,parse4,parse5,parse6)*/
/*var parsers = vector(parse1,parse2,parse3,parse4,parse5,parse6,parse7,parse8)*/
// This is our REPL loop
var scope = ast_translation_unit_ptr(string("stdin"))
while (doing_repl) {
var line = get_line(string("> "), 100)
if (line == "end")
return 0
var trimmed_parse = trim(parse1.parse_input(line, string("stdin")))
var ast_expression = ast_pass.transform_expression(trimmed_parse, scope, map<string, *type>())
print_value(evaluate_constant_expression(ast_expression))
}
var kraken_file_name = string(argv[input_file_offset])
var executable_name = string(".").join(kraken_file_name.split('.').slice(0,-2))
if (argc == input_file_offset+2)
executable_name = string(argv[input_file_offset+1])
var importer.construct(parsers, ast_pass, vector(string(), base_dir + "/stdlib/")): importer
importer.import(kraken_file_name)
// Passes
@@ -109,8 +123,7 @@ fun main(argc: int, argv: **char):int {
defer_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)
if (interpret_instead) {
printlnerr("Interpreting!")
var interpret.construct(importer.name_ast_map, importer.ast_pass.ast_to_syntax): interpreter
interpret.call_main()
call_main(importer.name_ast_map)
} else {
if (line_ctrl) {
printlnerr("running C-specific passes")
@@ -122,7 +135,6 @@ fun main(argc: int, argv: **char):int {
var c_output_pair = c_generator.generate_c(importer.name_ast_map, importer.ast_pass.ast_to_syntax)
var kraken_c_output_name = kraken_file_name + ".c"
write_file(kraken_c_output_name, c_output_pair.first)
/*println(string("linker string: ") + c_output_pair.second)*/
var compile_string = "cc -g " + opt_str + " -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -std=c99 " + c_output_pair.second + " " + kraken_c_output_name + " -o " + executable_name
printlnerr(compile_string)
system(compile_string)

View File

@@ -11,6 +11,7 @@ import os:*
import importer:*
import ast_nodes:*
import type:*
import pass_common:*
adt search_type {
none,
@@ -1116,74 +1117,6 @@ obj ast_transformation (Object) {
return fitting_functions.max(fun(a: pair<*ast_node, int>, b: pair<*ast_node, int>): bool return a.second < b.second;).first
}
}
fun get_from_scope(node: *ast_node, member: *char): *ast_node
return get_from_scope(node, string(member))
fun get_from_scope(node: *ast_node, member: string): *ast_node
return get_ast_scope(node)->get(member).first()
fun has_method(object: *ast_node, name: *char, parameter_types: vector<*type>): bool return has_method(object, string(name), parameter_types);
fun has_method(object: *ast_node, name: string, parameter_types: vector<*type>): bool {
/*println("HAS METHOD:")*/
var to_ret = function_lookup(name, object, parameter_types) || false
/*println("HAS METHOD result:")*/
/*println(to_ret)*/
return to_ret
}
fun make_method_call(object_ident: *ast_node, name: *char, parameters: vector<*ast_node>): *ast_node return make_method_call(object_ident, string(name), parameters);
fun make_method_call(object_ident: *ast_node, name: string, parameters: vector<*ast_node>): *ast_node {
/*println("MAKE METHOD CALL OUT:")*/
// note that this type_def is the adt_def if this is an adt type
var method = function_lookup(name, get_ast_type(object_ident)->type_def, parameters.map(fun(param: *ast_node): *type return get_ast_type(param);))
/*print("Here is the Method: ")*/
/*println(method)*/
return make_method_call(object_ident, method, parameters)
}
fun make_method_call(object_ident: *ast_node, method: *ast_node, parameters: vector<*ast_node>): *ast_node {
/*println("MAKE METHOD CALL IN:")*/
var access_op = "."
if (get_ast_type(object_ident)->indirection)
access_op = "->"
var method_access = ast_function_call_ptr(get_builtin_function(string(access_op), vector(get_ast_type(object_ident), get_ast_type(method))), vector(object_ident, method))
return ast_function_call_ptr(method_access, parameters)
}
fun make_operator_call(func: *char, params: vector<*ast_node>): *ast_node return make_operator_call(string(func), params);
fun make_operator_call(func: string, params: vector<*ast_node>): *ast_node {
return ast_function_call_ptr(get_builtin_function(func, params.map(fun(p:*ast_node): *type return get_ast_type(p);)), params)
}
fun get_builtin_function(name: *char, param_types: vector<*type>): *ast_node
return get_builtin_function(string(name), param_types, null<tree<symbol>>())
fun get_builtin_function(name: string, param_types: vector<*type>): *ast_node
return get_builtin_function(name, param_types, null<tree<symbol>>())
fun get_builtin_function(name: string, param_types: vector<*type>, syntax: *tree<symbol>): *ast_node {
// none of the builtin functions should take in references
param_types = param_types.map(fun(t: *type): *type return t->clone_without_ref();)
if (name == "==" || name == "!=" || name == ">" || name == "<" || name == "<=" || name == ">" || name == ">=" || name == "&&" || name == "||" || name == "!")
return ast_function_ptr(name, type_ptr(param_types, type_ptr(base_type::boolean())), vector<*ast_node>(), false)
if (name == "." || name == "->") {
if (name == "->" && param_types[0]->indirection == 0)
error(syntax, string("drereferencing not a pointer: ") + name)
else if (name == "." && param_types[0]->indirection != 0)
error(syntax, string("dot operator on a pointer: ") + name)
else
return ast_function_ptr(name, type_ptr(param_types, param_types[1]), vector<*ast_node>(), false)
}
if (name == "[]") {
if (param_types[0]->indirection == 0)
error(syntax, string("drereferencing not a pointer: ") + name)
else
return ast_function_ptr(name, type_ptr(param_types, param_types[0]->clone_with_decreased_indirection()), vector<*ast_node>(), false)
}
if (name == "&" && param_types.size == 1)
return ast_function_ptr(name, type_ptr(param_types, param_types[0]->clone_with_increased_indirection()), vector<*ast_node>(), false)
if (name == "\*" && param_types.size == 1) {
if (param_types[0]->indirection == 0)
error(syntax, string("drereferencing not a pointer: ") + name)
else
return ast_function_ptr(name, type_ptr(param_types, param_types[0]->clone_with_decreased_indirection()), vector<*ast_node>(), false)
}
if (param_types.size > 1 && param_types[1]->rank() > param_types[0]->rank())
return ast_function_ptr(name, type_ptr(param_types, param_types[1]), vector<*ast_node>(), false)
return ast_function_ptr(name, type_ptr(param_types, param_types[0]), vector<*ast_node>(), false)
}
fun unify_type(template_type: *tree<symbol>, param_type: *type, new_map: *map<string, *type>, template_replacements: map<string, *type>) {
/*println(string("Unifying type: ") + concat_symbol_tree(template_type))*/
// first get rid of the reference if we have it - we don't care for unification
@@ -1247,163 +1180,3 @@ fun unify_type(template_type: *tree<symbol>, param_type: *type, new_map: *map<st
error(template_type, "TYPE INFERENCE NOT GOOD ENOUGH")
}
}
fun function_satisfies_params(node: *ast_node, param_types: vector<*type>): bool {
var func_type = get_ast_type(node)
var func_param_types = func_type->parameter_types
var param_string = string()
param_types.for_each(fun(t: *type) param_string += t->to_string() + ", ";)
if (!func_type->is_variadic && func_param_types.size != param_types.size) {
/*println(string("type sizes don't match ") + param_types.size + " with needed " + param_string)*/
return false
} else if (param_types.size < func_param_types.size) {
return false
}
// note we iterate over the func_param_types which will stop short if function is variadic
// just like we want
for (var j = 0; j < func_param_types.size; j++;) {
// don't care about references
if (!func_param_types[j]->equality(param_types[j], false)) {
/*println(string("types don't match ") + func_param_types[j]->to_string() + " with needed " + param_types[j]->to_string())*/
if (func_param_types[j]->to_string() == param_types[j]->to_string())
error(string("types aren't equal, but their string rep is (and ref doesn't even matter): ") + func_param_types[j]->to_string() + " vs " + param_types[j]->to_string() )
return false
}
}
return true
}
fun function_lookup(name: string, scope: *ast_node, param_types: vector<*type>): *ast_node {
/*println(string("doing function lookup for: ") + name)*/
var results = scope_lookup(name, scope)
/*print(results.size); println(" number of results")*/
for (var i = 0; i < results.size; i++;) {
if ((is_function(results[i]) || (is_identifier(results[i]) && get_ast_type(results[i])->is_function())) && function_satisfies_params(results[i], param_types)) {
return results[i]
}
}
/*println(string("function lookup failed for ") + name)*/
return null<ast_node>()
}
fun identifier_lookup(name: ref string, scope: *ast_node): *ast_node {
/*println(string("doing identifier lookup for: ") + name)*/
var results = scope_lookup(name, scope)
if (!results.size) {
/*println(string("identifier lookup failed for ") + name)*/
return null<ast_node>()
}
return results[0]
}
fun scope_lookup(name: ref string, scope: *ast_node): vector<*ast_node> {
// println("*****Doing a name lookup for*****")
// println(name)
var results = vector(scope)
name.split("::").for_each(fun(i: string) {
// println(string("based on split, looking up: ") + i)
var next_results = vector<*ast_node>()
results.for_each(fun(s: *ast_node) {
// print("looking in scope: ")
// println(s)
scope_lookup_helper(i, s, set<*ast_node>()).for_each(fun (result: *ast_node) {
if (!next_results.contains(result))
next_results.add(result)
})
})
results = next_results
})
return results
}
fun scope_lookup_helper(name: ref string, scope: *ast_node, visited: set<*ast_node>): vector<*ast_node> {
// need to do properly scopded lookups
// print("scope is: ")
// get_ast_scope(scope)->for_each(fun(key: string, value: vector<*ast_node>) print(key + " ");)
// println()
var results = vector<*ast_node>()
// prevent re-checking the same one...
if (visited.contains(scope))
return results
visited.add(scope)
if (get_ast_scope(scope)->contains_key(name)) {
// println(name + " is in scope, adding to results")
results += get_ast_scope(scope)->get(name)
}
if (get_ast_scope(scope)->contains_key(string("~enclosing_scope")))
results += scope_lookup_helper(name, get_ast_scope(scope)->get(string("~enclosing_scope"))[0], visited)
if (is_translation_unit(scope)) {
scope->translation_unit.children.for_each(fun(child: *ast_node) {
if (is_import(child)) {
if (child->import.imported.contains(name)) {
// println(name + " is indeed imported")
results += scope_lookup_helper(name, child->import.translation_unit, visited)
} else if (child->import.starred) {
// println("import has an import *, checking along it")
results += scope_lookup_helper(name, child->import.translation_unit, visited)
} else {
// println(name + " is not imported (this time)")
// print("import imports")
// child->import.imported.for_each(fun(it: string) print(it + " ");)
}
}
})
}
return results
}
fun concat_symbol_tree(node: *tree<symbol>): string {
var str.construct(): string
if (node->data.data != "no_value")
str += node->data.data
node->children.for_each(fun(child: *tree<symbol>) str += concat_symbol_tree(child);)
return str
}
fun get_node(lookup: *char, parent: *tree<symbol>): *tree<symbol> {
return get_node(string(lookup), parent)
}
fun get_node(lookup: string, parent: *tree<symbol>): *tree<symbol> {
var results = get_nodes(lookup, parent)
if (results.size > 1)
error(parent, "get node too many results!")
if (results.size)
return results[0]
return null<tree<symbol>>()
}
fun get_nodes(lookup: *char, parent: *tree<symbol>): vector<*tree<symbol>> {
return get_nodes(string(lookup), parent)
}
fun get_nodes(lookup: string, parent: *tree<symbol>): vector<*tree<symbol>> {
return parent->children.filter(fun(node: *tree<symbol>):bool return node->data.name == lookup;)
}
fun add_to_scope(name: *char, to_add: *ast_node, add_to: *ast_node) {
add_to_scope(string(name), to_add, add_to)
}
fun add_to_scope(name: string, to_add: *ast_node, add_to: *ast_node) {
var add_to_map = get_ast_scope(add_to)
if (add_to_map->contains_key(name))
(*add_to_map)[name].add(to_add)
else
add_to_map->set(name, vector(to_add))
}
fun get_first_terminal(source: *tree<symbol>): *tree<symbol> {
if (!source)
return null<tree<symbol>>()
if (source->data.terminal)
return source
if (source->children.size == 0)
return null<tree<symbol>>()
return get_first_terminal(source->children.first())
}
fun assert(works: bool, message: *char) {
if (!works)
error(message)
}
fun assert(works: bool, message: string) {
if (!works)
error(message)
}
fun error(source: *tree<symbol>, message: *char) error(source, string(message));
fun error(source: *tree<symbol>, message: string) {
source = get_first_terminal(source)
if (source)
error(source->data.source + ": " + source->data.position + " " + message)
error(message)
}

View File

@@ -8,7 +8,7 @@ import tree:*
import symbol:*
import ast_nodes:*
// for error with syntax tree
import ast_transformation:*
import pass_common:*
import poset:*
fun code_triple(): code_triple return code_triple(string(), string(), string());
@@ -72,27 +72,6 @@ obj code_triple (Object) {
return pre+value+post
}
}
fun is_dot_style_method_call(node: *ast_node): bool {
return is_function_call(node->function_call.func) &&
is_function(node->function_call.func->function_call.func) &&
(node->function_call.func->function_call.func->function.name == "->" || node->function_call.func->function_call.func->function.name == ".") &&
is_function(node->function_call.func->function_call.parameters[1]) &&
(is_type_def(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(string("~enclosing_scope"))[0]) ||
// or if it's a templated method (yes, this has gotten uuuuugly)
is_type_def(get_ast_scope(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(string("~enclosing_scope"))[0])->get(string("~enclosing_scope"))[0]) ||
// or it's in an adt
is_adt_def(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(string("~enclosing_scope"))[0]))
// should get uglier when we have to figure out if it's just an inside lambda
}
fun method_in_object(method: *ast_node, enclosing_object: *ast_node): bool {
var methods = enclosing_object->type_def.methods
for (var i = 0; i < methods.size; i++;) {
if (methods[i] == method || (is_template(methods[i]) && methods[i]->template.instantiated.contains(method))) {
return true
}
}
return false
}
obj c_generator (Object) {
var id_counter: int
var ast_to_syntax: map<*ast_node, *tree<symbol>>

View File

@@ -104,7 +104,9 @@ obj importer (Object) {
printlnerr("**Fourth Pass**")
name_ast_map.for_each(fun(name: string, tree_pair: pair<*tree<symbol>, *ast_node>) ast_pass.fourth_pass(tree_pair.first, tree_pair.second);)
}
fun trim(parse_tree: *tree<symbol>) {
}
fun trim(parse_tree: *tree<symbol>): *tree<symbol> {
remove_node(symbol("$NULL$", false), parse_tree)
remove_node(symbol("WS", false), parse_tree)
// the terminals have " around them, which we have to escape
@@ -145,8 +147,10 @@ obj importer (Object) {
collapse_node(symbol("template_param_list", false), parse_tree)
collapse_node(symbol("trait_list", false), parse_tree)
collapse_node(symbol("dec_type", false), parse_tree)
}
fun remove_node(remove: symbol, parse_tree: *tree<symbol>) {
return parse_tree
}
fun remove_node(remove: symbol, parse_tree: *tree<symbol>) {
var to_process = queue<*tree<symbol>>()
to_process.push(parse_tree)
while(!to_process.empty()) {
@@ -168,8 +172,8 @@ obj importer (Object) {
}
}
}
}
fun collapse_node(remove: symbol, parse_tree: *tree<symbol>) {
}
fun collapse_node(remove: symbol, parse_tree: *tree<symbol>) {
var to_process = queue<*tree<symbol>>()
to_process.push(parse_tree)
while(!to_process.empty()) {
@@ -187,6 +191,4 @@ obj importer (Object) {
}
}
}
}
}

View File

@@ -1,4 +1,3 @@
import io:*
import mem:*
import math:*
import map:*
@@ -9,12 +8,10 @@ import tree:*
import symbol:*
import ast_nodes:*
import type:*
import ast_transformation:*
import os:*
// for is_dot_style_method_call
import c_generator:*
import pass_common:*
// there is never an object literal/primitive
// they remain wrapped in a variable value
adt value {
boolean: bool,
character: char,
@@ -101,7 +98,6 @@ fun wrap_value(val: *ast_node): value {
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] == '.') {
@@ -208,9 +204,9 @@ fun do_basic_op(func_name: string, a: value, b: value): value {
} else if (func_name == "-") {
ptr = ((av.first) cast *char - inc_in_bytes) cast *void
} else {
println(string("pointer arithmatic is not + or -: ") + func_name + ", b is: ")
println(string("pointer arithmatic is not +, -, or ==: ") + func_name + ", b is: ")
print_value(b)
error(string("pointer arithmatic is not + or -: ") + func_name)
error(string("pointer arithmatic is not +, -, or ==: ") + func_name)
}
return value::pointer(make_pair(ptr, av.second))
}
@@ -336,7 +332,6 @@ fun get_real_value(v: value): value {
if (var_type->indirection)
return value::pointer(make_pair(*(var_ptr) cast **void, var_type))
match (var_type->base) {
// really this could just be make_pair(variable)
base_type::object() return value::object_like(make_pair(var_ptr, var_type))
base_type::boolean() return value::boolean(*(var_ptr) cast *bool)
base_type::character() return value::character(*(var_ptr) cast *char)
@@ -360,9 +355,6 @@ fun wrap_into_variable(v: value): value {
return value::variable(make_pair(v.object_like.first, v.object_like.second))
var variable_type = get_type_from_primitive_value(v)
var to_ret = value::variable(make_pair(malloc(type_size(variable_type)), variable_type))
/*if (is_function(v))*/
/*(to_ret.variable.first) cast *pair<*ast_node,map<*ast_node,value>> ->copy_construct(&v.function)*/
/*else*/
store_into_variable(to_ret, v)
return to_ret
}
@@ -408,9 +400,6 @@ fun cast_value(v: value, to_type: *type): value {
}
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)
@@ -510,71 +499,38 @@ fun offset_into_struct(struct_type: *type, ident: *ast_node): ulong {
size += type_size(struct_type->type_def->type_def.variables[i]->declaration_statement.identifier->identifier.type)
return size
}
// 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)
fun dereference_pointer_into_variable(dereference_val: value): value
return value::variable(make_pair(get_real_value(dereference_val).pointer.first, dereference_val.pointer.second->clone_with_decreased_indirection()))
fun pop_and_free(var_stack: *stack<map<*ast_node, value>>) {
var_stack->pop().for_each(fun(k: *ast_node, v: value) {
match(v) {
value::variable(backing) {
/*if (backing.second->is_function())*/
/*(backing.first) cast *pair<*ast_node,map<*ast_node,value>> ->destruct()*/
/*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>>
var globals: map<*ast_node, value>
var id_counter: int
fun get_id(): string return to_string(id_counter++);
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)
globals.construct()
id_counter = 0
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)
globals.copy_construct(&old->globals)
id_counter == old->id_counter
}
fun destruct() {
name_ast_map.destruct()
ast_to_syntax.destruct()
globals.destruct()
}
fun call_main() {
fun call_main(name_ast_map: ref map<string, pair<*tree<symbol>,*ast_node>>) {
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)
printlnerr("=============")
printlnerr("setting up globals!")
printlnerr("=============")
setup_globals();
printlnerr("=============")
printlnerr("calling main!")
printlnerr("=============")
var globals = setup_globals(name_ast_map)
var var_stack = stack<map<*ast_node, value>>()
var_stack.push(map<*ast_node,value>())
var result = call_function(results[0], vector<value>(), vector<*ast_node>(), &var_stack, map<*ast_node,value>(), value::void_nothing(), value::void_nothing(), null<ast_node>())
printlnerr("=============")
printlnerr("Done!")
printlnerr("=============")
var result = call_function(results[0], vector<value>(), vector<*ast_node>(), &var_stack, map<*ast_node,value>(), value::void_nothing(), value::void_nothing(), null<ast_node>(), &globals)
pop_and_free(&var_stack)
}
fun setup_globals() {
}
fun evaluate_constant_expression(node: *ast_node): value {
return interpret(node, null<stack<map<*ast_node, value>>>(), value::void_nothing(), null<ast_node>(), null<map<*ast_node, value>>()).first
}
fun setup_globals(name_ast_map: ref map<string, pair<*tree<symbol>,*ast_node>>): map<*ast_node, value> {
var globals = map<*ast_node, value>()
name_ast_map.for_each(fun(key: string, value: pair<*tree<symbol>,*ast_node>) {
value.second->translation_unit.children.for_each(fun(child: *ast_node) {
if (is_declaration_statement(child)) {
@@ -586,19 +542,25 @@ obj interpreter (Object) {
var stderr_pointer = malloc(type_size(stderr_type))
*(stderr_pointer) cast **void = stderr;
globals[declaration.identifier] = value::variable(make_pair(stderr_pointer, stderr_type))
} else if (identifier.name == "stdin") {
var stdin_type = type_ptr(base_type::void_return(), 1)
var stdin_pointer = malloc(type_size(stdin_type))
*(stdin_pointer) cast **void = stdin;
globals[declaration.identifier] = value::variable(make_pair(stdin_pointer, stdin_type))
} else {
error(string("unknown extern: ") + identifier.name)
}
} else {
globals[declaration.identifier] = value::variable(make_pair(calloc(type_size(identifier.type)), identifier.type))
if (declaration.expression)
store_into_variable(globals[declaration.identifier], get_real_value(interpret(declaration.expression, null<stack<map<*ast_node,value>>>(), value::void_nothing(), null<ast_node>()).first))
store_into_variable(globals[declaration.identifier], get_real_value(interpret(declaration.expression, null<stack<map<*ast_node,value>>>(), value::void_nothing(), null<ast_node>(), null<map<*ast_node,value>>()).first))
}
}
})
})
}
fun interpret_function_call(func_call: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
return globals
}
fun interpret_function_call(func_call: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): 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()
@@ -606,9 +568,7 @@ obj interpreter (Object) {
var possible_closure_map = map<*ast_node,value>()
// test for function value
if (!dot_style_method_call && (!is_function(func_call_func) || func_call_func->function.closed_variables.size())) {
/*error("func_call_func is not a function")*/
/*println(string("func_call_func is not a function: ") + get_ast_name(func_call_func))*/
var func_value = get_real_value(interpret(func_call_func, var_stack, enclosing_object, enclosing_func).first)
var func_value = get_real_value(interpret(func_call_func, var_stack, enclosing_object, enclosing_func, globals).first)
func_call_func = func_value.function.first
possible_closure_map = *func_value.function.second
// if the closure closes over this, put it as the enclosing object inside the closure
@@ -617,15 +577,10 @@ obj interpreter (Object) {
new_enclosing_object = get_real_value(dereference_pointer_into_variable(v))
}
})
/*println("possible_closure_map is")*/
/*possible_closure_map.for_each(fun(key: *ast_node, v: value) print(get_ast_name(key) + " ");)*/
/*println()*/
/*println("end pcm")*/
/*println(string("calling func we got from interpreting: ") + get_ast_name(func_call_func))*/
}
// note here also that this is likely not a foolproof method
if (dot_style_method_call) {
new_enclosing_object = get_real_value(interpret(func_call_func->function_call.parameters[0], var_stack, enclosing_object, enclosing_func).first)
new_enclosing_object = get_real_value(interpret(func_call_func->function_call.parameters[0], var_stack, enclosing_object, enclosing_func, globals).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())))
@@ -642,7 +597,7 @@ obj interpreter (Object) {
if (func_name == "&&" || func_name == "||") {
error("short circuit still in interpreter")
} else if (func_name == "." || func_name == "->") {
var left_side = get_real_value(interpret(func_call_parameters[0], var_stack, enclosing_object, enclosing_func).first)
var left_side = get_real_value(interpret(func_call_parameters[0], var_stack, enclosing_object, enclosing_func, globals).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
@@ -656,7 +611,7 @@ obj interpreter (Object) {
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() && get_ast_type(p)->indirection == 0;)) {
parameters = func_call_parameters.map(fun(p: *ast_node): value return interpret(p, var_stack, enclosing_object, enclosing_func).first;)
parameters = func_call_parameters.map(fun(p: *ast_node): value return interpret(p, var_stack, enclosing_object, enclosing_func, globals).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 == "^"
@@ -688,8 +643,6 @@ obj interpreter (Object) {
error("Trying to take address of not a variable or object_like")
}
}
// 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 == "[]")
@@ -707,12 +660,12 @@ obj interpreter (Object) {
// 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, possible_closure_map, enclosing_object, new_enclosing_object, enclosing_func), 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<*ast_node, value>>, possible_closure_map: ref map<*ast_node, value>, enclosing_object: value, new_enclosing_object: value, enclosing_func: *ast_node): value {
return make_pair(call_function(func_call_func, parameters, parameter_sources, var_stack, possible_closure_map, enclosing_object, new_enclosing_object, enclosing_func, globals), 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<*ast_node, value>>, possible_closure_map: ref map<*ast_node, value>, enclosing_object: value, new_enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): value {
// will need adjustment
if (!is_function(func))
error("Can't handle not function function calls (can do regular method, is this chained or something?)")
@@ -721,13 +674,6 @@ obj interpreter (Object) {
// start out with the possible closure map as the highest scope (gloabals checked seperately)
var new_var_stack = stack(possible_closure_map)
new_var_stack.push(map<*ast_node,value>())
/*println("stack after pcm and new m is")*/
/*for (var i = 0; i < new_var_stack.size(); i++;) {*/
/*println(string("level: ") + i)*/
/*new_var_stack.from_top(i).for_each(fun(key: *ast_node, v: value) print(get_ast_name(key) + " ");)*/
/*println()*/
/*}*/
/*println("end stack after")*/
// if this is a value based call, pull from parameters
if (parameter_sources.size == 0) {
/*println(func_name + " being called with parameter values")*/
@@ -743,9 +689,6 @@ obj interpreter (Object) {
new_var_stack.top()[param_ident] = wrap_into_variable(parameters[i])
} else {
new_var_stack.top()[param_ident] = value::variable(make_pair(malloc(type_size(param_type)), param_type))
//HERE
/*if (param_type->indirection == 0 && param_type->is_function())*/
/*(new_var_stack.top()[param_ident].variable.first) cast *pair<*ast_node,map<*ast_node,value>> ->construct()*/
store_into_variable(new_var_stack.top()[param_ident], get_real_value(parameters[i]))
}
}
@@ -760,18 +703,18 @@ obj interpreter (Object) {
var param_type = get_ast_type(func)->parameter_types[i]
var param_ident = func->function.parameters[i]
if (param_type->is_ref) {
var param = interpret(parameter_sources[i], var_stack, enclosing_object, enclosing_func).first
var param = interpret(parameter_sources[i], var_stack, enclosing_object, enclosing_func, globals).first
if (is_variable(param))
new_var_stack.top()[param_ident] = param
else
new_var_stack.top()[param_ident] = wrap_into_variable(param)
} else {
new_var_stack.top()[param_ident] = value::variable(make_pair(malloc(type_size(param_type)), param_type))
store_into_variable(new_var_stack.top()[param_ident], get_real_value(interpret(parameter_sources[i], var_stack, enclosing_object, enclosing_func).first))
store_into_variable(new_var_stack.top()[param_ident], get_real_value(interpret(parameter_sources[i], var_stack, enclosing_object, enclosing_func, globals).first))
}
}
}
var to_ret = interpret(func->function.body_statement, &new_var_stack, new_enclosing_object, func).first
var to_ret = interpret(func->function.body_statement, &new_var_stack, new_enclosing_object, func, globals).first
// to_ret is on the new_var_stack, likely
/*pop_and_free(&new_var_stack)*/
if (parameter_sources.size) {
@@ -779,8 +722,8 @@ obj interpreter (Object) {
pop_and_free(var_stack)
}
return to_ret
}
fun call_built_in_extern(func_name: string, parameters: vector<value>): value {
}
fun call_built_in_extern(func_name: string, parameters: vector<value>): value {
for (var i = 0; i < parameters.size; i++;)
parameters[i] = get_real_value(parameters[i])
if (func_name == "printf") {
@@ -848,40 +791,34 @@ obj interpreter (Object) {
error(string("trying to call invalid func: ") + func_name)
}
return value::void_nothing()
}
fun interpret_function(function: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
}
fun interpret_function(function: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
var possible_closure_map = new<map<*ast_node,value>>()->construct()
/*println("trying to close")*/
function->function.closed_variables.for_each(fun(v: *ast_node) {
(*possible_closure_map)[v] = interpret_identifier(v, var_stack, enclosing_object, enclosing_func).first
/*println(string("closed over ") + get_ast_name(v))*/
(*possible_closure_map)[v] = interpret_identifier(v, var_stack, enclosing_object, enclosing_func, globals).first
})
/*println("in interpret function possible_closure_map is")*/
/*possible_closure_map->for_each(fun(key: *ast_node, v: value) print(get_ast_name(key) + " ");)*/
/*println()*/
/*println("end in inteprret function pcm")*/
return make_pair(value::function(make_pair(function, possible_closure_map)), control_flow::nor())
}
fun interpret_statement(stmt: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
return interpret(stmt->statement.child, var_stack, enclosing_object, enclosing_func)
}
fun interpret_if_statement(if_stmt: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
}
fun interpret_statement(stmt: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
return interpret(stmt->statement.child, var_stack, enclosing_object, enclosing_func, globals)
}
fun interpret_if_statement(if_stmt: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
var_stack->push(map<*ast_node,value>())
var value_from_inside = make_pair(value::void_nothing(), control_flow::nor())
if (truthy(interpret(if_stmt->if_statement.condition, var_stack, enclosing_object, enclosing_func).first)) {
value_from_inside = interpret(if_stmt->if_statement.then_part, var_stack, enclosing_object, enclosing_func)
if (truthy(interpret(if_stmt->if_statement.condition, var_stack, enclosing_object, enclosing_func, globals).first)) {
value_from_inside = interpret(if_stmt->if_statement.then_part, var_stack, enclosing_object, enclosing_func, globals)
} else if (if_stmt->if_statement.else_part) {
value_from_inside = interpret(if_stmt->if_statement.else_part, var_stack, enclosing_object, enclosing_func)
value_from_inside = interpret(if_stmt->if_statement.else_part, var_stack, enclosing_object, enclosing_func, globals)
}
pop_and_free(var_stack)
return value_from_inside
}
fun interpret_while_loop(while_loop: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
}
fun interpret_while_loop(while_loop: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
var_stack->push(map<*ast_node,value>())
var value_from_inside = make_pair(value::void_nothing(), control_flow::nor())
var going = true
while (going && truthy(interpret(while_loop->while_loop.condition, var_stack, enclosing_object, enclosing_func).first)) {
value_from_inside = interpret(while_loop->while_loop.statement, var_stack, enclosing_object, enclosing_func)
while (going && truthy(interpret(while_loop->while_loop.condition, var_stack, enclosing_object, enclosing_func, globals).first)) {
value_from_inside = interpret(while_loop->while_loop.statement, var_stack, enclosing_object, enclosing_func, globals)
if (value_from_inside.second == control_flow::ret() || value_from_inside.second == control_flow::bre())
going = false
if (value_from_inside.second == control_flow::bre() || value_from_inside.second == control_flow::con())
@@ -889,15 +826,15 @@ obj interpreter (Object) {
}
pop_and_free(var_stack)
return value_from_inside
}
fun interpret_for_loop(for_loop: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
}
fun interpret_for_loop(for_loop: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
var_stack->push(map<*ast_node,value>())
var value_from_inside = make_pair(value::void_nothing(), control_flow::nor())
var going = true
if (for_loop->for_loop.init)
interpret(for_loop->for_loop.init, var_stack, enclosing_object, enclosing_func)
while (going && (!for_loop->for_loop.condition || truthy(interpret(for_loop->for_loop.condition, var_stack, enclosing_object, enclosing_func).first))) {
value_from_inside = interpret(for_loop->for_loop.body, var_stack, enclosing_object, enclosing_func)
interpret(for_loop->for_loop.init, var_stack, enclosing_object, enclosing_func, globals)
while (going && (!for_loop->for_loop.condition || truthy(interpret(for_loop->for_loop.condition, var_stack, enclosing_object, enclosing_func, globals).first))) {
value_from_inside = interpret(for_loop->for_loop.body, var_stack, enclosing_object, enclosing_func, globals)
if (value_from_inside.second == control_flow::ret() || value_from_inside.second == control_flow::bre())
going = false
if (value_from_inside.second == control_flow::bre() || value_from_inside.second == control_flow::con())
@@ -905,22 +842,22 @@ obj interpreter (Object) {
// only run update if we're not breaking or continuing
if (going && for_loop->for_loop.update)
interpret(for_loop->for_loop.update, var_stack, enclosing_object, enclosing_func)
interpret(for_loop->for_loop.update, var_stack, enclosing_object, enclosing_func, globals)
}
pop_and_free(var_stack)
return value_from_inside
}
fun interpret_branching_statement(bstatement: *ast_node): pair<value, control_flow> {
}
fun interpret_branching_statement(bstatement: *ast_node): pair<value, control_flow> {
match (bstatement->branching_statement.b_type) {
branching_type::break_stmt() return make_pair(value::void_nothing(), control_flow::bre())
branching_type::continue_stmt() return make_pair(value::void_nothing(), control_flow::con())
}
error("bad branch type")
}
fun interpret_code_block(block: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
}
fun interpret_code_block(block: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
var_stack->push(map<*ast_node,value>())
for (var i = 0; i < block->code_block.children.size; i++;) {
var statement = interpret(block->code_block.children[i], var_stack, enclosing_object, enclosing_func)
var statement = interpret(block->code_block.children[i], var_stack, enclosing_object, enclosing_func, globals)
match (statement.second) {
control_flow::con() {
pop_and_free(var_stack)
@@ -939,40 +876,40 @@ obj interpreter (Object) {
}
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<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
}
fun interpret_return_statement(stmt: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
if (stmt->return_statement.return_value == null<ast_node>())
return make_pair(value::void_nothing(), control_flow::ret())
var return_expression = stmt->return_statement.return_value
var return_type = get_ast_type(return_expression)
var to_ret.construct(): value
if (get_ast_type(enclosing_func)->return_type->is_ref) {
to_ret = interpret(return_expression, var_stack, enclosing_object, enclosing_func).first
to_ret = interpret(return_expression, var_stack, enclosing_object, enclosing_func, globals).first
if (!is_variable(to_ret)) {
print("here is: ")
print_value(to_ret)
error("interpreter returning reference is not variable")
}
} else {
to_ret = interpret(return_expression, var_stack, enclosing_object, enclosing_func).first
to_ret = interpret(return_expression, var_stack, enclosing_object, enclosing_func, globals).first
}
return make_pair(to_ret, control_flow::ret())
}
fun interpret_declaration_statement(stmt: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
}
fun interpret_declaration_statement(stmt: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
var ident = stmt->declaration_statement.identifier
var ident_type = ident->identifier.type
var_stack->top()[ident] = value::variable(make_pair(malloc(type_size(ident_type)),ident_type))
// NOTE: store_into_variable takes to in as a ref because it might change it in the special case ref = ptr
if (stmt->declaration_statement.expression) {
store_into_variable(var_stack->top()[ident], get_real_value(interpret(stmt->declaration_statement.expression, var_stack, enclosing_object, enclosing_func).first))
store_into_variable(var_stack->top()[ident], get_real_value(interpret(stmt->declaration_statement.expression, var_stack, enclosing_object, enclosing_func, globals).first))
} else if (stmt->declaration_statement.init_method_call) {
interpret(stmt->declaration_statement.init_method_call, var_stack, enclosing_object, enclosing_func)
interpret(stmt->declaration_statement.init_method_call, var_stack, enclosing_object, enclosing_func, globals)
}
return make_pair(value::void_nothing(), control_flow::nor())
}
fun interpret_assignment_statement(stmt: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
var to = interpret(stmt->assignment_statement.to, var_stack, enclosing_object, enclosing_func).first
var from = interpret(stmt->assignment_statement.from, var_stack, enclosing_object, enclosing_func).first
}
fun interpret_assignment_statement(stmt: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
var to = interpret(stmt->assignment_statement.to, var_stack, enclosing_object, enclosing_func, globals).first
var from = interpret(stmt->assignment_statement.from, var_stack, enclosing_object, enclosing_func, globals).first
assert(is_variable(to), "assigning into not a variable")
// always do cast now to make our best effort at assignment (assign into a double from a float, etc)
// unless it's an object
@@ -983,8 +920,8 @@ obj interpreter (Object) {
else
store_into_variable(to, cast_value(from_real, to.variable.second))
return make_pair(value::void_nothing(), control_flow::nor())
}
fun interpret_identifier(ident: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
}
fun interpret_identifier(ident: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
for (var i = 0; i < var_stack->size(); i++;)
if (var_stack->from_top(i).contains_key(ident))
return make_pair(var_stack->from_top(i)[ident], control_flow::nor())
@@ -1001,8 +938,8 @@ obj interpreter (Object) {
}
}
// check for global
if (globals.contains_key(ident))
return make_pair(globals[ident], control_flow::nor())
if (globals->contains_key(ident))
return make_pair((*globals)[ident], control_flow::nor())
println("couldn't find it in interpret identifier, scope:")
for (var i = 0; i < var_stack->size(); i++;) {
println(string("level: ") + i)
@@ -1020,38 +957,37 @@ obj interpreter (Object) {
print_value(enclosing_object)
}
error(string("Cannot find variable: ") + ident->identifier.name)
}
fun interpret_cast(node: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
return make_pair(cast_value(interpret(node->cast.value, var_stack, enclosing_object, enclosing_func).first, node->cast.to_type), control_flow::nor())
}
fun interpret_compiler_intrinsic(node: *ast_node, var_stack: *stack<map<*ast_node, value>>): pair<value, control_flow> {
}
fun interpret_cast(node: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
return make_pair(cast_value(interpret(node->cast.value, var_stack, enclosing_object, enclosing_func, globals).first, node->cast.to_type), control_flow::nor())
}
fun interpret_compiler_intrinsic(node: *ast_node, var_stack: *stack<map<*ast_node, 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>
}
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<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node): pair<value, control_flow> {
fun interpret(node: *ast_node, var_stack: *stack<map<*ast_node, value>>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair<value, control_flow> {
if (!node) error("cannot interpret null node!")
match (*node) {
ast_node::function_call(backing) return interpret_function_call(node, var_stack, enclosing_object, enclosing_func)
ast_node::function(backing) return interpret_function(node, var_stack, enclosing_object, enclosing_func)
ast_node::statement(backing) return interpret_statement(node, var_stack, enclosing_object, enclosing_func)
ast_node::if_statement(backing) return interpret_if_statement(node, var_stack, enclosing_object, enclosing_func)
ast_node::while_loop(backing) return interpret_while_loop(node, var_stack, enclosing_object, enclosing_func)
ast_node::for_loop(backing) return interpret_for_loop(node, var_stack, enclosing_object, enclosing_func)
ast_node::function_call(backing) return interpret_function_call(node, var_stack, enclosing_object, enclosing_func, globals)
ast_node::function(backing) return interpret_function(node, var_stack, enclosing_object, enclosing_func, globals)
ast_node::statement(backing) return interpret_statement(node, var_stack, enclosing_object, enclosing_func, globals)
ast_node::if_statement(backing) return interpret_if_statement(node, var_stack, enclosing_object, enclosing_func, globals)
ast_node::while_loop(backing) return interpret_while_loop(node, var_stack, enclosing_object, enclosing_func, globals)
ast_node::for_loop(backing) return interpret_for_loop(node, var_stack, enclosing_object, enclosing_func, globals)
ast_node::branching_statement(backing) return interpret_branching_statement(node)
ast_node::code_block(backing) return interpret_code_block(node, var_stack, enclosing_object, enclosing_func)
ast_node::return_statement(backing) return interpret_return_statement(node, var_stack, enclosing_object, enclosing_func)
ast_node::declaration_statement(backing) return interpret_declaration_statement(node, var_stack, enclosing_object, enclosing_func)
ast_node::assignment_statement(backing) return interpret_assignment_statement(node, var_stack, enclosing_object, enclosing_func)
ast_node::identifier(backing) return interpret_identifier(node, var_stack, enclosing_object, enclosing_func)
ast_node::cast(backing) return interpret_cast(node, var_stack, enclosing_object, enclosing_func)
ast_node::code_block(backing) return interpret_code_block(node, var_stack, enclosing_object, enclosing_func, globals)
ast_node::return_statement(backing) return interpret_return_statement(node, var_stack, enclosing_object, enclosing_func, globals)
ast_node::declaration_statement(backing) return interpret_declaration_statement(node, var_stack, enclosing_object, enclosing_func, globals)
ast_node::assignment_statement(backing) return interpret_assignment_statement(node, var_stack, enclosing_object, enclosing_func, globals)
ast_node::identifier(backing) return interpret_identifier(node, var_stack, enclosing_object, enclosing_func, globals)
ast_node::cast(backing) return interpret_cast(node, var_stack, enclosing_object, enclosing_func, globals)
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))
}
}

View File

@@ -7,7 +7,21 @@ ext fun fprintf(file: *void, format: *char, ...): int
ext fun snprintf(to_str: *char, num: ulong, format: *char, ...): int
ext fun fflush(file: int): int
ext var stderr: *void
ext fun fgets(buff: *char, size: int, file: *void): *char
ext var stdin: *void
// dead simple stdin
fun get_line(prompt: string::string, line_size: int): string::string {
print(prompt)
return get_line(line_size)
}
fun get_line(line_size: int): string::string {
var buff = new<char>(line_size)
fgets(buff, line_size, stdin)
var to_ret = string::string(buff)
delete(buff)
return to_ret.slice(0,-2) // remove '\n'
}
fun printlnerr<T>(toPrint: T) : void {
printerr(toPrint)
printerr("\n")

View File

@@ -1,5 +1,4 @@
import ast_nodes:*
import ast_transformation:*
import mem:*
import util:*
import vector:*
@@ -9,6 +8,200 @@ import string:*
fun make_this_noncached(object: *ast_node): *ast_node {
return ast_identifier_ptr("this", object->type_def.self_type->clone_with_indirection(1), object)
}
fun get_first_terminal(source: *tree<symbol>): *tree<symbol> {
if (!source)
return null<tree<symbol>>()
if (source->data.terminal)
return source
if (source->children.size == 0)
return null<tree<symbol>>()
return get_first_terminal(source->children.first())
}
fun error(source: *tree<symbol>, message: *char) error(source, string(message));
fun error(source: *tree<symbol>, message: string) {
source = get_first_terminal(source)
if (source)
error(source->data.source + ": " + source->data.position + " " + message)
error(message)
}
fun method_in_object(method: *ast_node, enclosing_object: *ast_node): bool {
var methods = enclosing_object->type_def.methods
for (var i = 0; i < methods.size; i++;) {
if (methods[i] == method || (is_template(methods[i]) && methods[i]->template.instantiated.contains(method))) {
return true
}
}
return false
}
fun is_dot_style_method_call(node: *ast_node): bool {
return is_function_call(node->function_call.func) &&
is_function(node->function_call.func->function_call.func) &&
(node->function_call.func->function_call.func->function.name == "->" || node->function_call.func->function_call.func->function.name == ".") &&
is_function(node->function_call.func->function_call.parameters[1]) &&
(is_type_def(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(string("~enclosing_scope"))[0]) ||
// or if it's a templated method (yes, this has gotten uuuuugly)
is_type_def(get_ast_scope(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(string("~enclosing_scope"))[0])->get(string("~enclosing_scope"))[0]) ||
// or it's in an adt
is_adt_def(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(string("~enclosing_scope"))[0]))
// should get uglier when we have to figure out if it's just an inside lambda
}
fun function_satisfies_params(node: *ast_node, param_types: vector<*type>): bool {
var func_type = get_ast_type(node)
var func_param_types = func_type->parameter_types
var param_string = string()
param_types.for_each(fun(t: *type) param_string += t->to_string() + ", ";)
if (!func_type->is_variadic && func_param_types.size != param_types.size) {
/*println(string("type sizes don't match ") + param_types.size + " with needed " + param_string)*/
return false
} else if (param_types.size < func_param_types.size) {
return false
}
// note we iterate over the func_param_types which will stop short if function is variadic
// just like we want
for (var j = 0; j < func_param_types.size; j++;) {
// don't care about references
if (!func_param_types[j]->equality(param_types[j], false)) {
/*println(string("types don't match ") + func_param_types[j]->to_string() + " with needed " + param_types[j]->to_string())*/
if (func_param_types[j]->to_string() == param_types[j]->to_string())
error(string("types aren't equal, but their string rep is (and ref doesn't even matter): ") + func_param_types[j]->to_string() + " vs " + param_types[j]->to_string() )
return false
}
}
return true
}
fun function_lookup(name: string, scope: *ast_node, param_types: vector<*type>): *ast_node {
var results = scope_lookup(name, scope)
for (var i = 0; i < results.size; i++;) {
if ((is_function(results[i]) || (is_identifier(results[i]) && get_ast_type(results[i])->is_function())) && function_satisfies_params(results[i], param_types)) {
return results[i]
}
}
return null<ast_node>()
}
fun identifier_lookup(name: ref string, scope: *ast_node): *ast_node {
/*println(string("doing identifier lookup for: ") + name)*/
var results = scope_lookup(name, scope)
if (!results.size) {
/*println(string("identifier lookup failed for ") + name)*/
return null<ast_node>()
}
return results[0]
}
fun scope_lookup(name: ref string, scope: *ast_node): vector<*ast_node> {
// println("*****Doing a name lookup for*****")
// println(name)
var results = vector(scope)
name.split("::").for_each(fun(i: string) {
// println(string("based on split, looking up: ") + i)
var next_results = vector<*ast_node>()
results.for_each(fun(s: *ast_node) {
// print("looking in scope: ")
// println(s)
scope_lookup_helper(i, s, set<*ast_node>()).for_each(fun (result: *ast_node) {
if (!next_results.contains(result))
next_results.add(result)
})
})
results = next_results
})
return results
}
fun scope_lookup_helper(name: ref string, scope: *ast_node, visited: set<*ast_node>): vector<*ast_node> {
// need to do properly scopded lookups
// print("scope is: ")
// get_ast_scope(scope)->for_each(fun(key: string, value: vector<*ast_node>) print(key + " ");)
// println()
var results = vector<*ast_node>()
// prevent re-checking the same one...
if (visited.contains(scope))
return results
visited.add(scope)
if (get_ast_scope(scope)->contains_key(name)) {
// println(name + " is in scope, adding to results")
results += get_ast_scope(scope)->get(name)
}
if (get_ast_scope(scope)->contains_key(string("~enclosing_scope")))
results += scope_lookup_helper(name, get_ast_scope(scope)->get(string("~enclosing_scope"))[0], visited)
if (is_translation_unit(scope)) {
scope->translation_unit.children.for_each(fun(child: *ast_node) {
if (is_import(child)) {
if (child->import.imported.contains(name)) {
// println(name + " is indeed imported")
results += scope_lookup_helper(name, child->import.translation_unit, visited)
} else if (child->import.starred) {
// println("import has an import *, checking along it")
results += scope_lookup_helper(name, child->import.translation_unit, visited)
} else {
// println(name + " is not imported (this time)")
// print("import imports")
// child->import.imported.for_each(fun(it: string) print(it + " ");)
}
}
})
}
return results
}
fun has_method(object: *ast_node, name: *char, parameter_types: vector<*type>): bool return has_method(object, string(name), parameter_types);
fun has_method(object: *ast_node, name: string, parameter_types: vector<*type>): bool {
var to_ret = function_lookup(name, object, parameter_types) || false
return to_ret
}
fun get_from_scope(node: *ast_node, member: *char): *ast_node
return get_from_scope(node, string(member))
fun get_from_scope(node: *ast_node, member: string): *ast_node
return get_ast_scope(node)->get(member).first()
fun make_method_call(object_ident: *ast_node, name: *char, parameters: vector<*ast_node>): *ast_node return make_method_call(object_ident, string(name), parameters);
fun make_method_call(object_ident: *ast_node, name: string, parameters: vector<*ast_node>): *ast_node {
// note that this type_def is the adt_def if this is an adt type
var method = function_lookup(name, get_ast_type(object_ident)->type_def, parameters.map(fun(param: *ast_node): *type return get_ast_type(param);))
return make_method_call(object_ident, method, parameters)
}
fun make_method_call(object_ident: *ast_node, method: *ast_node, parameters: vector<*ast_node>): *ast_node {
var access_op = "."
if (get_ast_type(object_ident)->indirection)
access_op = "->"
var method_access = ast_function_call_ptr(get_builtin_function(string(access_op), vector(get_ast_type(object_ident), get_ast_type(method))), vector(object_ident, method))
return ast_function_call_ptr(method_access, parameters)
}
fun make_operator_call(func: *char, params: vector<*ast_node>): *ast_node return make_operator_call(string(func), params);
fun make_operator_call(func: string, params: vector<*ast_node>): *ast_node {
return ast_function_call_ptr(get_builtin_function(func, params.map(fun(p:*ast_node): *type return get_ast_type(p);)), params)
}
fun get_builtin_function(name: *char, param_types: vector<*type>): *ast_node
return get_builtin_function(string(name), param_types, null<tree<symbol>>())
fun get_builtin_function(name: string, param_types: vector<*type>): *ast_node
return get_builtin_function(name, param_types, null<tree<symbol>>())
fun get_builtin_function(name: string, param_types: vector<*type>, syntax: *tree<symbol>): *ast_node {
// none of the builtin functions should take in references
param_types = param_types.map(fun(t: *type): *type return t->clone_without_ref();)
if (name == "==" || name == "!=" || name == ">" || name == "<" || name == "<=" || name == ">" || name == ">=" || name == "&&" || name == "||" || name == "!")
return ast_function_ptr(name, type_ptr(param_types, type_ptr(base_type::boolean())), vector<*ast_node>(), false)
if (name == "." || name == "->") {
if (name == "->" && param_types[0]->indirection == 0)
error(syntax, string("drereferencing not a pointer: ") + name)
else if (name == "." && param_types[0]->indirection != 0)
error(syntax, string("dot operator on a pointer: ") + name)
else
return ast_function_ptr(name, type_ptr(param_types, param_types[1]), vector<*ast_node>(), false)
}
if (name == "[]") {
if (param_types[0]->indirection == 0)
error(syntax, string("drereferencing not a pointer: ") + name)
else
return ast_function_ptr(name, type_ptr(param_types, param_types[0]->clone_with_decreased_indirection()), vector<*ast_node>(), false)
}
if (name == "&" && param_types.size == 1)
return ast_function_ptr(name, type_ptr(param_types, param_types[0]->clone_with_increased_indirection()), vector<*ast_node>(), false)
if (name == "\*" && param_types.size == 1) {
if (param_types[0]->indirection == 0)
error(syntax, string("drereferencing not a pointer: ") + name)
else
return ast_function_ptr(name, type_ptr(param_types, param_types[0]->clone_with_decreased_indirection()), vector<*ast_node>(), false)
}
if (param_types.size > 1 && param_types[1]->rank() > param_types[0]->rank())
return ast_function_ptr(name, type_ptr(param_types, param_types[1]), vector<*ast_node>(), false)
return ast_function_ptr(name, type_ptr(param_types, param_types[0]), vector<*ast_node>(), false)
}
fun possible_object_equality(lvalue: *ast_node, rvalue: *ast_node): *ast_node {
var ltype = get_ast_type(lvalue)
var rtype = get_ast_type(rvalue)
@@ -19,7 +212,40 @@ fun possible_object_equality(lvalue: *ast_node, rvalue: *ast_node): *ast_node {
return ast_value_ptr(string("false"), type_ptr(base_type::boolean()))
return make_operator_call("==", vector(lvalue, rvalue))
}
fun concat_symbol_tree(node: *tree<symbol>): string {
var str.construct(): string
if (node->data.data != "no_value")
str += node->data.data
node->children.for_each(fun(child: *tree<symbol>) str += concat_symbol_tree(child);)
return str
}
fun get_node(lookup: *char, parent: *tree<symbol>): *tree<symbol> {
return get_node(string(lookup), parent)
}
fun get_node(lookup: string, parent: *tree<symbol>): *tree<symbol> {
var results = get_nodes(lookup, parent)
if (results.size > 1)
error(parent, "get node too many results!")
if (results.size)
return results[0]
return null<tree<symbol>>()
}
fun get_nodes(lookup: *char, parent: *tree<symbol>): vector<*tree<symbol>> {
return get_nodes(string(lookup), parent)
}
fun get_nodes(lookup: string, parent: *tree<symbol>): vector<*tree<symbol>> {
return parent->children.filter(fun(node: *tree<symbol>):bool return node->data.name == lookup;)
}
fun add_to_scope(name: *char, to_add: *ast_node, add_to: *ast_node) {
add_to_scope(string(name), to_add, add_to)
}
fun add_to_scope(name: string, to_add: *ast_node, add_to: *ast_node) {
var add_to_map = get_ast_scope(add_to)
if (add_to_map->contains_key(name))
(*add_to_map)[name].add(to_add)
else
add_to_map->set(name, vector(to_add))
}
// for now, needs source to already be in a variable for copy_constructing
fun assign_or_copy_construct_statement(lvalue: *ast_node, rvalue: *ast_node): *ast_node {
var ltype = get_ast_type(lvalue)

View File

@@ -20,6 +20,14 @@ fun error(message: string::string) {
io::printlnerr(message)
os::exit(-1)
}
fun assert(works: bool, message: *char) {
if (!works)
error(message)
}
fun assert(works: bool, message: string::string) {
if (!works)
error(message)
}
fun deref_equality<T>(a: *T, b: *T): bool {
if ( (a && b && !(*a == *b)) || (a && !b) || (!a && b) )