Adding in proper copy_construct into function calls and destruct afterwards. Doesn't correctly destruct return values yet.

This commit is contained in:
Nathan Braswell
2016-05-21 11:20:29 -07:00
parent cf8090f825
commit 828f36daab
5 changed files with 100 additions and 54 deletions

View File

@@ -1,6 +1,6 @@
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
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1139,6 +1139,8 @@ fun get_builtin_function(name: string, param_types: vector<*type>): *ast_node {
if (name == "." || name == "->") {
if (name == "->" && param_types[0]->indirection == 0)
error(string("drereferencing not a pointer: ") + name)
else if (name == "." && param_types[0]->indirection != 0)
error(string("dot operator on a pointer: ") + name)
else
return ast_function_ptr(name, type_ptr(param_types, param_types[1]), vector<*ast_node>(), false)
}

View File

@@ -476,7 +476,8 @@ obj interpreter (Object) {
println("calling main!")
println("=============")
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("Main returned: ")
print_value(result)
@@ -518,34 +519,35 @@ 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
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;)
return make_pair(call_function(func_call_func, parameters, var_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 {
// will need adjustment
var func_name = func->function.name
// so here we either do an operator, call call_func with value parameters, or call call_func with ast_expressions
// (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 do_basic_op(func_name, parameters[0], parameters[1])
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 do_basic_op_second_half(string("-"), 0, parameters[0], null<type>())
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 to_ret
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 get_real_value(parameters[0])
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 value::pointer(make_pair(parameters[0].variable.first, parameters[0].variable.second->clone_with_increased_indirection()))
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)
@@ -555,26 +557,66 @@ obj interpreter (Object) {
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()))
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 call_built_in_extern(func_name, parameters)
if (!func->function.body_statement)
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())
}
// 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
var func_name = func->function.name
// do regular function
var new_var_stack = stack<map<string, value>>()
// the new defer stack takes care of destructing parameters that were copy_constructed
var new_defer_stack = stack<*ast_node>()
// if this is a value based call, pull from parameters
if (parameter_sources.size == 0) {
new_var_stack.push(map<string,value>())
/*println(func_name + " being called with parameter values")*/
if (parameters.size != func->function.parameters.size)
error(string("calling function ") + func->function.name + " with wrong number of parameters")
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]
new_var_stack.top()[func->function.parameters[i]->identifier.name] = value::variable(make_pair(malloc(type_size(param_type)), param_type))
store_into_variable(new_var_stack.top()[func->function.parameters[i]->identifier.name], get_real_value(parameters[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]))
}
// our defer stack to keep track of what needs to be evaluated later at runtime
var defer_stack = stack<*ast_node>()
var to_ret = interpret(func->function.body_statement, &new_var_stack, enclosing_object, &defer_stack).first
} 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())
}
var to_ret = interpret(func->function.body_statement, &new_var_stack, enclosing_object, &new_defer_stack).first
// handle destructing params
interpret_from_defer_stack(&new_defer_stack, &new_var_stack, enclosing_object)
// need to handle copying out object before pop_and_free deletes them
pop_and_free(&new_var_stack)
return to_ret

View File

@@ -47,7 +47,7 @@ fun print(toPrint: double) {
var int_str = new<char>(how_much+2)
snprintf(int_str, (how_much+1) cast ulong, "%f", toPrint)
print(int_str)
/*delete(int_str)*/
delete(int_str)
}
fun print<T>(toPrint: T): void
print(string::to_string(toPrint))

View File

@@ -225,6 +225,8 @@ obj type (Object) {
to_ret->is_ref = is_ref_in
return to_ret
}
fun is_object_like(): bool
return is_object() || is_adt()
fun is_object(): bool {
match (base) {
base_type::object() return true