Adding in proper copy_construct into function calls and destruct afterwards. Doesn't correctly destruct return values yet.
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014 Nathan Christopher Braswell
|
Copyright (c) 2014-2016 Nathan Christopher Braswell, Google Inc.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1139,6 +1139,8 @@ fun get_builtin_function(name: string, param_types: vector<*type>): *ast_node {
|
|||||||
if (name == "." || name == "->") {
|
if (name == "." || name == "->") {
|
||||||
if (name == "->" && param_types[0]->indirection == 0)
|
if (name == "->" && param_types[0]->indirection == 0)
|
||||||
error(string("drereferencing not a pointer: ") + name)
|
error(string("drereferencing not a pointer: ") + name)
|
||||||
|
else if (name == "." && param_types[0]->indirection != 0)
|
||||||
|
error(string("dot operator on a pointer: ") + name)
|
||||||
else
|
else
|
||||||
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[1]), vector<*ast_node>(), false)
|
||||||
}
|
}
|
||||||
|
|||||||
+94
-52
@@ -476,7 +476,8 @@ obj interpreter (Object) {
|
|||||||
println("calling main!")
|
println("calling main!")
|
||||||
println("=============")
|
println("=============")
|
||||||
var var_stack = stack<map<string, value>>()
|
var var_stack = stack<map<string, value>>()
|
||||||
var result = call_function(results[0], vector<value>(), &var_stack, value::void_nothing())
|
var defer_stack = stack<*ast_node>()
|
||||||
|
var result = call_function(results[0], vector<value>(), vector<*ast_node>(), &var_stack, &defer_stack, value::void_nothing())
|
||||||
println("=============")
|
println("=============")
|
||||||
println("Main returned: ")
|
println("Main returned: ")
|
||||||
print_value(result)
|
print_value(result)
|
||||||
@@ -518,63 +519,104 @@ obj interpreter (Object) {
|
|||||||
ret_ptr = ((left_side.object_like.first) cast *char + offset_into_struct(left_side.object_like.second, func_call_parameters[1])) cast *void
|
ret_ptr = ((left_side.object_like.first) cast *char + offset_into_struct(left_side.object_like.second, func_call_parameters[1])) cast *void
|
||||||
return make_pair(value::variable(make_pair(ret_ptr, func_call_parameters[1]->identifier.type)), control_flow::nor())
|
return make_pair(value::variable(make_pair(ret_ptr, func_call_parameters[1]->identifier.type)), control_flow::nor())
|
||||||
}
|
}
|
||||||
var parameters = func_call_parameters.map(fun(p: *ast_node): value return interpret(p, var_stack, enclosing_object, defer_stack).first;)
|
// so here we either do an operator, call call_func with value parameters, or call call_func with ast_expressions
|
||||||
return make_pair(call_function(func_call_func, parameters, var_stack, new_enclosing_object), control_flow::nor())
|
// (so we can properly copy_construct if necessary)
|
||||||
|
var parameters = vector<value>()
|
||||||
|
var parameter_sources = vector<*ast_node>()
|
||||||
|
// if we don't have to copy_construct params (is an operator, or has no object params)
|
||||||
|
if (func_name == "&" || !func_call_parameters.any_true(fun(p: *ast_node): bool return get_ast_type(p)->is_object_like() && get_ast_type(p)->indirection == 0;)) {
|
||||||
|
parameters = func_call_parameters.map(fun(p: *ast_node): value return interpret(p, var_stack, enclosing_object, defer_stack).first;)
|
||||||
|
if ( parameters.size == 2 && (func_name == "+" || func_name == "-" || func_name == "*" || func_name == "/"
|
||||||
|
|| func_name == "<" || func_name == ">" || func_name == "<=" || func_name == ">="
|
||||||
|
|| func_name == "==" || func_name == "!=" || func_name == "%" || func_name == "^"
|
||||||
|
|| func_name == "|" || func_name == "&"
|
||||||
|
))
|
||||||
|
return make_pair(do_basic_op(func_name, parameters[0], parameters[1]), control_flow::nor())
|
||||||
|
// do negate by subtracting from zero
|
||||||
|
if (func_name == "-")
|
||||||
|
return make_pair(do_basic_op_second_half(string("-"), 0, parameters[0], null<type>()), control_flow::nor())
|
||||||
|
if (func_name == "++p" || func_name == "--p") {
|
||||||
|
var to_ret = get_real_value(parameters[0])
|
||||||
|
store_into_variable(parameters[0], do_basic_op(func_name.slice(0,1), parameters[0], value::integer(1)))
|
||||||
|
return make_pair(to_ret, control_flow::nor())
|
||||||
|
}
|
||||||
|
if (func_name == "++" || func_name == "--") {
|
||||||
|
store_into_variable(parameters[0], do_basic_op(func_name.slice(0,1), parameters[0], value::integer(1)))
|
||||||
|
return make_pair(get_real_value(parameters[0]), control_flow::nor())
|
||||||
|
}
|
||||||
|
if (func_name == "&") {
|
||||||
|
if (!is_variable(parameters[0]))
|
||||||
|
error("Trying to take address of not a variable")
|
||||||
|
return make_pair(value::pointer(make_pair(parameters[0].variable.first, parameters[0].variable.second->clone_with_increased_indirection())), control_flow::nor())
|
||||||
|
}
|
||||||
|
// to dereference, we basically take the pointer's value (maybe going through a variable to get it)
|
||||||
|
// and re-wrap it up into a variable value (so it can be assigned to, etc)
|
||||||
|
if (func_name == "*" || func_name == "[]") {
|
||||||
|
var dereference_val = parameters[0]
|
||||||
|
if (func_name == "[]")
|
||||||
|
dereference_val = do_basic_op(string("+"), parameters[0], parameters[1])
|
||||||
|
if (!is_pointer(get_real_value(parameters[0])))
|
||||||
|
error("Trying to take dereference not a pointer")
|
||||||
|
return make_pair(value::variable(make_pair(get_real_value(dereference_val).pointer.first, dereference_val.pointer.second->clone_with_decreased_indirection())), control_flow::nor())
|
||||||
|
}
|
||||||
|
// check for built-in-ish externs (everything the standard library needs)
|
||||||
|
if (func_name == "printf" || func_name == "malloc" || func_name == "free" || func_name == "fflush" || func_name == "snprintf")
|
||||||
|
return make_pair(call_built_in_extern(func_name, parameters), control_flow::nor())
|
||||||
|
if (!func_call_func->function.body_statement)
|
||||||
|
error(string("trying to call unsupported extern function: ") + func_name)
|
||||||
|
} else {
|
||||||
|
// not the operator & and at least one object like parameter
|
||||||
|
parameter_sources = func_call_parameters
|
||||||
|
}
|
||||||
|
return make_pair(call_function(func_call_func, parameters, parameter_sources, var_stack, defer_stack, new_enclosing_object), control_flow::nor())
|
||||||
}
|
}
|
||||||
fun call_function(func: *ast_node, parameters: vector<value>, var_stack: *stack<map<string, value>>, enclosing_object: value): value {
|
// call_function can be called with either parameter values in parameters or ast expressions in parameter_sources
|
||||||
|
// this is to allow easy function calling if we already have the values (for main, say, or to make our job if it's not
|
||||||
|
// an operator easier), but we need to be able to be called with ast_expressions too so we can properly copy_construct once
|
||||||
|
fun call_function(func: *ast_node, parameters: vector<value>, parameter_sources: vector<*ast_node>, var_stack: *stack<map<string, value>>, defer_stack: *stack<*ast_node>, enclosing_object: value): value {
|
||||||
// will need adjustment
|
// will need adjustment
|
||||||
var func_name = func->function.name
|
var func_name = func->function.name
|
||||||
if ( parameters.size == 2 && (func_name == "+" || func_name == "-" || func_name == "*" || func_name == "/"
|
|
||||||
|| func_name == "<" || func_name == ">" || func_name == "<=" || func_name == ">="
|
|
||||||
|| func_name == "==" || func_name == "!=" || func_name == "%" || func_name == "^"
|
|
||||||
|| func_name == "|" || func_name == "&"
|
|
||||||
))
|
|
||||||
return do_basic_op(func_name, parameters[0], parameters[1])
|
|
||||||
// do negate by subtracting from zero
|
|
||||||
if (func_name == "-")
|
|
||||||
return do_basic_op_second_half(string("-"), 0, parameters[0], null<type>())
|
|
||||||
if (func_name == "++p" || func_name == "--p") {
|
|
||||||
var to_ret = get_real_value(parameters[0])
|
|
||||||
store_into_variable(parameters[0], do_basic_op(func_name.slice(0,1), parameters[0], value::integer(1)))
|
|
||||||
return to_ret
|
|
||||||
}
|
|
||||||
if (func_name == "++" || func_name == "--") {
|
|
||||||
store_into_variable(parameters[0], do_basic_op(func_name.slice(0,1), parameters[0], value::integer(1)))
|
|
||||||
return get_real_value(parameters[0])
|
|
||||||
}
|
|
||||||
if (func_name == "&") {
|
|
||||||
if (!is_variable(parameters[0]))
|
|
||||||
error("Trying to take address of not a variable")
|
|
||||||
return value::pointer(make_pair(parameters[0].variable.first, parameters[0].variable.second->clone_with_increased_indirection()))
|
|
||||||
}
|
|
||||||
// to dereference, we basically take the pointer's value (maybe going through a variable to get it)
|
|
||||||
// and re-wrap it up into a variable value (so it can be assigned to, etc)
|
|
||||||
if (func_name == "*" || func_name == "[]") {
|
|
||||||
var dereference_val = parameters[0]
|
|
||||||
if (func_name == "[]")
|
|
||||||
dereference_val = do_basic_op(string("+"), parameters[0], parameters[1])
|
|
||||||
if (!is_pointer(get_real_value(parameters[0])))
|
|
||||||
error("Trying to take dereference not a pointer")
|
|
||||||
return value::variable(make_pair(get_real_value(dereference_val).pointer.first, dereference_val.pointer.second->clone_with_decreased_indirection()))
|
|
||||||
}
|
|
||||||
// check for built-in-ish externs (everything the standard library needs)
|
|
||||||
if (func_name == "printf" || func_name == "malloc" || func_name == "free" || func_name == "fflush" || func_name == "snprintf")
|
|
||||||
return call_built_in_extern(func_name, parameters)
|
|
||||||
if (!func->function.body_statement)
|
|
||||||
error(string("trying to call unsupported extern function: ") + func_name)
|
|
||||||
// do regular function
|
// do regular function
|
||||||
var new_var_stack = stack<map<string, value>>()
|
var new_var_stack = stack<map<string, value>>()
|
||||||
new_var_stack.push(map<string,value>())
|
// the new defer stack takes care of destructing parameters that were copy_constructed
|
||||||
if (parameters.size != func->function.parameters.size)
|
var new_defer_stack = stack<*ast_node>()
|
||||||
error(string("calling function ") + func->function.name + " with wrong number of parameters")
|
// if this is a value based call, pull from parameters
|
||||||
for (var i = 0; i < parameters.size; i++;) {
|
if (parameter_sources.size == 0) {
|
||||||
var param_type = get_ast_type(func)->parameter_types[i]
|
new_var_stack.push(map<string,value>())
|
||||||
new_var_stack.top()[func->function.parameters[i]->identifier.name] = value::variable(make_pair(malloc(type_size(param_type)), param_type))
|
/*println(func_name + " being called with parameter values")*/
|
||||||
store_into_variable(new_var_stack.top()[func->function.parameters[i]->identifier.name], get_real_value(parameters[i]))
|
if (parameters.size != func->function.parameters.size)
|
||||||
|
error(string("calling function ") + func->function.name + " with wrong number of parameters (values)")
|
||||||
|
for (var i = 0; i < parameters.size; i++;) {
|
||||||
|
var param_type = get_ast_type(func)->parameter_types[i]
|
||||||
|
var param_ident = func->function.parameters[i]
|
||||||
|
new_var_stack.top()[param_ident->identifier.name] = value::variable(make_pair(malloc(type_size(param_type)), param_type))
|
||||||
|
store_into_variable(new_var_stack.top()[param_ident->identifier.name], get_real_value(parameters[i]))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// on this side we construct in the old var stack, then move it over to the new one so that references resolve correctly
|
||||||
|
var_stack->push(map<string,value>())
|
||||||
|
/*println(func_name + " being called with parameter sources")*/
|
||||||
|
// need to pull from parameter_sources instead
|
||||||
|
if (parameter_sources.size != func->function.parameters.size)
|
||||||
|
error(string("calling function ") + func->function.name + " with wrong number of parameters (sources)")
|
||||||
|
for (var i = 0; i < parameter_sources.size; i++;) {
|
||||||
|
var param_type = get_ast_type(func)->parameter_types[i]
|
||||||
|
var param_ident = func->function.parameters[i]
|
||||||
|
/*println(param_ident->identifier.name + " is the name of the identifier being added")*/
|
||||||
|
var_stack->top()[param_ident->identifier.name] = value::variable(make_pair(malloc(type_size(param_type)), param_type))
|
||||||
|
if (param_type->indirection == 0 && (param_type->is_adt() || (param_type->is_object() && has_method(param_type->type_def, "copy_construct", vector(param_type->clone_with_increased_indirection()))))) {
|
||||||
|
interpret(ast_statement_ptr(make_method_call(param_ident, "copy_construct", vector(make_operator_call("&", vector(parameter_sources[i]))))), var_stack, enclosing_object, defer_stack)
|
||||||
|
new_defer_stack.push(ast_statement_ptr(make_method_call(param_ident, "destruct", vector<*ast_node>())))
|
||||||
|
} else {
|
||||||
|
store_into_variable(var_stack->top()[param_ident->identifier.name], get_real_value(interpret(parameter_sources[i], var_stack, enclosing_object, defer_stack).first))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// swap the params over
|
||||||
|
new_var_stack.push(var_stack->pop())
|
||||||
}
|
}
|
||||||
// our defer stack to keep track of what needs to be evaluated later at runtime
|
var to_ret = interpret(func->function.body_statement, &new_var_stack, enclosing_object, &new_defer_stack).first
|
||||||
var defer_stack = stack<*ast_node>()
|
// handle destructing params
|
||||||
var to_ret = interpret(func->function.body_statement, &new_var_stack, enclosing_object, &defer_stack).first
|
interpret_from_defer_stack(&new_defer_stack, &new_var_stack, enclosing_object)
|
||||||
// need to handle copying out object before pop_and_free deletes them
|
// need to handle copying out object before pop_and_free deletes them
|
||||||
pop_and_free(&new_var_stack)
|
pop_and_free(&new_var_stack)
|
||||||
return to_ret
|
return to_ret
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ fun print(toPrint: double) {
|
|||||||
var int_str = new<char>(how_much+2)
|
var int_str = new<char>(how_much+2)
|
||||||
snprintf(int_str, (how_much+1) cast ulong, "%f", toPrint)
|
snprintf(int_str, (how_much+1) cast ulong, "%f", toPrint)
|
||||||
print(int_str)
|
print(int_str)
|
||||||
/*delete(int_str)*/
|
delete(int_str)
|
||||||
}
|
}
|
||||||
fun print<T>(toPrint: T): void
|
fun print<T>(toPrint: T): void
|
||||||
print(string::to_string(toPrint))
|
print(string::to_string(toPrint))
|
||||||
|
|||||||
@@ -225,6 +225,8 @@ obj type (Object) {
|
|||||||
to_ret->is_ref = is_ref_in
|
to_ret->is_ref = is_ref_in
|
||||||
return to_ret
|
return to_ret
|
||||||
}
|
}
|
||||||
|
fun is_object_like(): bool
|
||||||
|
return is_object() || is_adt()
|
||||||
fun is_object(): bool {
|
fun is_object(): bool {
|
||||||
match (base) {
|
match (base) {
|
||||||
base_type::object() return true
|
base_type::object() return true
|
||||||
|
|||||||
Reference in New Issue
Block a user