Refactored interpreter into just functions, added a REPL to the main kraken.
This commit is contained in:
56
kraken.krak
56
kraken.krak
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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>>
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) )
|
||||
|
||||
Reference in New Issue
Block a user