mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-06 04:37:47 +08:00
yet another minor refactor
This commit is contained in:
parent
19e8733b9c
commit
258b64948e
@ -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 */
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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).
|
||||||
|
@ -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
|
||||||
|
@ -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].
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
23
src/pk_var.c
23
src/pk_var.c
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
32
src/pk_vm.c
32
src/pk_vm.c
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user