From ce1afa45f447b408ea3ca2693e131209a31179bb Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 18 May 2016 23:11:00 -0700 Subject: [PATCH] Added a lot to the interpreter, but some odd problem where snprintf seems to print the wrong thing something like a 10th of the time. Debugged it for a while over two days, and I've narrowed it down to the actual snprintf call. It seems to happen under some different circumstances for compiled versions too, so I'm just going to keep it like this for now. --- kraken.krak | 2 +- stdlib/c_generator.krak | 23 ++++--- stdlib/interpreter.krak | 147 ++++++++++++++++++++++++++-------------- stdlib/io.krak | 7 +- 4 files changed, 115 insertions(+), 64 deletions(-) diff --git a/kraken.krak b/kraken.krak index 46c04c9..26c0ef1 100644 --- a/kraken.krak +++ b/kraken.krak @@ -87,7 +87,7 @@ fun main(argc: int, argv: **char):int { 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 -O3 -std=c99 " + c_output_pair.second + " " + kraken_c_output_name + " -o " + executable_name + var compile_string = "cc -g -O3 -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -std=c99 " + c_output_pair.second + " " + kraken_c_output_name + " -o " + executable_name println(compile_string) system(compile_string) } diff --git a/stdlib/c_generator.krak b/stdlib/c_generator.krak index 0baf454..7c2fbaa 100644 --- a/stdlib/c_generator.krak +++ b/stdlib/c_generator.krak @@ -84,6 +84,15 @@ fun is_dot_style_method_call(node: *ast_node): bool { 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> @@ -789,15 +798,11 @@ obj c_generator (Object) { } // handle method call from inside method of same object if (!dot_style_method_call && enclosing_object) { - var methods = enclosing_object->type_def.methods - for (var i = 0; i < methods.size; i++;) { - if (methods[i] == node->function_call.func || (is_template(methods[i]) && methods[i]->template.instantiated.contains(node->function_call.func))) { - if (enclosing_func && enclosing_func->function.closed_variables.size()) - call_string += "(*(closure_data->this))"; - else - call_string += "this"; - break - } + if (method_in_object(node->function_call.func, enclosing_object)) { + if (enclosing_func && enclosing_func->function.closed_variables.size()) + call_string += "(*(closure_data->this))"; + else + call_string += "this"; } } diff --git a/stdlib/interpreter.krak b/stdlib/interpreter.krak index f18bfc2..5fc2380 100644 --- a/stdlib/interpreter.krak +++ b/stdlib/interpreter.krak @@ -81,6 +81,9 @@ fun wrap_value(val: *ast_node): value { to_ret += value_str[i] } } + // if there was only one character + if (value_str.length() == 1) + to_ret = value_str return value::pointer(make_pair((to_ret.toCharArray()) cast *void, get_ast_type(val))) } else if (value_str[0] == '\'') //'// lol, comment hack for vim syntax highlighting (my fault, of course) return value::character(value_str[1]) @@ -435,7 +438,9 @@ fun offset_into_struct(struct_type: *type, ident: *ast_node): ulong { fun pop_and_free(var_stack: *stack>) { var_stack->pop().for_each(fun(k: string, v: value) { match(v) { - value::variable(backing) free(backing.first) + value::variable(backing) { + free(backing.first) + } } }) } @@ -477,30 +482,35 @@ obj interpreter (Object) { print_value(result) println("=============") } - fun interpret_function_call(func_call: *ast_node, var_stack: *stack>, enclosing_object: value): pair { + fun interpret_function_call(func_call: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { 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() // note here also that this is likely not a foolproof method if (is_dot_style_method_call(func_call)) { - println("DOT STYLE METHOD CALL") - new_enclosing_object = get_real_value(interpret(func_call_func->function_call.parameters[0], var_stack, enclosing_object).first) + new_enclosing_object = get_real_value(interpret(func_call_func->function_call.parameters[0], var_stack, enclosing_object, defer_stack).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()))) func_call_func = func_call_func->function_call.parameters[1] + } else if (!is_void_nothing(enclosing_object)) { + if (method_in_object(func_call_func, enclosing_object.object_like.second->type_def)) { + // should maybe do something special for closure here + // copy over old enclosing object + new_enclosing_object = enclosing_object + } } // check if it's a same method method call and do the right new_enclosing_object // new_enclosing_object = enclosing_object var func_name = func_call_func->function.name // some of these have to be done before parameters are evaluated (&&, ||, ., ->) if (func_name == "&&" || func_name == "||") { - var p1true = truthy(get_real_value(interpret(func_call_parameters[0], var_stack, enclosing_object).first)) + var p1true = truthy(get_real_value(interpret(func_call_parameters[0], var_stack, enclosing_object, defer_stack).first)) if ( (func_name == "&&" && !p1true) || (func_name == "||" && p1true) ) return make_pair(value::boolean(p1true), control_flow::nor()) - return make_pair(value::boolean(truthy(get_real_value(interpret(func_call_parameters[1], var_stack, enclosing_object).first))), control_flow::nor()) + return make_pair(value::boolean(truthy(get_real_value(interpret(func_call_parameters[1], var_stack, enclosing_object, defer_stack).first))), control_flow::nor()) } else if (func_name == "." || func_name == "->") { - var left_side = get_real_value(interpret(func_call_parameters[0], var_stack, enclosing_object).first) + var left_side = get_real_value(interpret(func_call_parameters[0], var_stack, enclosing_object, defer_stack).first) var ret_ptr = null() 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 @@ -508,7 +518,7 @@ 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).first;) + 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, var_stack: *stack>, enclosing_object: value): value { @@ -548,7 +558,7 @@ obj interpreter (Object) { 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 == "sprintf") + 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) @@ -562,7 +572,9 @@ obj interpreter (Object) { 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 to_ret = interpret(func->function.body_statement, &new_var_stack, enclosing_object).first + // 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 // need to handle copying out object before pop_and_free deletes them pop_and_free(&new_var_stack) return to_ret @@ -584,9 +596,9 @@ obj interpreter (Object) { } else if (func_name == "fflush") { assert(parameters.size == 1 && is_integer(parameters[0]), "Calling fflush with wrong params") fflush(parameters[0].integer) - } else if (func_name == "sprintf") { - assert(parameters.size == 3 && is_pointer(parameters[0]) && is_pointer(parameters[1]) && is_double_precision(parameters[2]), "Calling fflush with wrong params") - sprintf((parameters[0].pointer.first) cast *char, (parameters[1].pointer.first) cast *char, parameters[2].double_precision) + } else if (func_name == "snprintf") { + assert(parameters.size == 4 && is_pointer(parameters[0]) && is_ulong_int(parameters[1]) && is_pointer(parameters[2]) && is_double_precision(parameters[3]), "Calling snprintf with wrong params") + return value::integer(snprintf((parameters[0].pointer.first) cast *char, parameters[1].ulong_int, (parameters[2].pointer.first) cast *char, parameters[3].double_precision)) } else if (func_name == "exit") { assert(parameters.size == 1 && is_integer(parameters[0]), "Calling exit with wrong params") exit(parameters[0].integer) @@ -595,86 +607,118 @@ obj interpreter (Object) { } return value::void_nothing() } - fun interpret_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value): pair { - return interpret(stmt->statement.child, var_stack, enclosing_object) + fun interpret_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { + return interpret(stmt->statement.child, var_stack, enclosing_object, defer_stack) } - fun interpret_if_statement(if_stmt: *ast_node, var_stack: *stack>, enclosing_object: value): pair { + fun interpret_if_statement(if_stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { var_stack->push(map()) - if (truthy(interpret(if_stmt->if_statement.condition, var_stack, enclosing_object).first)) { - interpret(if_stmt->if_statement.then_part, var_stack, enclosing_object) + if (truthy(interpret(if_stmt->if_statement.condition, var_stack, enclosing_object, defer_stack).first)) { + interpret(if_stmt->if_statement.then_part, var_stack, enclosing_object, defer_stack) } else if (if_stmt->if_statement.else_part) { - interpret(if_stmt->if_statement.else_part, var_stack, enclosing_object) + interpret(if_stmt->if_statement.else_part, var_stack, enclosing_object, defer_stack) } pop_and_free(var_stack) return make_pair(value::void_nothing(), control_flow::nor()) } - fun interpret_while_loop(while_loop: *ast_node, var_stack: *stack>, enclosing_object: value): pair { + fun interpret_while_loop(while_loop: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { var_stack->push(map()) - while (truthy(interpret(while_loop->while_loop.condition, var_stack, enclosing_object).first)) { - interpret(while_loop->while_loop.statement, var_stack, enclosing_object) + while (truthy(interpret(while_loop->while_loop.condition, var_stack, enclosing_object, defer_stack).first)) { + interpret(while_loop->while_loop.statement, var_stack, enclosing_object, defer_stack) } pop_and_free(var_stack) return make_pair(value::void_nothing(), control_flow::nor()) } fun interpret_for_loop(for_loop: *ast_node, var_stack: *stack>, enclosing_object: value): pair { + var defer_stack = stack<*ast_node>() var_stack->push(map()) - interpret(for_loop->for_loop.init, var_stack, enclosing_object) - while (truthy(interpret(for_loop->for_loop.condition, var_stack, enclosing_object).first)) { - interpret(for_loop->for_loop.body, var_stack, enclosing_object) - interpret(for_loop->for_loop.update, var_stack, enclosing_object) + interpret(for_loop->for_loop.init, var_stack, enclosing_object, &defer_stack) + while (truthy(interpret(for_loop->for_loop.condition, var_stack, enclosing_object, &defer_stack).first)) { + var inner_defer_stack = stack<*ast_node>() + interpret(for_loop->for_loop.body, var_stack, enclosing_object, &inner_defer_stack) + interpret(for_loop->for_loop.update, var_stack, enclosing_object, &inner_defer_stack) + interpret_from_defer_stack(&defer_stack, var_stack, enclosing_object) } pop_and_free(var_stack) return make_pair(value::void_nothing(), control_flow::nor()) } - fun interpret_code_block(block: *ast_node, var_stack: *stack>, enclosing_object: value): pair { + fun interpret_code_block(block: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { var_stack->push(map()) + var defer_stack = stack<*ast_node>() for (var i = 0; i < block->code_block.children.size; i++;) { - var statement = interpret(block->code_block.children[i], var_stack, enclosing_object) + var statement = interpret(block->code_block.children[i], var_stack, enclosing_object, &defer_stack) match (statement.second) { control_flow::con() { + interpret_from_defer_stack(&defer_stack, var_stack, enclosing_object) pop_and_free(var_stack) return make_pair(value::void_nothing(), control_flow::con()) } control_flow::bre() { + interpret_from_defer_stack(&defer_stack, var_stack, enclosing_object) pop_and_free(var_stack) return make_pair(value::void_nothing(), control_flow::bre()) } control_flow::ret() { + interpret_from_defer_stack(&defer_stack, var_stack, enclosing_object) pop_and_free(var_stack) return statement } } // if nor, continue on } + interpret_from_defer_stack(&defer_stack, var_stack, enclosing_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>, enclosing_object: value): pair { - return make_pair(get_real_value(interpret(stmt->return_statement.return_value, var_stack, enclosing_object).first), control_flow::ret()) + fun interpret_from_defer_stack(defer_stack: *stack<*ast_node>, var_stack: *stack>, enclosing_object: value) { + var new_defer_stack = stack<*ast_node>() + defer_stack->for_each_reverse(fun(i: *ast_node) { + interpret(i, var_stack, enclosing_object, &new_defer_stack) + }) + if (new_defer_stack.size()) + interpret_from_defer_stack(&new_defer_stack, var_stack, enclosing_object) } - fun interpret_declaration_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value): pair { - var ident_type = stmt->declaration_statement.identifier->identifier.type - var ident_name = stmt->declaration_statement.identifier->identifier.name + fun interpret_return_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { + return make_pair(get_real_value(interpret(stmt->return_statement.return_value, var_stack, enclosing_object, defer_stack).first), control_flow::ret()) + } + fun interpret_declaration_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { + var ident = stmt->declaration_statement.identifier + var ident_type = ident->identifier.type + var ident_name = ident->identifier.name var_stack->top()[ident_name] = value::variable(make_pair(malloc(type_size(ident_type)),ident_type)) - if (stmt->declaration_statement.expression) - store_into_variable(var_stack->top()[ident_name], get_real_value(interpret(stmt->declaration_statement.expression, var_stack, enclosing_object).first)) + if (stmt->declaration_statement.expression) { + if (ident_type->indirection == 0 && (ident_type->is_adt() || (ident_type->is_object() && has_method(ident_type->type_def, "copy_construct", vector(get_ast_type(stmt->declaration_statement.expression)->clone_with_increased_indirection()))))) + interpret(ast_statement_ptr(make_method_call(ident, "copy_construct", vector(make_operator_call("&", vector(stmt->declaration_statement.expression))))), var_stack, enclosing_object, defer_stack) + else + store_into_variable(var_stack->top()[ident_name], get_real_value(interpret(stmt->declaration_statement.expression, var_stack, enclosing_object, defer_stack).first)) + } else if (stmt->declaration_statement.init_method_call) { + interpret(stmt->declaration_statement.init_method_call, var_stack, enclosing_object, defer_stack) + } + // defering destructs + if (ident_type->indirection == 0 && (ident_type->is_adt() || (ident_type->is_object() && has_method(ident_type->type_def, "destruct", vector<*type>())))) + defer_stack->push(ast_statement_ptr(make_method_call(ident, "destruct", vector<*ast_node>()))) return make_pair(value::void_nothing(), control_flow::nor()) } - fun interpret_assignment_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value): pair { - var to = interpret(stmt->assignment_statement.to, var_stack, enclosing_object).first - var from = interpret(stmt->assignment_statement.from, var_stack, enclosing_object).first + fun interpret_assignment_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { + var to = interpret(stmt->assignment_statement.to, var_stack, enclosing_object, defer_stack).first + var from = interpret(stmt->assignment_statement.from, var_stack, enclosing_object, defer_stack).first assert(is_variable(to), "assigning into not a variable") // first, we have to see if this is an object // always do cast now to make our best effort at assignment (assign into a double from a float, etc) store_into_variable(to, cast_value(get_real_value(from), to.variable.second)) return make_pair(value::void_nothing(), control_flow::nor()) } + fun interpret_defer_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { + defer_stack->push(stmt->defer_statement.statement) + return make_pair(value::void_nothing(), control_flow::nor()) + } fun interpret_identifier(ident: *ast_node, var_stack: *stack>, enclosing_object: value): pair { for (var i = 0; i < var_stack->size(); i++;) if (var_stack->from_top(i).contains_key(ident->identifier.name)) return make_pair(var_stack->from_top(i)[ident->identifier.name], control_flow::nor()) - // check for object member + // check for object member / this if (is_object_like(enclosing_object)) { + if (ident->identifier.name == "this") + return make_pair(value::pointer(make_pair(enclosing_object.object_like.first, enclosing_object.object_like.second->clone_with_increased_indirection())), control_flow::nor()) var object_def = enclosing_object.object_like.second->type_def for (var i = 0; i < object_def->type_def.variables.size; i++;) { if (object_def->type_def.variables[i]->declaration_statement.identifier == ident) { @@ -685,8 +729,8 @@ obj interpreter (Object) { } error(string("Cannot find variable: ") + ident->identifier.name) } - fun interpret_cast(node: *ast_node, var_stack: *stack>, enclosing_object: value): pair { - return make_pair(cast_value(interpret(node->cast.value, var_stack, enclosing_object).first, node->cast.to_type), control_flow::nor()) + fun interpret_cast(node: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { + return make_pair(cast_value(interpret(node->cast.value, var_stack, enclosing_object, defer_stack).first, node->cast.to_type), control_flow::nor()) } fun interpret_compiler_intrinsic(node: *ast_node, var_stack: *stack>): pair { var intrinsic_name = node->compiler_intrinsic.intrinsic @@ -696,19 +740,20 @@ obj interpreter (Object) { } fun interpret_value(val: *ast_node): pair return make_pair(wrap_value(val), control_flow::nor()) - fun interpret(node: *ast_node, var_stack: *stack>, enclosing_object: value): pair { + fun interpret(node: *ast_node, var_stack: *stack>, enclosing_object: value, defer_stack: *stack<*ast_node>): pair { match (*node) { - ast_node::function_call(backing) return interpret_function_call(node, var_stack, enclosing_object) - ast_node::statement(backing) return interpret_statement(node, var_stack, enclosing_object) - ast_node::if_statement(backing) return interpret_if_statement(node, var_stack, enclosing_object) - ast_node::while_loop(backing) return interpret_while_loop(node, var_stack, enclosing_object) + ast_node::function_call(backing) return interpret_function_call(node, var_stack, enclosing_object, defer_stack) + ast_node::statement(backing) return interpret_statement(node, var_stack, enclosing_object, defer_stack) + ast_node::if_statement(backing) return interpret_if_statement(node, var_stack, enclosing_object, defer_stack) + ast_node::while_loop(backing) return interpret_while_loop(node, var_stack, enclosing_object, defer_stack) ast_node::for_loop(backing) return interpret_for_loop(node, var_stack, enclosing_object) - ast_node::code_block(backing) return interpret_code_block(node, var_stack, enclosing_object) - ast_node::return_statement(backing) return interpret_return_statement(node, var_stack, enclosing_object) - ast_node::declaration_statement(backing) return interpret_declaration_statement(node, var_stack, enclosing_object) - ast_node::assignment_statement(backing) return interpret_assignment_statement(node, var_stack, enclosing_object) + ast_node::code_block(backing) return interpret_code_block(node, var_stack, enclosing_object, defer_stack) + ast_node::return_statement(backing) return interpret_return_statement(node, var_stack, enclosing_object, defer_stack) + ast_node::declaration_statement(backing) return interpret_declaration_statement(node, var_stack, enclosing_object, defer_stack) + ast_node::assignment_statement(backing) return interpret_assignment_statement(node, var_stack, enclosing_object, defer_stack) + ast_node::defer_statement(backing) return interpret_defer_statement(node, var_stack, enclosing_object, defer_stack) ast_node::identifier(backing) return interpret_identifier(node, var_stack, enclosing_object) - ast_node::cast(backing) return interpret_cast(node, var_stack, enclosing_object) + ast_node::cast(backing) return interpret_cast(node, var_stack, enclosing_object, defer_stack) ast_node::compiler_intrinsic(backing) return interpret_compiler_intrinsic(node, var_stack) ast_node::value(backing) return interpret_value(node) } diff --git a/stdlib/io.krak b/stdlib/io.krak index 6eeb6d8..e968bd2 100644 --- a/stdlib/io.krak +++ b/stdlib/io.krak @@ -38,13 +38,14 @@ fun print(toPrint: bool): void { return; } -ext fun sprintf(to_str: *char, format: *char, d: double) +ext fun snprintf(to_str: *char, num: ulong, format: *char, d: double): int fun print(toPrint: float) print((toPrint) cast double) fun print(toPrint: double) { - var int_str = new((#sizeof) cast int) - sprintf(int_str, "%f", toPrint) + var how_much = snprintf(null(), (0) cast ulong, "%f", toPrint) + var int_str = new(how_much+2) + snprintf(int_str, (how_much+1) cast ulong, "%f", toPrint) print(int_str) delete(int_str) }