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) }