diff --git a/cli/all.c b/cli/all.c index 084bee2..6a60d8d 100644 --- a/cli/all.c +++ b/cli/all.c @@ -17,7 +17,7 @@ // Doc : https://likle.github.io/cwalk/ // About : Path library for C/C++. Cross-Platform for Windows, MacOS and // Linux. Supports UNIX and Windows path styles on those platforms. -#include "thirdparty/cwalk/cwalk.c" +#include "modules/thirdparty/cwalk/cwalk.c" /*****************************************************************************/ /* CLI MODULES */ diff --git a/cli/modules/path.c b/cli/modules/path.c index e07bc16..002787f 100644 --- a/cli/modules/path.c +++ b/cli/modules/path.c @@ -7,12 +7,9 @@ #include #include /* defines FILENAME_MAX */ -// TODO: more cli/thirdparty to cli/modules/thirdparty to remove ".." in the -// relative import and split thirdparty sources into dependent directory. - -#include "../thirdparty/cwalk/cwalk.h" +#include "thirdparty/cwalk/cwalk.h" #if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__)) - #include "../thirdparty/dirent/dirent.h" + #include "thirdparty/dirent/dirent.h" #else #include #endif @@ -26,9 +23,6 @@ #define get_cwd getcwd #endif -// TODO: No error is handled below. I should check for path with size more than -// FILENAME_MAX. - // TODO: this macros should be moved to a general place of in cli. #define TOSTRING(x) #x #define STRINGIFY(x) TOSTRING(x) @@ -54,7 +48,7 @@ size_t pathNormalize(const char* path, char* buff, size_t buff_size) { } size_t pathJoin(const char* path_a, const char* path_b, char* buffer, - size_t buff_size) { + size_t buff_size) { return cwk_path_join(path_a, path_b, buffer, buff_size); } @@ -77,7 +71,7 @@ static inline bool pathIsDirectoryExists(const char* path) { if (dir) { /* Directory exists. */ closedir(dir); return true; - } else if (ENOENT == errno) { /* Directory does not exist. */ + } else if (errno == ENOENT) { /* Directory does not exist. */ } else { /* opendir() failed for some other reason. */ } @@ -88,6 +82,17 @@ static inline bool pathIsExists(const char* path) { return pathIsFileExists(path) || pathIsDirectoryExists(path); } +static inline size_t pathAbs(const char* path, char* buff, size_t buff_size) { + + char cwd[FILENAME_MAX]; + + if (get_cwd(cwd, sizeof(cwd)) == NULL) { + // TODO: handle error. + } + + return cwk_path_get_absolute(cwd, path, buff, buff_size); +} + /*****************************************************************************/ /* MODULE FUNCTIONS */ /*****************************************************************************/ @@ -100,7 +105,9 @@ static void _pathSetStyleUnix(PKVM* vm) { static void _pathGetCWD(PKVM* vm) { char cwd[FILENAME_MAX]; - get_cwd(cwd, sizeof(cwd)); // Check if res is NULL. + if (get_cwd(cwd, sizeof(cwd)) == NULL) { + // TODO: Handle error. + } pkReturnString(vm, cwd); } @@ -108,11 +115,8 @@ static void _pathAbspath(PKVM* vm) { const char* path; if (!pkGetArgString(vm, 1, &path)) return; - char cwd[FILENAME_MAX]; - get_cwd(cwd, sizeof(cwd)); // Check if res is NULL. - char abspath[FILENAME_MAX]; - size_t len = cwk_path_get_absolute(cwd, path, abspath, sizeof(abspath)); + size_t len = pathAbs(path, abspath, sizeof(abspath)); pkReturnStringLength(vm, abspath, len); } @@ -121,15 +125,15 @@ static void _pathRelpath(PKVM* vm) { if (!pkGetArgString(vm, 1, &from)) return; if (!pkGetArgString(vm, 2, &path)) return; - // TODO: this won't work if both [from] and [path] doen't have a similler - // root path, so we need to get the absolute path of the both paths (if - // thre're not already) and call the cwalk_relative(). - // ie. - // a/b/c --> a/b/d.txt - works - // a/b/c --> ../d.txt - won't work + char abs_from[FILENAME_MAX]; + size_t len_from = pathAbs(from, abs_from, sizeof(abs_from)); + + char abs_path[FILENAME_MAX]; + size_t len_path = pathAbs(path, abs_path, sizeof(abs_path)); char result[FILENAME_MAX]; - size_t len = cwk_path_get_relative(from, path, result, sizeof(result)); + size_t len = cwk_path_get_relative(abs_from, abs_path, + result, sizeof(result)); pkReturnStringLength(vm, result, len); } diff --git a/cli/thirdparty/cwalk/LICENSE.md b/cli/modules/thirdparty/cwalk/LICENSE.md similarity index 100% rename from cli/thirdparty/cwalk/LICENSE.md rename to cli/modules/thirdparty/cwalk/LICENSE.md diff --git a/cli/thirdparty/cwalk/cwalk.c b/cli/modules/thirdparty/cwalk/cwalk.c similarity index 100% rename from cli/thirdparty/cwalk/cwalk.c rename to cli/modules/thirdparty/cwalk/cwalk.c diff --git a/cli/thirdparty/cwalk/cwalk.h b/cli/modules/thirdparty/cwalk/cwalk.h similarity index 100% rename from cli/thirdparty/cwalk/cwalk.h rename to cli/modules/thirdparty/cwalk/cwalk.h diff --git a/cli/thirdparty/dirent/LICENSE b/cli/modules/thirdparty/dirent/LICENSE similarity index 100% rename from cli/thirdparty/dirent/LICENSE rename to cli/modules/thirdparty/dirent/LICENSE diff --git a/cli/thirdparty/dirent/dirent.h b/cli/modules/thirdparty/dirent/dirent.h similarity index 100% rename from cli/thirdparty/dirent/dirent.h rename to cli/modules/thirdparty/dirent/dirent.h diff --git a/docs/TODO.txt b/docs/TODO.txt index a7064b5..d4a4cd2 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -1,8 +1,11 @@ +// In good first issue +- Refactor fiber into a module and is_done as an attribute. +- floats like ".5". +- Implement argparse. + // To implement. -- Refactor fiber into a module and is_done as an attribute. - - def f(x) f(x) ## not tco, unless return f(x) end @@ -11,13 +14,6 @@ - implement 'lang.getMaxCallDepth()' (default=1000 like python) and setMaxCallDepth(val) to change stack size at runtime. -- move moduleAddGlobalInternal() to var.h (also other var functions). - -- refactor build.bat batch script to powershell - refactor makefile and setup a github action. - -- floats like ".5". - - change or add => to_string() to value.as_string and add as_repr, as_bool. @@ -30,13 +26,6 @@ fn(a, b) // May be closure support? end -- Implement argparse. - - -v --version - - emit opcodes - - maybe write a similar .pyc file for pocket - - --docs to generate docs from cstring. - - dump compiled code to a file. - - In keyword. - Structs (maybe enums). - Implement file IO (require structs). @@ -52,10 +41,7 @@ - Make it possible to override function names. - To do so the functions and global variables should be in the same buffer as the property of the script. -- Function docstring property. - Union tagging alter in var. -- Github actions. - // Add more. - Single header for embedding (script in pk, require file IO). diff --git a/src/pk_compiler.c b/src/pk_compiler.c index cb79950..3614eda 100644 --- a/src/pk_compiler.c +++ b/src/pk_compiler.c @@ -1942,6 +1942,17 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) { if (fn_type != FN_NATIVE) { compileBlockBody(compiler, BLOCK_FUNC); + + // Tail call optimization disabled at debug mode. + if (compiler->options && !compiler->options->debug) { + if (compiler->is_last_call) { + ASSERT(_FN->opcodes.count >= 3, OOPS); // OP_CALL, argc, OP_POP + ASSERT(_FN->opcodes.data[_FN->opcodes.count - 1] == OP_POP, OOPS); + ASSERT(_FN->opcodes.data[_FN->opcodes.count - 3] == OP_CALL, OOPS); + _FN->opcodes.data[_FN->opcodes.count - 3] = OP_TAIL_CALL; + } + } + consume(compiler, TK_END, "Expected 'end' after function definition end."); compilerExitBlock(compiler); // Parameter depth. emitFunctionEnd(compiler); @@ -2153,6 +2164,31 @@ static int compilerImportName(Compiler* compiler, int line, UNREACHABLE(); } +// This will called by the compilerImportAll() function to import a single +// entry from the imported script. (could be a function or global variable). +static void compilerImportSingleEntry(Compiler* compiler, + const char* name, uint32_t length) { + + // Special names are begins with '$' like function body (only for now). + // Skip them. + if (name[0] == '$') return; + + // Line number of the variables which will be bind to the imported symbol. + int line = compiler->previous.line; + + // Add the name to the **current** script's name buffer. + int name_index = (int)scriptAddName(compiler->script, compiler->vm, + name, length); + + // Get the function from the script. + emitOpcode(compiler, OP_GET_ATTRIB_KEEP); + emitShort(compiler, name_index); + + int index = compilerImportName(compiler, line, name, length); + if (index != -1) emitStoreVariable(compiler, index, true); + emitOpcode(compiler, OP_POP); +} + // Import all from the script, which is also would be at the top of the stack // before executing the below instructions. static void compilerImportAll(Compiler* compiler, Script* script) { @@ -2160,65 +2196,24 @@ static void compilerImportAll(Compiler* compiler, Script* script) { ASSERT(script != NULL, OOPS); ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); - // Line number of the variables which will be bind to the imported symbol. - int line = compiler->previous.line; - - // TODO: Refactor this to a loop rather than jumping with goto. - - // !!! WARNING !!! - // - // The below code uses 'goto' statement to run same loop twice with different - // string buffer, instead of making the loop a function or writeing it twice. - // So modify the below code with caution. - bool done = false; //< A flag to jump out of the loop. pkUintBuffer* name_buff = NULL; //< The string buffer to iterate through. - goto L_first_buffer; //< Skip pass the below iteration. - // -------------------------------------------------------------------------- -L_import_all_from_buffer: - // Iterate over the names and import them. - for (uint32_t i = 0; i < name_buff->count; i++) { - String* name = script->names.data[name_buff->data[i]]; - - // Special names are begins with '$' like function body (only for now). - // Skip them. - if (name->data[0] == '$') continue; - - // Add the name to the **current** script's name buffer. - int name_index = (int)scriptAddName(compiler->script, compiler->vm, - name->data, name->length); - // Get the function from the script. - emitOpcode(compiler, OP_GET_ATTRIB_KEEP); - emitShort(compiler, name_index); - - int index = compilerImportName(compiler, line, name->data, name->length); - if (index != -1) emitStoreVariable(compiler, index, true); - emitOpcode(compiler, OP_POP); + // Import all functions. + for (uint32_t i = 0; i < script->functions.count; i++) { + const char* name = script->functions.data[i]->name; + uint32_t length = (uint32_t)strlen(name); + compilerImportSingleEntry(compiler, name, length); } - // If we have multiple buffer, we need to use an integer to keep track by - // incrementing it, But it's just 2 buffers so using a boolean 'done' here. - if (!done) { - done = true; - goto L_next_buffer; - } else { - goto L_import_done; + // Import all globals. + for (uint32_t i = 0; i < script->globals.count; i++) { + ASSERT(i < script->global_names.count, OOPS); + ASSERT(script->global_names.data[i] < script->names.count, OOPS); + const String* name = script->names.data[script->global_names.data[i]]; + + compilerImportSingleEntry(compiler, name->data, name->length); } - // -------------------------------------------------------------------------- - - // Set the buffer to function names and run the iteration. -L_first_buffer: - name_buff = &script->function_names; - goto L_import_all_from_buffer; - - // Set the buffer to global names and run the iteration. -L_next_buffer: - name_buff = &script->global_names; - goto L_import_all_from_buffer; - -L_import_done: - return; } // from module import symbol [as alias [, symbol2 [as alias]]] @@ -2488,6 +2483,9 @@ static void compileStatement(Compiler* compiler) { // print it's value when running in REPL mode. bool is_expression = false; + // If the statement is call, this will be set to true. + compiler->is_last_call = false; + if (match(compiler, TK_BREAK)) { if (compiler->loop == NULL) { parseError(compiler, "Cannot use 'break' outside a loop."); @@ -2536,6 +2534,9 @@ static void compileStatement(Compiler* compiler) { ASSERT(_FN->opcodes.count >= 2, OOPS); // OP_CALL, argc ASSERT(_FN->opcodes.data[_FN->opcodes.count - 2] == OP_CALL, OOPS); _FN->opcodes.data[_FN->opcodes.count - 2] = OP_TAIL_CALL; + + // Now it's a return statement, not call. + compiler->is_last_call = false; } } @@ -2576,6 +2577,10 @@ static void compileStatement(Compiler* compiler) { // as import statement, function define, and if we're running REPL mode top // level expression's evaluated value will be printed. static void compileTopLevelStatement(Compiler* compiler) { + + // If the statement is call, this will be set to true. + compiler->is_last_call = false; + if (match(compiler, TK_NATIVE)) { compileFunction(compiler, FN_NATIVE); @@ -2682,7 +2687,7 @@ PkResult compile(PKVM* vm, Script* script, const char* source, // If compilation failed, discard all the invalid functions and globals. if (compiler->has_errors) { script->globals.count = script->global_names.count = globals_count; - script->functions.count = script->function_names.count = functions_count; + script->functions.count = functions_count; } #if DEBUG_DUMP_COMPILED_CODE diff --git a/src/pk_core.c b/src/pk_core.c index 3042e8a..6919fb2 100644 --- a/src/pk_core.c +++ b/src/pk_core.c @@ -27,8 +27,8 @@ // A macro to declare a function, with docstring, which is defined as // _pk_doc_ = docstring; That'll used to generate function help text. -#define DEF(fn, docstring) \ - const char* DOCSTRING(fn) = docstring; \ +#define DEF(fn, docstring) \ + static const char* DOCSTRING(fn) = docstring; \ static void fn(PKVM* vm) /*****************************************************************************/ @@ -82,20 +82,6 @@ PkHandle* pkGetFunction(PKVM* vm, PkHandle* module, __ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), "Given handle is not a module"); Script* script = (Script*)AS_OBJ(scr); - // TODO: Currently it's O(n) and could be optimized to O(log(n)) but does it - // worth it? - // - // 'function_names' buffer is un-necessary since the function itself has the - // reference to the function name and it can be refactored into a index - // buffer in an "increasing-name" order which can be used to binary search. - // Similer for 'global_names' refactor them from VarBuffer to GlobalVarBuffer - // where GlobalVar is struct { const char* name, Var value }; - // - // "increasing-name" order index buffer: - // A buffer of int where each is an index in the function buffer and each - // points to different functions in an "increasing-name" (could be hash - // value) order. If we have more than some threshold number of function - // use binary search. (remember to skip literal functions). for (uint32_t i = 0; i < script->functions.count; i++) { const char* fn_name = script->functions.data[i]->name; if (strcmp(name, fn_name) == 0) { @@ -770,15 +756,11 @@ static inline void assertModuleNameDef(PKVM* vm, Script* script, static void moduleAddGlobalInternal(PKVM* vm, Script* script, const char* name, Var value) { - // Ensure the name isn't predefined. + // Ensure the name isn't defined already. assertModuleNameDef(vm, script, name); - // TODO: move this to pk_var.h and use it in the compilerAddVariable - // function. - uint32_t name_index = scriptAddName(script, vm, name, - (uint32_t)strlen(name)); - pkUintBufferWrite(&script->global_names, vm, name_index); - pkVarBufferWrite(&script->globals, vm, value); + // Add the value to the globals buffer. + scriptAddGlobal(vm, script, name, (uint32_t)strlen(name), value); } // An internal function to add a function to the given [script]. diff --git a/src/pk_debug.c b/src/pk_debug.c index 75fcbb5..40ffd1b 100644 --- a/src/pk_debug.c +++ b/src/pk_debug.c @@ -214,13 +214,12 @@ void dumpFunctionCode(PKVM* vm, Function* func, pkByteBuffer* buff) { case OP_PUSH_FN: { int fn_index = READ_BYTE(); - int name_index = func->owner->function_names.data[fn_index]; - String* name = func->owner->names.data[name_index]; + const char* name = func->owner->functions.data[fn_index]->name; // Prints: %5d [Fn:%s]\n ADD_INTEGER(vm, buff, fn_index, INT_WIDTH); pkByteBufferAddString(buff, vm, STR_AND_LEN(" [Fn:")); - pkByteBufferAddString(buff, vm, name->data, name->length); + pkByteBufferAddString(buff, vm, STR_AND_LEN(name)); pkByteBufferAddString(buff, vm, STR_AND_LEN("]\n")); break; } diff --git a/src/pk_var.c b/src/pk_var.c index 4897ddb..78de015 100644 --- a/src/pk_var.c +++ b/src/pk_var.c @@ -192,9 +192,6 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) { markFunctionBuffer(vm, &scr->functions); vm->bytes_allocated += sizeof(Function*) * scr->functions.capacity; - // Integer buffer have no gray call. - vm->bytes_allocated += sizeof(uint32_t) * scr->function_names.capacity; - markStringBuffer(vm, &scr->names); vm->bytes_allocated += sizeof(String*) * scr->names.capacity; @@ -332,7 +329,6 @@ Script* newScript(PKVM* vm, String* path) { pkUintBufferInit(&script->global_names); pkVarBufferInit(&script->literals); pkFunctionBufferInit(&script->functions); - pkUintBufferInit(&script->function_names); pkStringBufferInit(&script->names); vmPushTempRef(vm, &script->_super); @@ -358,6 +354,8 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner, Function* func = ALLOCATE(vm, Function); varInitObject(&func->_super, vm, OBJ_FUNC); + vmPushTempRef(vm, &func->_super); // func + if (owner == NULL) { ASSERT(is_native, OOPS); func->name = name; @@ -365,12 +363,8 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner, func->is_native = is_native; } else { - // Add the name in the script's function buffer. - vmPushTempRef(vm, &func->_super); pkFunctionBufferWrite(&owner->functions, vm, func); uint32_t name_index = scriptAddName(owner, vm, name, length); - pkUintBufferWrite(&owner->function_names, vm, name_index); - vmPopTempRef(vm); func->name = owner->names.data[name_index]->data; func->owner = owner; @@ -380,9 +374,9 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner, if (is_native) { func->native = NULL; + } else { Fn* fn = ALLOCATE(vm, Fn); - pkByteBufferInit(&fn->opcodes); pkUintBufferInit(&fn->oplines); fn->stack_size = 0; @@ -392,6 +386,7 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner, // Both native and script (TODO:) functions support docstring. func->docstring = docstring; + vmPopTempRef(vm); // func return func; } @@ -903,7 +898,6 @@ void freeObject(PKVM* vm, Object* self) { pkUintBufferClear(&scr->global_names, vm); pkVarBufferClear(&scr->literals, vm); pkFunctionBufferClear(&scr->functions, vm); - pkUintBufferClear(&scr->function_names, vm); pkStringBufferClear(&scr->names, vm); } break; @@ -950,11 +944,10 @@ uint32_t scriptAddName(Script* self, PKVM* vm, const char* name, } uint32_t scriptGetFunc(Script* script, const char* name, uint32_t length) { - for (uint32_t i = 0; i < script->function_names.count; i++) { - uint32_t name_index = script->function_names.data[i]; - String* fn_name = script->names.data[name_index]; - if (fn_name->length == length && - strncmp(fn_name->data, name, length) == 0) { + for (uint32_t i = 0; i < script->functions.count; i++) { + const char* fn_name = script->functions.data[i]->name; + uint32_t fn_length = (uint32_t)strlen(fn_name); + if (fn_length == length && strncmp(fn_name, name, length) == 0) { return i; } } diff --git a/src/pk_var.h b/src/pk_var.h index 94c4ef3..d970e18 100644 --- a/src/pk_var.h +++ b/src/pk_var.h @@ -273,10 +273,10 @@ struct Script { names: ["v1", "fn1", "v2", "fn2", ...] 0 1 2 3 - fn_names: [ 1, 3 ] <-- function name + g_names: [ 1, 3 ] <-- function name 0 1 <-- it's index - functions: [ fn1, fn2 ] + globals: [ fn1, fn2 ] 0 1 */ @@ -285,8 +285,8 @@ struct Script { pkVarBuffer globals; //< Script level global variables. pkUintBuffer global_names; //< Name map to index in globals. + pkFunctionBuffer functions; //< Script level functions. - pkUintBuffer function_names; //< Name map to index in functions. pkStringBuffer names; //< Name literals, attribute names, etc. pkVarBuffer literals; //< Script literal constant values. @@ -299,7 +299,7 @@ struct Script { typedef struct { pkByteBuffer opcodes; //< Buffer of opcodes. pkUintBuffer oplines; //< Line number of opcodes for debug (1 based). - int stack_size; //< Maximum size of stack required. + int stack_size; //< Maximum size of stack required. } Fn; struct Function { diff --git a/src/pk_vm.c b/src/pk_vm.c index 1044440..94e8eaf 100644 --- a/src/pk_vm.c +++ b/src/pk_vm.c @@ -526,26 +526,27 @@ static inline void growStack(PKVM* vm, int size) { } } -static inline void pushCallFrame(PKVM* vm, const Function* fn) { - ASSERT(!fn->is_native, "Native function shouldn't use call frames."); +static inline void pushCallFrame(PKVM* vm, const Function* fn, Var* rbp) { + ASSERT(!fn->is_native, "Native function shouldn't use call frames."); - // Grow the stack frame if needed. - if (vm->fiber->frame_count + 1 > vm->fiber->frame_capacity) { - int new_capacity = vm->fiber->frame_capacity << 1; - vm->fiber->frames = (CallFrame*)vmRealloc(vm, vm->fiber->frames, - sizeof(CallFrame) * vm->fiber->frame_capacity, - sizeof(CallFrame) * new_capacity); - vm->fiber->frame_capacity = new_capacity; - } + // Grow the stack frame if needed. + if (vm->fiber->frame_count + 1 > vm->fiber->frame_capacity) { + int new_capacity = vm->fiber->frame_capacity << 1; + vm->fiber->frames = (CallFrame*)vmRealloc(vm, vm->fiber->frames, + sizeof(CallFrame) * vm->fiber->frame_capacity, + sizeof(CallFrame) * new_capacity); + vm->fiber->frame_capacity = new_capacity; + } - // Grow the stack if needed. - int needed = fn->fn->stack_size + (int)(vm->fiber->sp - vm->fiber->stack); - if (vm->fiber->stack_size <= needed) growStack(vm, needed); + // Grow the stack if needed. + int needed = fn->fn->stack_size + (int)(vm->fiber->sp - vm->fiber->stack); + if (vm->fiber->stack_size <= needed) growStack(vm, needed); - CallFrame* frame = vm->fiber->frames + vm->fiber->frame_count++; - frame->rbp = vm->fiber->ret; - frame->fn = fn; - frame->ip = fn->fn->opcodes.data; + CallFrame* frame = vm->fiber->frames + vm->fiber->frame_count++; + *rbp = VAR_NULL; + frame->rbp = rbp; + frame->fn = fn; + frame->ip = fn->fn->opcodes.data; } static inline void reuseCallFrame(PKVM* vm, const Function* fn) { @@ -556,9 +557,15 @@ static inline void reuseCallFrame(PKVM* vm, const Function* fn) { Fiber* fb = vm->fiber; + CallFrame* frame = fb->frames + fb->frame_count - 1; + frame->fn = fn; + frame->ip = fn->fn->opcodes.data; + + ASSERT(*frame->rbp == VAR_NULL, OOPS); + // Move all the argument(s) to the base of the current frame. Var* arg = fb->sp - fn->arity; - Var* target = fb->ret + 1; + Var* target = frame->rbp + 1; for (; arg < fb->sp; arg++, target++) { *target = *arg; } @@ -569,11 +576,6 @@ static inline void reuseCallFrame(PKVM* vm, const Function* fn) { // Grow the stack if needed (least probably). int needed = fn->fn->stack_size + (int)(vm->fiber->sp - vm->fiber->stack); if (vm->fiber->stack_size <= needed) growStack(vm, needed); - - CallFrame* frame = vm->fiber->frames + vm->fiber->frame_count - 1; - ASSERT(frame->rbp == fb->ret, OOPS); - frame->fn = fn; - frame->ip = fn->fn->opcodes.data; } static void reportError(PKVM* vm) { @@ -901,10 +903,6 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) { if (fn->is_native) { - // Next call frame starts here. (including return value). - call_fiber->ret = callable; - *(call_fiber->ret) = VAR_NULL; //< Set the return value to null. - if (fn->native == NULL) { RUNTIME_ERROR(stringFormat(vm, "Native function pointer of $ was NULL.", fn->name)); @@ -913,6 +911,10 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) { // Update the current frame's ip. UPDATE_FRAME(); + // Next call frame starts here. (including return value). + call_fiber->ret = callable; + *(call_fiber->ret) = VAR_NULL; //< Set the return value to null. + fn->native(vm); //< Call the native function. // Calling yield() will change vm->fiber to it's caller fiber, which @@ -931,12 +933,8 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) { } else { if (instruction == OP_CALL) { - // Next call frame starts here. (including return value). - call_fiber->ret = callable; - *(call_fiber->ret) = VAR_NULL; //< Set the return value to null. - UPDATE_FRAME(); //< Update the current frame's ip. - pushCallFrame(vm, fn); + pushCallFrame(vm, fn, callable); LOAD_FRAME(); //< Load the top frame to vm's execution variables. } else {