Refactored interpreter into just functions, added a REPL to the main kraken.
This commit is contained in:
78
kraken.krak
78
kraken.krak
@@ -16,33 +16,7 @@ import c_line_control:*
|
|||||||
import c_generator:*
|
import c_generator:*
|
||||||
import compiler_version
|
import compiler_version
|
||||||
|
|
||||||
|
|
||||||
fun main(argc: int, argv: **char):int {
|
fun main(argc: int, argv: **char):int {
|
||||||
if (argc <= 1) {
|
|
||||||
error("No input file!\n Call with one argument (the input file), or two arguments (input file and output name)")
|
|
||||||
} 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 (argv1_str == "-i") {
|
|
||||||
interpret_instead = true
|
|
||||||
input_file_offset++
|
|
||||||
} else if (argv1_str.length() > 2 && argv1_str.slice(0,2) == "-O") {
|
|
||||||
opt_str = argv1_str
|
|
||||||
input_file_offset++
|
|
||||||
} else if (argv1_str == "-g") {
|
|
||||||
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
|
// delay construction until we either load it or copy construct it
|
||||||
var gram: grammer
|
var gram: grammer
|
||||||
var base_dir = string("/").join(string(argv[0]).split('/').slice(0,-2))
|
var base_dir = string("/").join(string(argv[0]).split('/').slice(0,-2))
|
||||||
@@ -51,19 +25,44 @@ fun main(argc: int, argv: **char):int {
|
|||||||
var compiled_version = 1
|
var compiled_version = 1
|
||||||
var file_contents = read_file(file_name)
|
var file_contents = read_file(file_name)
|
||||||
var loaded_and_valid = false
|
var loaded_and_valid = false
|
||||||
|
var doing_repl = false
|
||||||
|
|
||||||
|
if (argc <= 1) {
|
||||||
|
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 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++
|
||||||
|
} else if (argv1_str.length() > 2 && argv1_str.slice(0,2) == "-O") {
|
||||||
|
opt_str = argv1_str
|
||||||
|
input_file_offset++
|
||||||
|
} else if (argv1_str == "-g") {
|
||||||
|
line_ctrl = true
|
||||||
|
input_file_offset++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (file_exists(compiled_name)) {
|
if (file_exists(compiled_name)) {
|
||||||
/*println("cached file exists")*/
|
|
||||||
var pos = 0
|
var pos = 0
|
||||||
var binary = read_file_binary(compiled_name)
|
var binary = read_file_binary(compiled_name)
|
||||||
/*println("read file!")*/
|
|
||||||
var saved_version = 0
|
var saved_version = 0
|
||||||
unpack(saved_version, pos) = unserialize<int>(binary, pos)
|
unpack(saved_version, pos) = unserialize<int>(binary, pos)
|
||||||
if (saved_version == compiled_version) {
|
if (saved_version == compiled_version) {
|
||||||
var cached_contents = string()
|
var cached_contents = string()
|
||||||
unpack(cached_contents, pos) = unserialize<string>(binary, pos)
|
unpack(cached_contents, pos) = unserialize<string>(binary, pos)
|
||||||
if (cached_contents == file_contents) {
|
if (cached_contents == file_contents) {
|
||||||
/*println("loaded_and_valid, using cached version!")*/
|
|
||||||
loaded_and_valid = true
|
loaded_and_valid = true
|
||||||
pos = gram.unserialize(binary, pos)
|
pos = gram.unserialize(binary, pos)
|
||||||
} else println("contents different")
|
} else println("contents different")
|
||||||
@@ -73,7 +72,6 @@ fun main(argc: int, argv: **char):int {
|
|||||||
}
|
}
|
||||||
if (!loaded_and_valid) {
|
if (!loaded_and_valid) {
|
||||||
println("Not loaded_and_valid, re-generating and writing out")
|
println("Not loaded_and_valid, re-generating and writing out")
|
||||||
/*gram = load_grammer(file_contents)*/
|
|
||||||
// since we now don't construct before hand
|
// since we now don't construct before hand
|
||||||
gram.copy_construct(&load_grammer(file_contents))
|
gram.copy_construct(&load_grammer(file_contents))
|
||||||
println("grammer loaded, calculate_first_set")
|
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)*/
|
||||||
/*var parsers = vector(parse1,parse2,parse3,parse4,parse5,parse6)*/
|
/*var parsers = vector(parse1,parse2,parse3,parse4,parse5,parse6)*/
|
||||||
/*var parsers = vector(parse1,parse2,parse3,parse4,parse5,parse6,parse7,parse8)*/
|
/*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
|
var importer.construct(parsers, ast_pass, vector(string(), base_dir + "/stdlib/")): importer
|
||||||
importer.import(kraken_file_name)
|
importer.import(kraken_file_name)
|
||||||
// Passes
|
// Passes
|
||||||
@@ -109,8 +123,7 @@ fun main(argc: int, argv: **char):int {
|
|||||||
defer_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)
|
defer_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)
|
||||||
if (interpret_instead) {
|
if (interpret_instead) {
|
||||||
printlnerr("Interpreting!")
|
printlnerr("Interpreting!")
|
||||||
var interpret.construct(importer.name_ast_map, importer.ast_pass.ast_to_syntax): interpreter
|
call_main(importer.name_ast_map)
|
||||||
interpret.call_main()
|
|
||||||
} else {
|
} else {
|
||||||
if (line_ctrl) {
|
if (line_ctrl) {
|
||||||
printlnerr("running C-specific passes")
|
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 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"
|
var kraken_c_output_name = kraken_file_name + ".c"
|
||||||
write_file(kraken_c_output_name, c_output_pair.first)
|
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
|
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)
|
printlnerr(compile_string)
|
||||||
system(compile_string)
|
system(compile_string)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import os:*
|
|||||||
import importer:*
|
import importer:*
|
||||||
import ast_nodes:*
|
import ast_nodes:*
|
||||||
import type:*
|
import type:*
|
||||||
|
import pass_common:*
|
||||||
|
|
||||||
adt search_type {
|
adt search_type {
|
||||||
none,
|
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
|
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>) {
|
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))*/
|
/*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
|
// 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")
|
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 symbol:*
|
||||||
import ast_nodes:*
|
import ast_nodes:*
|
||||||
// for error with syntax tree
|
// for error with syntax tree
|
||||||
import ast_transformation:*
|
import pass_common:*
|
||||||
import poset:*
|
import poset:*
|
||||||
|
|
||||||
fun code_triple(): code_triple return code_triple(string(), string(), string());
|
fun code_triple(): code_triple return code_triple(string(), string(), string());
|
||||||
@@ -72,27 +72,6 @@ obj code_triple (Object) {
|
|||||||
return pre+value+post
|
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) {
|
obj c_generator (Object) {
|
||||||
var id_counter: int
|
var id_counter: int
|
||||||
var ast_to_syntax: map<*ast_node, *tree<symbol>>
|
var ast_to_syntax: map<*ast_node, *tree<symbol>>
|
||||||
|
|||||||
@@ -104,89 +104,91 @@ obj importer (Object) {
|
|||||||
printlnerr("**Fourth Pass**")
|
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);)
|
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>) {
|
}
|
||||||
remove_node(symbol("$NULL$", false), parse_tree)
|
|
||||||
remove_node(symbol("WS", false), parse_tree)
|
|
||||||
// the terminals have " around them, which we have to escape
|
|
||||||
remove_node(symbol("\"\\(\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\"\\)\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\"template\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\"return\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\"defer\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\";\"", true), parse_tree)
|
|
||||||
remove_node(symbol("line_end", false), parse_tree)
|
|
||||||
remove_node(symbol("\"{\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\"}\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\"(\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\")\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\"if\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\"while\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\"__if_comp__\"", true), parse_tree)
|
|
||||||
remove_node(symbol("\"comp_simple_passthrough\"", true), parse_tree)
|
|
||||||
/*remove_node(symbol("obj_nonterm", false), parse_tree)*/
|
|
||||||
remove_node(symbol("adt_nonterm", false), parse_tree)
|
|
||||||
|
|
||||||
collapse_node(symbol("case_statement_list", false), parse_tree)
|
fun trim(parse_tree: *tree<symbol>): *tree<symbol> {
|
||||||
collapse_node(symbol("opt_param_assign_list", false), parse_tree)
|
remove_node(symbol("$NULL$", false), parse_tree)
|
||||||
collapse_node(symbol("param_assign_list", false), parse_tree)
|
remove_node(symbol("WS", false), parse_tree)
|
||||||
collapse_node(symbol("opt_typed_parameter_list", false), parse_tree)
|
// the terminals have " around them, which we have to escape
|
||||||
collapse_node(symbol("opt_parameter_list", false), parse_tree)
|
remove_node(symbol("\"\\(\"", true), parse_tree)
|
||||||
collapse_node(symbol("intrinsic_parameter_list", false), parse_tree)
|
remove_node(symbol("\"\\)\"", true), parse_tree)
|
||||||
collapse_node(symbol("identifier_list", false), parse_tree)
|
remove_node(symbol("\"template\"", true), parse_tree)
|
||||||
collapse_node(symbol("adt_option_list", false), parse_tree)
|
remove_node(symbol("\"return\"", true), parse_tree)
|
||||||
collapse_node(symbol("statement_list", false), parse_tree)
|
remove_node(symbol("\"defer\"", true), parse_tree)
|
||||||
collapse_node(symbol("parameter_list", false), parse_tree)
|
remove_node(symbol("\";\"", true), parse_tree)
|
||||||
collapse_node(symbol("typed_parameter_list", false), parse_tree)
|
remove_node(symbol("line_end", false), parse_tree)
|
||||||
collapse_node(symbol("unorderd_list_part", false), parse_tree)
|
remove_node(symbol("\"{\"", true), parse_tree)
|
||||||
collapse_node(symbol("if_comp_pred", false), parse_tree)
|
remove_node(symbol("\"}\"", true), parse_tree)
|
||||||
collapse_node(symbol("declaration_block", false), parse_tree)
|
remove_node(symbol("\"(\"", true), parse_tree)
|
||||||
collapse_node(symbol("type_list", false), parse_tree)
|
remove_node(symbol("\")\"", true), parse_tree)
|
||||||
collapse_node(symbol("opt_type_list", false), parse_tree)
|
remove_node(symbol("\"if\"", true), parse_tree)
|
||||||
collapse_node(symbol("template_param_list", false), parse_tree)
|
remove_node(symbol("\"while\"", true), parse_tree)
|
||||||
collapse_node(symbol("trait_list", false), parse_tree)
|
remove_node(symbol("\"__if_comp__\"", true), parse_tree)
|
||||||
collapse_node(symbol("dec_type", false), parse_tree)
|
remove_node(symbol("\"comp_simple_passthrough\"", true), parse_tree)
|
||||||
}
|
/*remove_node(symbol("obj_nonterm", false), parse_tree)*/
|
||||||
fun remove_node(remove: symbol, parse_tree: *tree<symbol>) {
|
remove_node(symbol("adt_nonterm", false), parse_tree)
|
||||||
var to_process = queue<*tree<symbol>>()
|
|
||||||
to_process.push(parse_tree)
|
collapse_node(symbol("case_statement_list", false), parse_tree)
|
||||||
while(!to_process.empty()) {
|
collapse_node(symbol("opt_param_assign_list", false), parse_tree)
|
||||||
var node = to_process.pop()
|
collapse_node(symbol("param_assign_list", false), parse_tree)
|
||||||
for (var i = 0; i < node->children.size; i++;) {
|
collapse_node(symbol("opt_typed_parameter_list", false), parse_tree)
|
||||||
if (!node->children[i] || node->children[i]->data.equal_wo_data(remove)) {
|
collapse_node(symbol("opt_parameter_list", false), parse_tree)
|
||||||
/*
|
collapse_node(symbol("intrinsic_parameter_list", false), parse_tree)
|
||||||
if (!node->children[i])
|
collapse_node(symbol("identifier_list", false), parse_tree)
|
||||||
println("not because null")
|
collapse_node(symbol("adt_option_list", false), parse_tree)
|
||||||
else {
|
collapse_node(symbol("statement_list", false), parse_tree)
|
||||||
print("not because "); println(remove.name)
|
collapse_node(symbol("parameter_list", false), parse_tree)
|
||||||
}
|
collapse_node(symbol("typed_parameter_list", false), parse_tree)
|
||||||
*/
|
collapse_node(symbol("unorderd_list_part", false), parse_tree)
|
||||||
node->children.remove(i)
|
collapse_node(symbol("if_comp_pred", false), parse_tree)
|
||||||
i--;
|
collapse_node(symbol("declaration_block", false), parse_tree)
|
||||||
} else {
|
collapse_node(symbol("type_list", false), parse_tree)
|
||||||
/*println(remove.to_string() + " not equal " + node->children[i]->data.to_string())*/
|
collapse_node(symbol("opt_type_list", false), parse_tree)
|
||||||
to_process.push(node->children[i])
|
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)
|
||||||
}
|
|
||||||
}
|
return parse_tree
|
||||||
fun collapse_node(remove: symbol, parse_tree: *tree<symbol>) {
|
}
|
||||||
var to_process = queue<*tree<symbol>>()
|
fun remove_node(remove: symbol, parse_tree: *tree<symbol>) {
|
||||||
to_process.push(parse_tree)
|
var to_process = queue<*tree<symbol>>()
|
||||||
while(!to_process.empty()) {
|
to_process.push(parse_tree)
|
||||||
var node = to_process.pop()
|
while(!to_process.empty()) {
|
||||||
for (var i = 0; i < node->children.size; i++;) {
|
var node = to_process.pop()
|
||||||
if (node->children[i]->data.equal_wo_data(remove)) {
|
for (var i = 0; i < node->children.size; i++;) {
|
||||||
var add_children = node->children[i]->children;
|
if (!node->children[i] || node->children[i]->data.equal_wo_data(remove)) {
|
||||||
// stick child's children between the current children divided
|
/*
|
||||||
// on i, without including i
|
if (!node->children[i])
|
||||||
node->children = node->children.slice(0,i) +
|
println("not because null")
|
||||||
add_children + node->children.slice(i+1,-1)
|
else {
|
||||||
i--;
|
print("not because "); println(remove.name)
|
||||||
} else {
|
|
||||||
to_process.push(node->children[i])
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
node->children.remove(i)
|
||||||
|
i--;
|
||||||
|
} else {
|
||||||
|
/*println(remove.to_string() + " not equal " + node->children[i]->data.to_string())*/
|
||||||
|
to_process.push(node->children[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun collapse_node(remove: symbol, parse_tree: *tree<symbol>) {
|
||||||
|
var to_process = queue<*tree<symbol>>()
|
||||||
|
to_process.push(parse_tree)
|
||||||
|
while(!to_process.empty()) {
|
||||||
|
var node = to_process.pop()
|
||||||
|
for (var i = 0; i < node->children.size; i++;) {
|
||||||
|
if (node->children[i]->data.equal_wo_data(remove)) {
|
||||||
|
var add_children = node->children[i]->children;
|
||||||
|
// stick child's children between the current children divided
|
||||||
|
// on i, without including i
|
||||||
|
node->children = node->children.slice(0,i) +
|
||||||
|
add_children + node->children.slice(i+1,-1)
|
||||||
|
i--;
|
||||||
|
} else {
|
||||||
|
to_process.push(node->children[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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 snprintf(to_str: *char, num: ulong, format: *char, ...): int
|
||||||
ext fun fflush(file: int): int
|
ext fun fflush(file: int): int
|
||||||
ext var stderr: *void
|
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 {
|
fun printlnerr<T>(toPrint: T) : void {
|
||||||
printerr(toPrint)
|
printerr(toPrint)
|
||||||
printerr("\n")
|
printerr("\n")
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import ast_nodes:*
|
import ast_nodes:*
|
||||||
import ast_transformation:*
|
|
||||||
import mem:*
|
import mem:*
|
||||||
import util:*
|
import util:*
|
||||||
import vector:*
|
import vector:*
|
||||||
@@ -9,6 +8,200 @@ import string:*
|
|||||||
fun make_this_noncached(object: *ast_node): *ast_node {
|
fun make_this_noncached(object: *ast_node): *ast_node {
|
||||||
return ast_identifier_ptr("this", object->type_def.self_type->clone_with_indirection(1), object)
|
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 {
|
fun possible_object_equality(lvalue: *ast_node, rvalue: *ast_node): *ast_node {
|
||||||
var ltype = get_ast_type(lvalue)
|
var ltype = get_ast_type(lvalue)
|
||||||
var rtype = get_ast_type(rvalue)
|
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 ast_value_ptr(string("false"), type_ptr(base_type::boolean()))
|
||||||
return make_operator_call("==", vector(lvalue, rvalue))
|
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
|
// 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 {
|
fun assign_or_copy_construct_statement(lvalue: *ast_node, rvalue: *ast_node): *ast_node {
|
||||||
var ltype = get_ast_type(lvalue)
|
var ltype = get_ast_type(lvalue)
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ fun error(message: string::string) {
|
|||||||
io::printlnerr(message)
|
io::printlnerr(message)
|
||||||
os::exit(-1)
|
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 {
|
fun deref_equality<T>(a: *T, b: *T): bool {
|
||||||
if ( (a && b && !(*a == *b)) || (a && !b) || (!a && b) )
|
if ( (a && b && !(*a == *b)) || (a && !b) || (!a && b) )
|
||||||
|
|||||||
Reference in New Issue
Block a user