yet another minor refactor

This commit is contained in:
Thakee Nathees 2021-06-20 15:53:21 +05:30
parent 19e8733b9c
commit 258b64948e
14 changed files with 140 additions and 173 deletions

View File

@ -17,7 +17,7 @@
// Doc : https://likle.github.io/cwalk/ // Doc : https://likle.github.io/cwalk/
// About : Path library for C/C++. Cross-Platform for Windows, MacOS and // About : Path library for C/C++. Cross-Platform for Windows, MacOS and
// Linux. Supports UNIX and Windows path styles on those platforms. // Linux. Supports UNIX and Windows path styles on those platforms.
#include "thirdparty/cwalk/cwalk.c" #include "modules/thirdparty/cwalk/cwalk.c"
/*****************************************************************************/ /*****************************************************************************/
/* CLI MODULES */ /* CLI MODULES */

View File

@ -7,12 +7,9 @@
#include <pocketlang.h> #include <pocketlang.h>
#include <stdio.h> /* defines FILENAME_MAX */ #include <stdio.h> /* defines FILENAME_MAX */
// TODO: more cli/thirdparty to cli/modules/thirdparty to remove ".." in the #include "thirdparty/cwalk/cwalk.h"
// relative import and split thirdparty sources into dependent directory.
#include "../thirdparty/cwalk/cwalk.h"
#if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__)) #if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__))
#include "../thirdparty/dirent/dirent.h" #include "thirdparty/dirent/dirent.h"
#else #else
#include <dirent.h> #include <dirent.h>
#endif #endif
@ -26,9 +23,6 @@
#define get_cwd getcwd #define get_cwd getcwd
#endif #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. // TODO: this macros should be moved to a general place of in cli.
#define TOSTRING(x) #x #define TOSTRING(x) #x
#define STRINGIFY(x) TOSTRING(x) #define STRINGIFY(x) TOSTRING(x)
@ -77,7 +71,7 @@ static inline bool pathIsDirectoryExists(const char* path) {
if (dir) { /* Directory exists. */ if (dir) { /* Directory exists. */
closedir(dir); closedir(dir);
return true; 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. */ } else { /* opendir() failed for some other reason. */
} }
@ -88,6 +82,17 @@ static inline bool pathIsExists(const char* path) {
return pathIsFileExists(path) || pathIsDirectoryExists(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 */ /* MODULE FUNCTIONS */
/*****************************************************************************/ /*****************************************************************************/
@ -100,7 +105,9 @@ static void _pathSetStyleUnix(PKVM* vm) {
static void _pathGetCWD(PKVM* vm) { static void _pathGetCWD(PKVM* vm) {
char cwd[FILENAME_MAX]; 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); pkReturnString(vm, cwd);
} }
@ -108,11 +115,8 @@ static void _pathAbspath(PKVM* vm) {
const char* path; const char* path;
if (!pkGetArgString(vm, 1, &path)) return; if (!pkGetArgString(vm, 1, &path)) return;
char cwd[FILENAME_MAX];
get_cwd(cwd, sizeof(cwd)); // Check if res is NULL.
char abspath[FILENAME_MAX]; 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); pkReturnStringLength(vm, abspath, len);
} }
@ -121,15 +125,15 @@ static void _pathRelpath(PKVM* vm) {
if (!pkGetArgString(vm, 1, &from)) return; if (!pkGetArgString(vm, 1, &from)) return;
if (!pkGetArgString(vm, 2, &path)) return; if (!pkGetArgString(vm, 2, &path)) return;
// TODO: this won't work if both [from] and [path] doen't have a similler char abs_from[FILENAME_MAX];
// root path, so we need to get the absolute path of the both paths (if size_t len_from = pathAbs(from, abs_from, sizeof(abs_from));
// thre're not already) and call the cwalk_relative().
// ie. char abs_path[FILENAME_MAX];
// a/b/c --> a/b/d.txt - works size_t len_path = pathAbs(path, abs_path, sizeof(abs_path));
// a/b/c --> ../d.txt - won't work
char result[FILENAME_MAX]; 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); pkReturnStringLength(vm, result, len);
} }

View File

@ -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. // To implement.
- Refactor fiber into a module and is_done as an attribute.
- def f(x) - def f(x)
f(x) ## not tco, unless return f(x) f(x) ## not tco, unless return f(x)
end end
@ -11,13 +14,6 @@
- implement 'lang.getMaxCallDepth()' (default=1000 like python) and - implement 'lang.getMaxCallDepth()' (default=1000 like python) and
setMaxCallDepth(val) to change stack size at runtime. 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 - change or add => to_string() to value.as_string
and add as_repr, as_bool. and add as_repr, as_bool.
@ -30,13 +26,6 @@
fn(a, b) // May be closure support? fn(a, b) // May be closure support?
end 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. - In keyword.
- Structs (maybe enums). - Structs (maybe enums).
- Implement file IO (require structs). - Implement file IO (require structs).
@ -52,10 +41,7 @@
- Make it possible to override function names. - Make it possible to override function names.
- To do so the functions and global variables should be in the same - To do so the functions and global variables should be in the same
buffer as the property of the script. buffer as the property of the script.
- Function docstring property.
- Union tagging alter in var. - Union tagging alter in var.
- Github actions.
// Add more. // Add more.
- Single header for embedding (script in pk, require file IO). - Single header for embedding (script in pk, require file IO).

View File

@ -1942,6 +1942,17 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) {
if (fn_type != FN_NATIVE) { if (fn_type != FN_NATIVE) {
compileBlockBody(compiler, BLOCK_FUNC); 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."); consume(compiler, TK_END, "Expected 'end' after function definition end.");
compilerExitBlock(compiler); // Parameter depth. compilerExitBlock(compiler); // Parameter depth.
emitFunctionEnd(compiler); emitFunctionEnd(compiler);
@ -2153,6 +2164,31 @@ static int compilerImportName(Compiler* compiler, int line,
UNREACHABLE(); 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 // Import all from the script, which is also would be at the top of the stack
// before executing the below instructions. // before executing the below instructions.
static void compilerImportAll(Compiler* compiler, Script* script) { static void compilerImportAll(Compiler* compiler, Script* script) {
@ -2160,65 +2196,24 @@ static void compilerImportAll(Compiler* compiler, Script* script) {
ASSERT(script != NULL, OOPS); ASSERT(script != NULL, OOPS);
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, 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. bool done = false; //< A flag to jump out of the loop.
pkUintBuffer* name_buff = NULL; //< The string buffer to iterate through. pkUintBuffer* name_buff = NULL; //< The string buffer to iterate through.
goto L_first_buffer; //< Skip pass the below iteration.
// -------------------------------------------------------------------------- // Import all functions.
L_import_all_from_buffer: for (uint32_t i = 0; i < script->functions.count; i++) {
// Iterate over the names and import them. const char* name = script->functions.data[i]->name;
for (uint32_t i = 0; i < name_buff->count; i++) { uint32_t length = (uint32_t)strlen(name);
String* name = script->names.data[name_buff->data[i]]; compilerImportSingleEntry(compiler, name, length);
// 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);
} }
// If we have multiple buffer, we need to use an integer to keep track by // Import all globals.
// incrementing it, But it's just 2 buffers so using a boolean 'done' here. for (uint32_t i = 0; i < script->globals.count; i++) {
if (!done) { ASSERT(i < script->global_names.count, OOPS);
done = true; ASSERT(script->global_names.data[i] < script->names.count, OOPS);
goto L_next_buffer; const String* name = script->names.data[script->global_names.data[i]];
} else {
goto L_import_done; 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]]] // 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. // print it's value when running in REPL mode.
bool is_expression = false; 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 (match(compiler, TK_BREAK)) {
if (compiler->loop == NULL) { if (compiler->loop == NULL) {
parseError(compiler, "Cannot use 'break' outside a loop."); 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.count >= 2, OOPS); // OP_CALL, argc
ASSERT(_FN->opcodes.data[_FN->opcodes.count - 2] == OP_CALL, OOPS); ASSERT(_FN->opcodes.data[_FN->opcodes.count - 2] == OP_CALL, OOPS);
_FN->opcodes.data[_FN->opcodes.count - 2] = OP_TAIL_CALL; _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 // as import statement, function define, and if we're running REPL mode top
// level expression's evaluated value will be printed. // level expression's evaluated value will be printed.
static void compileTopLevelStatement(Compiler* compiler) { 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)) { if (match(compiler, TK_NATIVE)) {
compileFunction(compiler, FN_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 compilation failed, discard all the invalid functions and globals.
if (compiler->has_errors) { if (compiler->has_errors) {
script->globals.count = script->global_names.count = globals_count; 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 #if DEBUG_DUMP_COMPILED_CODE

View File

@ -28,7 +28,7 @@
// A macro to declare a function, with docstring, which is defined as // A macro to declare a function, with docstring, which is defined as
// _pk_doc_<fn> = docstring; That'll used to generate function help text. // _pk_doc_<fn> = docstring; That'll used to generate function help text.
#define DEF(fn, docstring) \ #define DEF(fn, docstring) \
const char* DOCSTRING(fn) = docstring; \ static const char* DOCSTRING(fn) = docstring; \
static void fn(PKVM* vm) 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"); __ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), "Given handle is not a module");
Script* script = (Script*)AS_OBJ(scr); 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++) { for (uint32_t i = 0; i < script->functions.count; i++) {
const char* fn_name = script->functions.data[i]->name; const char* fn_name = script->functions.data[i]->name;
if (strcmp(name, fn_name) == 0) { 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, static void moduleAddGlobalInternal(PKVM* vm, Script* script,
const char* name, Var value) { const char* name, Var value) {
// Ensure the name isn't predefined. // Ensure the name isn't defined already.
assertModuleNameDef(vm, script, name); assertModuleNameDef(vm, script, name);
// TODO: move this to pk_var.h and use it in the compilerAddVariable // Add the value to the globals buffer.
// function. scriptAddGlobal(vm, script, name, (uint32_t)strlen(name), value);
uint32_t name_index = scriptAddName(script, vm, name,
(uint32_t)strlen(name));
pkUintBufferWrite(&script->global_names, vm, name_index);
pkVarBufferWrite(&script->globals, vm, value);
} }
// An internal function to add a function to the given [script]. // An internal function to add a function to the given [script].

View File

@ -214,13 +214,12 @@ void dumpFunctionCode(PKVM* vm, Function* func, pkByteBuffer* buff) {
case OP_PUSH_FN: case OP_PUSH_FN:
{ {
int fn_index = READ_BYTE(); int fn_index = READ_BYTE();
int name_index = func->owner->function_names.data[fn_index]; const char* name = func->owner->functions.data[fn_index]->name;
String* name = func->owner->names.data[name_index];
// Prints: %5d [Fn:%s]\n // Prints: %5d [Fn:%s]\n
ADD_INTEGER(vm, buff, fn_index, INT_WIDTH); ADD_INTEGER(vm, buff, fn_index, INT_WIDTH);
pkByteBufferAddString(buff, vm, STR_AND_LEN(" [Fn:")); 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")); pkByteBufferAddString(buff, vm, STR_AND_LEN("]\n"));
break; break;
} }

View File

@ -192,9 +192,6 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
markFunctionBuffer(vm, &scr->functions); markFunctionBuffer(vm, &scr->functions);
vm->bytes_allocated += sizeof(Function*) * scr->functions.capacity; 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); markStringBuffer(vm, &scr->names);
vm->bytes_allocated += sizeof(String*) * scr->names.capacity; vm->bytes_allocated += sizeof(String*) * scr->names.capacity;
@ -332,7 +329,6 @@ Script* newScript(PKVM* vm, String* path) {
pkUintBufferInit(&script->global_names); pkUintBufferInit(&script->global_names);
pkVarBufferInit(&script->literals); pkVarBufferInit(&script->literals);
pkFunctionBufferInit(&script->functions); pkFunctionBufferInit(&script->functions);
pkUintBufferInit(&script->function_names);
pkStringBufferInit(&script->names); pkStringBufferInit(&script->names);
vmPushTempRef(vm, &script->_super); vmPushTempRef(vm, &script->_super);
@ -358,6 +354,8 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner,
Function* func = ALLOCATE(vm, Function); Function* func = ALLOCATE(vm, Function);
varInitObject(&func->_super, vm, OBJ_FUNC); varInitObject(&func->_super, vm, OBJ_FUNC);
vmPushTempRef(vm, &func->_super); // func
if (owner == NULL) { if (owner == NULL) {
ASSERT(is_native, OOPS); ASSERT(is_native, OOPS);
func->name = name; func->name = name;
@ -365,12 +363,8 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner,
func->is_native = is_native; func->is_native = is_native;
} else { } else {
// Add the name in the script's function buffer.
vmPushTempRef(vm, &func->_super);
pkFunctionBufferWrite(&owner->functions, vm, func); pkFunctionBufferWrite(&owner->functions, vm, func);
uint32_t name_index = scriptAddName(owner, vm, name, length); 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->name = owner->names.data[name_index]->data;
func->owner = owner; func->owner = owner;
@ -380,9 +374,9 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner,
if (is_native) { if (is_native) {
func->native = NULL; func->native = NULL;
} else { } else {
Fn* fn = ALLOCATE(vm, Fn); Fn* fn = ALLOCATE(vm, Fn);
pkByteBufferInit(&fn->opcodes); pkByteBufferInit(&fn->opcodes);
pkUintBufferInit(&fn->oplines); pkUintBufferInit(&fn->oplines);
fn->stack_size = 0; 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. // Both native and script (TODO:) functions support docstring.
func->docstring = docstring; func->docstring = docstring;
vmPopTempRef(vm); // func
return func; return func;
} }
@ -903,7 +898,6 @@ void freeObject(PKVM* vm, Object* self) {
pkUintBufferClear(&scr->global_names, vm); pkUintBufferClear(&scr->global_names, vm);
pkVarBufferClear(&scr->literals, vm); pkVarBufferClear(&scr->literals, vm);
pkFunctionBufferClear(&scr->functions, vm); pkFunctionBufferClear(&scr->functions, vm);
pkUintBufferClear(&scr->function_names, vm);
pkStringBufferClear(&scr->names, vm); pkStringBufferClear(&scr->names, vm);
} break; } 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) { uint32_t scriptGetFunc(Script* script, const char* name, uint32_t length) {
for (uint32_t i = 0; i < script->function_names.count; i++) { for (uint32_t i = 0; i < script->functions.count; i++) {
uint32_t name_index = script->function_names.data[i]; const char* fn_name = script->functions.data[i]->name;
String* fn_name = script->names.data[name_index]; uint32_t fn_length = (uint32_t)strlen(fn_name);
if (fn_name->length == length && if (fn_length == length && strncmp(fn_name, name, length) == 0) {
strncmp(fn_name->data, name, length) == 0) {
return i; return i;
} }
} }

View File

@ -273,10 +273,10 @@ struct Script {
names: ["v1", "fn1", "v2", "fn2", ...] names: ["v1", "fn1", "v2", "fn2", ...]
0 1 2 3 0 1 2 3
fn_names: [ 1, 3 ] <-- function name g_names: [ 1, 3 ] <-- function name
0 1 <-- it's index 0 1 <-- it's index
functions: [ fn1, fn2 ] globals: [ fn1, fn2 ]
0 1 0 1
*/ */
@ -285,8 +285,8 @@ struct Script {
pkVarBuffer globals; //< Script level global variables. pkVarBuffer globals; //< Script level global variables.
pkUintBuffer global_names; //< Name map to index in globals. pkUintBuffer global_names; //< Name map to index in globals.
pkFunctionBuffer functions; //< Script level functions. pkFunctionBuffer functions; //< Script level functions.
pkUintBuffer function_names; //< Name map to index in functions.
pkStringBuffer names; //< Name literals, attribute names, etc. pkStringBuffer names; //< Name literals, attribute names, etc.
pkVarBuffer literals; //< Script literal constant values. pkVarBuffer literals; //< Script literal constant values.

View File

@ -526,7 +526,7 @@ static inline void growStack(PKVM* vm, int size) {
} }
} }
static inline void pushCallFrame(PKVM* vm, const Function* fn) { static inline void pushCallFrame(PKVM* vm, const Function* fn, Var* rbp) {
ASSERT(!fn->is_native, "Native function shouldn't use call frames."); ASSERT(!fn->is_native, "Native function shouldn't use call frames.");
// Grow the stack frame if needed. // Grow the stack frame if needed.
@ -543,7 +543,8 @@ static inline void pushCallFrame(PKVM* vm, const Function* fn) {
if (vm->fiber->stack_size <= needed) growStack(vm, needed); if (vm->fiber->stack_size <= needed) growStack(vm, needed);
CallFrame* frame = vm->fiber->frames + vm->fiber->frame_count++; CallFrame* frame = vm->fiber->frames + vm->fiber->frame_count++;
frame->rbp = vm->fiber->ret; *rbp = VAR_NULL;
frame->rbp = rbp;
frame->fn = fn; frame->fn = fn;
frame->ip = fn->fn->opcodes.data; frame->ip = fn->fn->opcodes.data;
} }
@ -556,9 +557,15 @@ static inline void reuseCallFrame(PKVM* vm, const Function* fn) {
Fiber* fb = vm->fiber; 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. // Move all the argument(s) to the base of the current frame.
Var* arg = fb->sp - fn->arity; Var* arg = fb->sp - fn->arity;
Var* target = fb->ret + 1; Var* target = frame->rbp + 1;
for (; arg < fb->sp; arg++, target++) { for (; arg < fb->sp; arg++, target++) {
*target = *arg; *target = *arg;
} }
@ -569,11 +576,6 @@ static inline void reuseCallFrame(PKVM* vm, const Function* fn) {
// Grow the stack if needed (least probably). // Grow the stack if needed (least probably).
int needed = fn->fn->stack_size + (int)(vm->fiber->sp - vm->fiber->stack); int needed = fn->fn->stack_size + (int)(vm->fiber->sp - vm->fiber->stack);
if (vm->fiber->stack_size <= needed) growStack(vm, needed); 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) { static void reportError(PKVM* vm) {
@ -901,10 +903,6 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
if (fn->is_native) { 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) { if (fn->native == NULL) {
RUNTIME_ERROR(stringFormat(vm, RUNTIME_ERROR(stringFormat(vm,
"Native function pointer of $ was NULL.", fn->name)); "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 the current frame's ip.
UPDATE_FRAME(); 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. fn->native(vm); //< Call the native function.
// Calling yield() will change vm->fiber to it's caller fiber, which // Calling yield() will change vm->fiber to it's caller fiber, which
@ -931,12 +933,8 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
} else { } else {
if (instruction == OP_CALL) { 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. 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. LOAD_FRAME(); //< Load the top frame to vm's execution variables.
} else { } else {