mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-05 20:26:53 +08:00
names buffer merged with constant pool (#202)
a buffer of classes for primitive types added to PKVM, but they'll not be initialized in this commit. names buffer and constant pool of a module are now merged (just like java's constant pool). VM's core libraries and scirpt modules are merged into a single map name modules. creating a new module doesn't register it automatically anymore, you need to call pkRegisterModule(...) each time. newModule() function refactored with a simpler interface, we're not setting path or registering globals anymore, the caller is responsible for that.
This commit is contained in:
parent
f980e91b60
commit
c67572d552
14
cli/all.c
14
cli/all.c
@ -23,6 +23,7 @@
|
||||
/*****************************************************************************/
|
||||
|
||||
// Library : cwalk
|
||||
// License : MIT
|
||||
// Source : https://github.com/likle/cwalk/
|
||||
// Doc : https://likle.github.io/cwalk/
|
||||
// About : Path library for C/C++. Cross-Platform for Windows, MacOS and
|
||||
@ -30,6 +31,19 @@
|
||||
#include "modules/thirdparty/cwalk/cwalk.c"
|
||||
|
||||
// Library : argparse
|
||||
// License : MIT
|
||||
// Source : https://github.com/cofyc/argparse/
|
||||
// About : Command-line arguments parsing library.
|
||||
#include "thirdparty/argparse/argparse.c"
|
||||
|
||||
// Library : dlfcn-win32
|
||||
// License : MIT
|
||||
// Source : https://github.com/dlfcn-win32/dlfcn-win32/
|
||||
// About : An implementation of dlfcn for Windows.
|
||||
#ifdef _WIN32
|
||||
// FIXME:
|
||||
// This library redefine the malloc family macro, which cause a compile
|
||||
// time warning.
|
||||
//
|
||||
// #include "modules/thirdparty/dlfcn-win32/dlfcn.c"
|
||||
#endif
|
||||
|
@ -141,5 +141,6 @@ void registerModuleFile(PKVM* vm) {
|
||||
pkModuleAddFunction(vm, file, "write", _fileWrite, 2);
|
||||
pkModuleAddFunction(vm, file, "close", _fileClose, 1);
|
||||
|
||||
pkRegisterModule(vm, file);
|
||||
pkReleaseHandle(vm, file);
|
||||
}
|
||||
|
@ -233,5 +233,6 @@ void registerModulePath(PKVM* vm) {
|
||||
pkModuleAddFunction(vm, path, "isfile", _pathIsFile, 1);
|
||||
pkModuleAddFunction(vm, path, "isdir", _pathIsDir, 1);
|
||||
|
||||
pkRegisterModule(vm, path);
|
||||
pkReleaseHandle(vm, path);
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ PK_API = "pk_api"
|
||||
PK_API_TYPE = "PkNativeApi"
|
||||
API_DEF = f'''\
|
||||
static {PK_API_TYPE} {PK_API};
|
||||
|
||||
void pkInitApi({PK_API_TYPE}* api) {{%s
|
||||
}}
|
||||
'''
|
||||
|
3
cli/thirdparty/argparse/argparse.c
vendored
3
cli/thirdparty/argparse/argparse.c
vendored
@ -102,7 +102,8 @@ argparse_getvalue(struct argparse *self, const struct argparse_option *opt,
|
||||
errno = 0;
|
||||
if (self->optvalue) {
|
||||
// -- pocketlang start --
|
||||
// Not sure why but tcc cause an error "tcc: error: undefined symbol 'strtof'".
|
||||
// tcc cause an error "tcc: error: undefined symbol 'strtof'" on Windows since
|
||||
// it depend on the libm. Maybe I should add _WIN32 marcro along with it.
|
||||
#if defined(__TINYC__)
|
||||
*(float*)opt->value = (float)strtod(self->optvalue, (char**)&s);
|
||||
#else
|
||||
|
@ -426,6 +426,10 @@ PK_PUBLIC PkHandle* pkNewMap(PKVM* vm);
|
||||
// already existed, otherwise an assertion will fail to indicate that.
|
||||
PK_PUBLIC PkHandle* pkNewModule(PKVM* vm, const char* name);
|
||||
|
||||
// Register the module to the PKVM's modules map, once after it can be
|
||||
// imported in other modules.
|
||||
PK_PUBLIC void pkRegisterModule(PKVM* vm, PkHandle* module);
|
||||
|
||||
// Create and return a new fiber around the function [fn].
|
||||
PK_PUBLIC PkHandle* pkNewFiber(PKVM* vm, PkHandle* fn);
|
||||
|
||||
|
@ -1931,8 +1931,9 @@ static void exprAttrib(Compiler* compiler) {
|
||||
int length = compiler->parser.previous.length;
|
||||
|
||||
// Store the name in module's names buffer.
|
||||
int index = moduleAddName(compiler->module, compiler->parser.vm,
|
||||
name, length);
|
||||
int index = 0;
|
||||
moduleAddString(compiler->module, compiler->parser.vm,
|
||||
name, length, &index);
|
||||
|
||||
if (compiler->l_value && matchAssignment(compiler)) {
|
||||
TokenType assignment = compiler->parser.previous.type;
|
||||
@ -2319,12 +2320,14 @@ static void compileClass(Compiler* compiler) {
|
||||
const char* f_name = compiler->parser.previous.start;
|
||||
int f_len = compiler->parser.previous.length;
|
||||
|
||||
uint32_t f_index = moduleAddName(compiler->module, compiler->parser.vm,
|
||||
f_name, f_len);
|
||||
int f_index = 0;
|
||||
String* new_name = moduleAddString(compiler->module, compiler->parser.vm,
|
||||
f_name, f_len, &f_index);
|
||||
|
||||
String* new_name = compiler->module->names.data[f_index];
|
||||
for (uint32_t i = 0; i < cls->field_names.count; i++) {
|
||||
String* prev = compiler->module->names.data[cls->field_names.data[i]];
|
||||
String* prev = moduleGetStringAt(compiler->module,
|
||||
cls->field_names.data[i]);
|
||||
ASSERT(prev != NULL, OOPS);
|
||||
if (IS_STR_EQ(new_name, prev)) {
|
||||
parseError(compiler, "Class field with name '%s' already exists.",
|
||||
new_name->data);
|
||||
@ -2519,13 +2522,15 @@ static Module* importFile(Compiler* compiler, const char* path) {
|
||||
}
|
||||
|
||||
// Create new string for the resolved path. And free the resolved path.
|
||||
int index = (int)moduleAddName(compiler->module, compiler->parser.vm,
|
||||
resolved.string, (uint32_t)strlen(resolved.string));
|
||||
String* path_name = compiler->module->names.data[index];
|
||||
int index = 0;
|
||||
String* path_ = moduleAddString(compiler->module, compiler->parser.vm,
|
||||
resolved.string,
|
||||
(uint32_t)strlen(resolved.string),
|
||||
&index);
|
||||
if (resolved.on_done != NULL) resolved.on_done(vm, resolved);
|
||||
|
||||
// Check if the script already compiled and cached in the PKVM.
|
||||
Var entry = mapGet(vm->modules, VAR_OBJ(path_name));
|
||||
Var entry = mapGet(vm->modules, VAR_OBJ(path_));
|
||||
if (!IS_UNDEF(entry)) {
|
||||
ASSERT(IS_OBJ_TYPE(entry, OBJ_MODULE), OOPS);
|
||||
|
||||
@ -2544,17 +2549,29 @@ static Module* importFile(Compiler* compiler, const char* path) {
|
||||
}
|
||||
|
||||
// Load the script at the path.
|
||||
PkStringPtr source = vm->config.load_script_fn(vm, path_name->data);
|
||||
PkStringPtr source = vm->config.load_script_fn(vm, path_->data);
|
||||
if (source.string == NULL) {
|
||||
parseError(compiler, "Error loading script at \"%s\"", path_name->data);
|
||||
parseError(compiler, "Error loading script at \"%s\"", path_->data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Make a new module and to compile it.
|
||||
Module* module = newModule(vm, path_name, false);
|
||||
vmPushTempRef(vm, &module->_super); // scr.
|
||||
mapSet(vm, vm->modules, VAR_OBJ(path_name), VAR_OBJ(module));
|
||||
vmPopTempRef(vm); // scr.
|
||||
Module* module = newModule(vm);
|
||||
module->path = path_;
|
||||
vmPushTempRef(vm, &module->_super); // module.
|
||||
{
|
||||
moduleAddMain(vm, module);
|
||||
|
||||
// Add '__file__' variable with it's path as value. If the path starts with
|
||||
// '@' It's a special file (@(REPL) or @(TRY)) and don't define __file__.
|
||||
if (module->path->data[0] != SPECIAL_NAME_CHAR) {
|
||||
moduleAddGlobal(vm, module, "__file__", 8, VAR_OBJ(module->path));
|
||||
}
|
||||
// TODO: Add ARGV to the module's globals.
|
||||
|
||||
vmRegisterModule(vm, module, path_);
|
||||
}
|
||||
vmPopTempRef(vm); // module.
|
||||
|
||||
// Push the compiled script on the stack.
|
||||
emitOpcode(compiler, OP_IMPORT);
|
||||
@ -2572,7 +2589,7 @@ static Module* importFile(Compiler* compiler, const char* path) {
|
||||
|
||||
if (result != PK_RESULT_SUCCESS) {
|
||||
parseError(compiler, "Compilation of imported script '%s' failed",
|
||||
path_name->data);
|
||||
path_->data);
|
||||
}
|
||||
|
||||
return module;
|
||||
@ -2586,12 +2603,12 @@ static Module* importCoreLib(Compiler* compiler, const char* name_start,
|
||||
|
||||
// Add the name to the module's name buffer, we need it as a key to the
|
||||
// PKVM's module cache.
|
||||
int index = (int)moduleAddName(compiler->module, compiler->parser.vm,
|
||||
name_start, name_length);
|
||||
String* module_name = compiler->module->names.data[index];
|
||||
int index = 0;
|
||||
String* module_name = moduleAddString(compiler->module, compiler->parser.vm,
|
||||
name_start, name_length, &index);
|
||||
|
||||
Var entry = mapGet(compiler->parser.vm->core_libs, VAR_OBJ(module_name));
|
||||
if (IS_UNDEF(entry)) {
|
||||
Module* imported = vmGetModule(compiler->parser.vm, module_name);
|
||||
if (imported == NULL) {
|
||||
parseError(compiler, "No module named '%s' exists.", module_name->data);
|
||||
return NULL;
|
||||
}
|
||||
@ -2600,8 +2617,7 @@ static Module* importCoreLib(Compiler* compiler, const char* name_start,
|
||||
emitOpcode(compiler, OP_IMPORT);
|
||||
emitShort(compiler, index);
|
||||
|
||||
ASSERT(IS_OBJ_TYPE(entry, OBJ_MODULE), OOPS);
|
||||
return (Module*)AS_OBJ(entry);
|
||||
return imported;
|
||||
}
|
||||
|
||||
// Push the imported module on the stack and return the pointer. It could be
|
||||
@ -2672,8 +2688,9 @@ static void compilerImportSingleEntry(Compiler* compiler,
|
||||
int line = compiler->parser.previous.line;
|
||||
|
||||
// Add the name to the **current** module's name buffer.
|
||||
int name_index = (int)moduleAddName(compiler->module, compiler->parser.vm,
|
||||
name, length);
|
||||
int name_index = 0;
|
||||
moduleAddString(compiler->module, compiler->parser.vm,
|
||||
name, length, &name_index);
|
||||
|
||||
// Get the global/function/class from the module.
|
||||
emitOpcode(compiler, OP_GET_ATTRIB_KEEP);
|
||||
@ -2694,9 +2711,10 @@ static void compilerImportAll(Compiler* compiler, Module* module) {
|
||||
// Import all globals.
|
||||
ASSERT(module->global_names.count == module->globals.count, OOPS);
|
||||
for (uint32_t i = 0; i < module->globals.count; i++) {
|
||||
ASSERT(module->global_names.data[i] < module->names.count, OOPS);
|
||||
const String* name = module->names.data[module->global_names.data[i]];
|
||||
|
||||
String* name = moduleGetStringAt(module, module->global_names.data[i]);
|
||||
ASSERT(name != NULL, OOPS);
|
||||
// If a name starts with '_' we treat it as private and not importing.
|
||||
if (name->length >= 1 && name->data[0] == '_') continue;
|
||||
compilerImportSingleEntry(compiler, name->data, name->length);
|
||||
}
|
||||
}
|
||||
@ -2726,9 +2744,9 @@ static void compileFromImport(Compiler* compiler) {
|
||||
int line = compiler->parser.previous.line;
|
||||
|
||||
// Add the name of the symbol to the names buffer.
|
||||
int name_index = (int)moduleAddName(compiler->module,
|
||||
compiler->parser.vm,
|
||||
name, length);
|
||||
int name_index = 0;
|
||||
moduleAddString(compiler->module, compiler->parser.vm,
|
||||
name, length, &name_index);
|
||||
|
||||
// Don't pop the lib since it'll be used for the next entry.
|
||||
emitOpcode(compiler, OP_GET_ATTRIB_KEEP);
|
||||
@ -3122,7 +3140,6 @@ PkResult compile(PKVM* vm, Module* module, const char* source,
|
||||
// Remember the count of constants, names, and globals, If the compilation
|
||||
// failed discard all of them and roll back.
|
||||
uint32_t constants_count = module->constants.count;
|
||||
uint32_t names_count = module->names.count;
|
||||
uint32_t globals_count = module->globals.count;
|
||||
|
||||
Func curr_fn;
|
||||
@ -3184,7 +3201,6 @@ PkResult compile(PKVM* vm, Module* module, const char* source,
|
||||
// If compilation failed, discard all the invalid functions and globals.
|
||||
if (compiler->parser.has_errors) {
|
||||
module->constants.count = constants_count;
|
||||
module->names.count = names_count;
|
||||
module->globals.count = module->global_names.count = globals_count;
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,14 @@ PkHandle* pkNewModule(PKVM* vm, const char* name) {
|
||||
return vmNewHandle(vm, VAR_OBJ(module));
|
||||
}
|
||||
|
||||
void pkRegisterModule(PKVM* vm, PkHandle* module) {
|
||||
ASSERT(module != NULL, "Argument module was NULL.");
|
||||
ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
||||
"Given handle is not a module.");
|
||||
Module* module_ = (Module*)AS_OBJ(module->value);
|
||||
vmRegisterModule(vm, module_, module_->name);
|
||||
}
|
||||
|
||||
void pkModuleAddGlobal(PKVM* vm, PkHandle* module,
|
||||
const char* name, PkHandle* value) {
|
||||
ASSERT(module != NULL, "Argument module was NULL.");
|
||||
@ -413,17 +421,12 @@ static inline bool validateCond(PKVM* vm, bool condition, const char* err) {
|
||||
|
||||
static void initializeBuiltinFunctions(PKVM* vm);
|
||||
static void initializeCoreModules(PKVM* vm);
|
||||
static void initializePrimitiveClasses(PKVM* vm);
|
||||
|
||||
void initializeCore(PKVM* vm) {
|
||||
initializeBuiltinFunctions(vm);
|
||||
initializeCoreModules(vm);
|
||||
}
|
||||
|
||||
Module* getCoreLib(const PKVM* vm, String* name) {
|
||||
Var lib = mapGet(vm->core_libs, VAR_OBJ(name));
|
||||
if (IS_UNDEF(lib)) return NULL;
|
||||
ASSERT(IS_OBJ_TYPE(lib, OBJ_MODULE), OOPS);
|
||||
return (Module*)AS_OBJ(lib);
|
||||
initializePrimitiveClasses(vm);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -805,19 +808,16 @@ static Module* newModuleInternal(PKVM* vm, const char* name) {
|
||||
|
||||
// Check if any module with the same name already exists and assert to the
|
||||
// hosting application.
|
||||
if (!IS_UNDEF(mapGet(vm->core_libs, VAR_OBJ(_name)))) {
|
||||
if (vmGetModule(vm, _name) != NULL) {
|
||||
ASSERT(false, stringFormat(vm,
|
||||
"A module named '$' already exists", name)->data);
|
||||
}
|
||||
|
||||
Module* module = newModule(vm, _name, true);
|
||||
Module* module = newModule(vm);
|
||||
module->name = _name;
|
||||
module->initialized = true;
|
||||
vmPopTempRef(vm); // _name
|
||||
|
||||
// Add the module to core_libs.
|
||||
vmPushTempRef(vm, &module->_super); // module.
|
||||
mapSet(vm, vm->core_libs, VAR_OBJ(_name), VAR_OBJ(module));
|
||||
vmPopTempRef(vm); // module.
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
@ -905,6 +905,8 @@ DEF(stdLangWrite,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move math to cli as it's not part of the pocketlang core.
|
||||
//
|
||||
// 'math' library methods.
|
||||
// -----------------------
|
||||
|
||||
@ -1155,7 +1157,13 @@ static void initializeCoreModules(PKVM* vm) {
|
||||
#define MODULE_ADD_FN(module, name, fn, argc) \
|
||||
moduleAddFunctionInternal(vm, module, name, fn, argc, DOCSTRING(fn))
|
||||
|
||||
Module* lang = newModuleInternal(vm, "lang");
|
||||
#define NEW_MODULE(module, name_string) \
|
||||
Module* module = newModuleInternal(vm, name_string); \
|
||||
vmPushTempRef(vm, &module->_super); /* module */ \
|
||||
vmRegisterModule(vm, module, module->name); \
|
||||
vmPopTempRef(vm) /* module */
|
||||
|
||||
NEW_MODULE(lang, "lang");
|
||||
MODULE_ADD_FN(lang, "clock", stdLangClock, 0);
|
||||
MODULE_ADD_FN(lang, "gc", stdLangGC, 0);
|
||||
MODULE_ADD_FN(lang, "disas", stdLangDisas, 1);
|
||||
@ -1164,7 +1172,7 @@ static void initializeCoreModules(PKVM* vm) {
|
||||
MODULE_ADD_FN(lang, "debug_break", stdLangDebugBreak, 0);
|
||||
#endif
|
||||
|
||||
Module* math = newModuleInternal(vm, "math");
|
||||
NEW_MODULE(math, "math");
|
||||
MODULE_ADD_FN(math, "floor", stdMathFloor, 1);
|
||||
MODULE_ADD_FN(math, "ceil", stdMathCeil, 1);
|
||||
MODULE_ADD_FN(math, "pow", stdMathPow, 2);
|
||||
@ -1189,18 +1197,27 @@ static void initializeCoreModules(PKVM* vm) {
|
||||
// modify the PI, like in python.
|
||||
moduleAddGlobal(vm, math, "PI", 2, VAR_NUM(M_PI));
|
||||
|
||||
Module* fiber = newModuleInternal(vm, "Fiber");
|
||||
NEW_MODULE(fiber, "Fiber");
|
||||
MODULE_ADD_FN(fiber, "new", stdFiberNew, 1);
|
||||
MODULE_ADD_FN(fiber, "run", stdFiberRun, -1);
|
||||
MODULE_ADD_FN(fiber, "resume", stdFiberResume, -1);
|
||||
|
||||
#undef MODULE_ADD_FN
|
||||
#undef NEW_MODULE
|
||||
}
|
||||
|
||||
#undef IS_NUM_BYTE
|
||||
#undef DOCSTRING
|
||||
#undef DEF
|
||||
|
||||
/*****************************************************************************/
|
||||
/* PRIMITIVE TYPES CLASS */
|
||||
/*****************************************************************************/
|
||||
|
||||
static void initializePrimitiveClasses(PKVM* vm) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* OPERATORS */
|
||||
/*****************************************************************************/
|
||||
|
@ -13,10 +13,6 @@
|
||||
// Initialize core language, builtin function and core libs.
|
||||
void initializeCore(PKVM* vm);
|
||||
|
||||
// Return the core library with the [name] if exists in the core libs,
|
||||
// otherwise returns NULL.
|
||||
Module* getCoreLib(const PKVM* vm, String* name);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* OPERATORS */
|
||||
/*****************************************************************************/
|
||||
|
@ -133,14 +133,11 @@ void dumpFunctionCode(PKVM* vm, Function* func) {
|
||||
ASSERT_INDEX((uint32_t)cls_index, func->owner->constants.count);
|
||||
Var constant = func->owner->constants.data[cls_index];
|
||||
ASSERT(IS_OBJ_TYPE(constant, OBJ_CLASS), OOPS);
|
||||
uint32_t name_ind = ((Class*)(AS_OBJ(constant)))->name;
|
||||
ASSERT_INDEX(name_ind, func->owner->names.count);
|
||||
String* cls_name = func->owner->names.data[name_ind];
|
||||
|
||||
// Prints: %5d [Class:%s]\n
|
||||
PRINT_INT(cls_index);
|
||||
PRINT(" [Class:");
|
||||
PRINT(cls_name->data);
|
||||
PRINT(func->owner->name->data);
|
||||
PRINT("]\n");
|
||||
break;
|
||||
}
|
||||
@ -218,12 +215,10 @@ void dumpFunctionCode(PKVM* vm, Function* func) {
|
||||
case OP_STORE_GLOBAL:
|
||||
{
|
||||
int index = READ_BYTE();
|
||||
int name_index = func->owner->global_names.data[index];
|
||||
String* name = func->owner->names.data[name_index];
|
||||
// Prints: %5d '%s'\n
|
||||
PRINT_INT(index);
|
||||
PRINT(" '");
|
||||
PRINT(name->data);
|
||||
PRINT(func->owner->name->data);
|
||||
PRINT("'\n");
|
||||
break;
|
||||
}
|
||||
@ -273,7 +268,8 @@ void dumpFunctionCode(PKVM* vm, Function* func) {
|
||||
case OP_IMPORT:
|
||||
{
|
||||
int index = READ_SHORT();
|
||||
String* name = func->owner->names.data[index];
|
||||
String* name = moduleGetStringAt(func->owner, index);
|
||||
ASSERT(name != NULL, OOPS);
|
||||
// Prints: %5d '%s'\n
|
||||
PRINT_INT(index);
|
||||
PRINT(" '");
|
||||
@ -330,7 +326,9 @@ void dumpFunctionCode(PKVM* vm, Function* func) {
|
||||
case OP_SET_ATTRIB:
|
||||
{
|
||||
int index = READ_SHORT();
|
||||
String* name = func->owner->names.data[index];
|
||||
String* name = moduleGetStringAt(func->owner, index);
|
||||
ASSERT(name != NULL, OOPS);
|
||||
|
||||
// Prints: %5d '%s'\n
|
||||
PRINT_INT(index);
|
||||
PRINT(" '");
|
||||
@ -397,7 +395,8 @@ void dumpGlobalValues(PKVM* vm) {
|
||||
Module* module = frame->closure->fn->owner;
|
||||
|
||||
for (uint32_t i = 0; i < module->global_names.count; i++) {
|
||||
String* name = module->names.data[module->global_names.data[i]];
|
||||
String* name = moduleGetStringAt(module, module->global_names.data[i]);
|
||||
ASSERT(name != NULL, OOPS);
|
||||
Var value = module->globals.data[i];
|
||||
printf("%10s = ", name->data);
|
||||
dumpValue(vm, value);
|
||||
|
151
src/pk_value.c
151
src/pk_value.c
@ -213,9 +213,6 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
||||
markVarBuffer(vm, &module->constants);
|
||||
vm->bytes_allocated += sizeof(Var) * module->constants.capacity;
|
||||
|
||||
markStringBuffer(vm, &module->names);
|
||||
vm->bytes_allocated += sizeof(String*) * module->names.capacity;
|
||||
|
||||
markObject(vm, &module->body->_super);
|
||||
} break;
|
||||
|
||||
@ -287,11 +284,12 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
||||
|
||||
case OBJ_CLASS:
|
||||
{
|
||||
Class* type = (Class*)obj;
|
||||
Class* cls = (Class*)obj;
|
||||
vm->bytes_allocated += sizeof(Class);
|
||||
markObject(vm, &type->owner->_super);
|
||||
markObject(vm, &type->ctor->_super);
|
||||
vm->bytes_allocated += sizeof(uint32_t) * type->field_names.capacity;
|
||||
markObject(vm, &cls->owner->_super);
|
||||
markObject(vm, &cls->ctor->_super);
|
||||
markObject(vm, &cls->name->_super);
|
||||
vm->bytes_allocated += sizeof(uint32_t) * cls->field_names.capacity;
|
||||
} break;
|
||||
|
||||
case OBJ_INST:
|
||||
@ -380,47 +378,24 @@ Range* newRange(PKVM* vm, double from, double to) {
|
||||
return range;
|
||||
}
|
||||
|
||||
Module* newModule(PKVM* vm, String* name, bool is_native) {
|
||||
Module* newModule(PKVM* vm) {
|
||||
Module* module = ALLOCATE(vm, Module);
|
||||
varInitObject(&module->_super, vm, OBJ_MODULE);
|
||||
|
||||
ASSERT(name != NULL && name->length > 0, OOPS);
|
||||
|
||||
module->path = name;
|
||||
module->path = NULL;
|
||||
module->name = NULL;
|
||||
module->initialized = is_native;
|
||||
module->initialized = false;
|
||||
module->body = NULL;
|
||||
|
||||
// Core modules has its name as the module name.
|
||||
if (is_native) module->name = name;
|
||||
|
||||
pkVarBufferInit(&module->globals);
|
||||
pkUintBufferInit(&module->global_names);
|
||||
pkVarBufferInit(&module->constants);
|
||||
pkStringBufferInit(&module->names);
|
||||
|
||||
// Add a implicit main function and the '__file__' global to the module, only
|
||||
// if it's not a core module.
|
||||
if (!is_native) {
|
||||
vmPushTempRef(vm, &module->_super); // module.
|
||||
|
||||
moduleAddMain(vm, module);
|
||||
|
||||
// Add '__file__' variable with it's path as value. If the path starts with
|
||||
// '@' It's a special file (@(REPL) or @(TRY)) and don't define __file__.
|
||||
if (module->path->data[0] != SPECIAL_NAME_CHAR) {
|
||||
moduleAddGlobal(vm, module, "__file__", 8, VAR_OBJ(module->path));
|
||||
}
|
||||
|
||||
// TODO: Add ARGV as a global.
|
||||
|
||||
vmPopTempRef(vm); // module.
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
Function* newFunction(PKVM* vm, const char* name, int length, Module* owner,
|
||||
Function* newFunction(PKVM* vm, const char* name, int length,
|
||||
Module* owner,
|
||||
bool is_native, const char* docstring,
|
||||
int* fn_index) {
|
||||
|
||||
@ -429,38 +404,36 @@ Function* newFunction(PKVM* vm, const char* name, int length, Module* owner,
|
||||
|
||||
vmPushTempRef(vm, &func->_super); // func
|
||||
|
||||
if (owner == NULL) {
|
||||
ASSERT(is_native, OOPS);
|
||||
func->owner = owner;
|
||||
func->is_native = is_native;
|
||||
func->upvalue_count = 0;
|
||||
func->arity = -2; // -2 means un-initialized (TODO: make it as a macro).
|
||||
func->docstring = docstring;
|
||||
|
||||
ASSERT(is_native || owner != NULL, OOPS);
|
||||
|
||||
// Only builtin function does't have an owner module.
|
||||
if (is_native && owner == NULL) {
|
||||
func->name = name;
|
||||
func->owner = NULL;
|
||||
func->native = NULL;
|
||||
|
||||
} else {
|
||||
uint32_t _fn_index = moduleAddConstant(vm, owner, VAR_OBJ(func));
|
||||
if (fn_index) *fn_index = _fn_index;
|
||||
func->name = moduleAddString(owner, vm, name, length, NULL)->data;
|
||||
|
||||
uint32_t name_index = moduleAddName(owner, vm, name, length);
|
||||
if (is_native) {
|
||||
func->native = NULL;
|
||||
|
||||
func->name = owner->names.data[name_index]->data;
|
||||
func->owner = owner;
|
||||
func->arity = -2; // -2 means un-initialized (TODO: make it as a macro).
|
||||
} else {
|
||||
Fn* fn = ALLOCATE(vm, Fn);
|
||||
pkByteBufferInit(&fn->opcodes);
|
||||
pkUintBufferInit(&fn->oplines);
|
||||
fn->stack_size = 0;
|
||||
func->fn = fn;
|
||||
}
|
||||
}
|
||||
|
||||
func->is_native = is_native;
|
||||
func->upvalue_count = 0;
|
||||
|
||||
if (is_native) {
|
||||
func->native = NULL;
|
||||
|
||||
} else {
|
||||
Fn* fn = ALLOCATE(vm, Fn);
|
||||
pkByteBufferInit(&fn->opcodes);
|
||||
pkUintBufferInit(&fn->oplines);
|
||||
fn->stack_size = 0;
|
||||
func->fn = fn;
|
||||
}
|
||||
|
||||
func->docstring = docstring;
|
||||
|
||||
vmPopTempRef(vm); // func
|
||||
return func;
|
||||
}
|
||||
@ -552,14 +525,13 @@ Class* newClass(PKVM* vm, Module* module, const char* name, uint32_t length,
|
||||
|
||||
pkUintBufferInit(&cls->field_names);
|
||||
cls->owner = module;
|
||||
cls->name = moduleAddName(module, vm, name, length);
|
||||
cls->name = moduleAddString(module, vm, name, length, NULL);
|
||||
|
||||
// Since characters '@' and '$' are special in stringFormat, and they
|
||||
// currently cannot be escaped (TODO), a string (char array) created
|
||||
// for that character and passed as C string format.
|
||||
char special[2] = { SPECIAL_NAME_CHAR, '\0' };
|
||||
String* cls_name = module->names.data[cls->name];
|
||||
String* ctor_name = stringFormat(vm, "$(Ctor:@)", special, cls_name);
|
||||
String* ctor_name = stringFormat(vm, "$(Ctor:@)", special, cls->name);
|
||||
|
||||
// Constructor.
|
||||
vmPushTempRef(vm, &ctor_name->_super); // ctor_name.
|
||||
@ -583,8 +555,7 @@ Instance* newInstance(PKVM* vm, Class* cls, bool initialize) {
|
||||
|
||||
vmPushTempRef(vm, &inst->_super); // inst.
|
||||
|
||||
ASSERT(cls->name < cls->owner->names.count, OOPS);
|
||||
inst->ty_name = cls->owner->names.data[cls->name]->data;
|
||||
inst->ty_name = cls->name->data;
|
||||
inst->is_native = false;
|
||||
|
||||
Inst* ins = ALLOCATE(vm, Inst);
|
||||
@ -1083,7 +1054,6 @@ void freeObject(PKVM* vm, Object* self) {
|
||||
pkVarBufferClear(&module->globals, vm);
|
||||
pkUintBufferClear(&module->global_names, vm);
|
||||
pkVarBufferClear(&module->constants, vm);
|
||||
pkStringBufferClear(&module->names, vm);
|
||||
} break;
|
||||
|
||||
case OBJ_FUNC: {
|
||||
@ -1143,24 +1113,37 @@ uint32_t moduleAddConstant(PKVM* vm, Module* module, Var value) {
|
||||
return (int)module->constants.count - 1;
|
||||
}
|
||||
|
||||
uint32_t moduleAddName(Module* module, PKVM* vm, const char* name,
|
||||
uint32_t length) {
|
||||
String* moduleAddString(Module* module, PKVM* vm, const char* name,
|
||||
uint32_t length, int* index) {
|
||||
|
||||
for (uint32_t i = 0; i < module->names.count; i++) {
|
||||
String* _name = module->names.data[i];
|
||||
for (uint32_t i = 0; i < module->constants.count; i++) {
|
||||
if (!IS_OBJ_TYPE(module->constants.data[i], OBJ_STRING)) continue;
|
||||
String* _name = (String*)AS_OBJ(module->constants.data[i]);
|
||||
if (_name->length == length && strncmp(_name->data, name, length) == 0) {
|
||||
// Name already exists in the buffer.
|
||||
return i;
|
||||
if (index) *index = i;
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
// If we reach here the name doesn't exists in the buffer, so add it and
|
||||
// return the index.
|
||||
String* new_name = newStringLength(vm, name, length);
|
||||
vmPushTempRef(vm, &new_name->_super);
|
||||
pkStringBufferWrite(&module->names, vm, new_name);
|
||||
vmPopTempRef(vm);
|
||||
return module->names.count - 1;
|
||||
vmPushTempRef(vm, &new_name->_super); // new_name
|
||||
pkVarBufferWrite(&module->constants, vm, VAR_OBJ(new_name));
|
||||
vmPopTempRef(vm); // new_name
|
||||
if (index) *index = module->constants.count - 1;
|
||||
return new_name;
|
||||
}
|
||||
|
||||
String* moduleGetStringAt(Module* module, int index) {
|
||||
ASSERT(index >= 0, OOPS);
|
||||
if (index >= (int)module->constants.count) return NULL;
|
||||
Var constant = module->constants.data[index];
|
||||
if (IS_OBJ_TYPE(constant, OBJ_STRING)) {
|
||||
return (String*)AS_OBJ(constant);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t moduleAddGlobal(PKVM* vm, Module* module,
|
||||
@ -1177,8 +1160,9 @@ uint32_t moduleAddGlobal(PKVM* vm, Module* module,
|
||||
|
||||
// If we're reached here that means we don't already have a variable with
|
||||
// that name, create new one and set the value.
|
||||
uint32_t name_ind = moduleAddName(module, vm, name, length);
|
||||
pkUintBufferWrite(&module->global_names, vm, name_ind);
|
||||
int name_index = 0;
|
||||
moduleAddString(module, vm, name, length, &name_index);
|
||||
pkUintBufferWrite(&module->global_names, vm, name_index);
|
||||
pkVarBufferWrite(&module->globals, vm, value);
|
||||
return module->globals.count - 1;
|
||||
}
|
||||
@ -1186,7 +1170,8 @@ uint32_t moduleAddGlobal(PKVM* vm, Module* module,
|
||||
int moduleGetGlobalIndex(Module* module, const char* name, uint32_t length) {
|
||||
for (uint32_t i = 0; i < module->global_names.count; i++) {
|
||||
uint32_t name_index = module->global_names.data[i];
|
||||
String* g_name = module->names.data[name_index];
|
||||
String* g_name = moduleGetStringAt(module, name_index);
|
||||
ASSERT(g_name != NULL, OOPS);
|
||||
if (g_name->length == length && strncmp(g_name->data, name, length) == 0) {
|
||||
return (int)i;
|
||||
}
|
||||
@ -1271,8 +1256,8 @@ bool instGetAttrib(PKVM* vm, Instance* inst, String* attrib, Var* value) {
|
||||
Class* cls = inst->ins->type;
|
||||
for (uint32_t i = 0; i < cls->field_names.count; i++) {
|
||||
ASSERT_INDEX(i, cls->field_names.count);
|
||||
ASSERT_INDEX(cls->field_names.data[i], cls->owner->names.count);
|
||||
String* f_name = cls->owner->names.data[cls->field_names.data[i]];
|
||||
String* f_name = moduleGetStringAt(cls->owner, cls->field_names.data[i]);
|
||||
ASSERT(f_name != NULL, OOPS);
|
||||
if (IS_STR_EQ(f_name, attrib)) {
|
||||
*value = inst->ins->fields.data[i];
|
||||
return true;
|
||||
@ -1326,8 +1311,8 @@ bool instSetAttrib(PKVM* vm, Instance* inst, String* attrib, Var value) {
|
||||
Class* ty = inst->ins->type;
|
||||
for (uint32_t i = 0; i < ty->field_names.count; i++) {
|
||||
ASSERT_INDEX(i, ty->field_names.count);
|
||||
ASSERT_INDEX(ty->field_names.data[i], ty->owner->names.count);
|
||||
String* f_name = ty->owner->names.data[ty->field_names.data[i]];
|
||||
String* f_name = moduleGetStringAt(ty->owner, ty->field_names.data[i]);
|
||||
ASSERT(f_name != NULL, OOPS);
|
||||
if (f_name->hash == attrib->hash &&
|
||||
f_name->length == attrib->length &&
|
||||
memcmp(f_name->data, attrib->data, attrib->length) == 0) {
|
||||
@ -1686,8 +1671,7 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
|
||||
case OBJ_CLASS: {
|
||||
const Class* cls = (const Class*)obj;
|
||||
pkByteBufferAddString(buff, vm, "[Class:", 7);
|
||||
String* ty_name = cls->owner->names.data[cls->name];
|
||||
pkByteBufferAddString(buff, vm, ty_name->data, ty_name->length);
|
||||
pkByteBufferAddString(buff, vm, cls->name->data, cls->name->length);
|
||||
pkByteBufferWrite(buff, vm, ']');
|
||||
return;
|
||||
}
|
||||
@ -1709,7 +1693,8 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
|
||||
if (i != 0) pkByteBufferWrite(buff, vm, ',');
|
||||
|
||||
pkByteBufferWrite(buff, vm, ' ');
|
||||
String* f_name = cls->owner->names.data[cls->field_names.data[i]];
|
||||
String* f_name = moduleGetStringAt(cls->owner,
|
||||
cls->field_names.data[i]);
|
||||
pkByteBufferAddString(buff, vm, f_name->data, f_name->length);
|
||||
pkByteBufferWrite(buff, vm, '=');
|
||||
_toStringInternal(vm, ins->fields.data[i], buff, outer, repr);
|
||||
|
@ -209,7 +209,7 @@ void pkByteBufferAddString(pkByteBuffer* self, PKVM* vm, const char* str,
|
||||
|
||||
// Type enums of the pocketlang heap allocated types.
|
||||
typedef enum {
|
||||
OBJ_STRING,
|
||||
OBJ_STRING = 0,
|
||||
OBJ_LIST,
|
||||
OBJ_MAP,
|
||||
OBJ_RANGE,
|
||||
@ -219,7 +219,7 @@ typedef enum {
|
||||
OBJ_UPVALUE,
|
||||
OBJ_FIBER,
|
||||
OBJ_CLASS,
|
||||
OBJ_INST,
|
||||
OBJ_INST, // OBJ_INST should be the last element of this enums (don't move).
|
||||
} ObjectType;
|
||||
|
||||
// Base struct for all heap allocated objects.
|
||||
@ -288,20 +288,10 @@ struct Module {
|
||||
// a moduel as well as classes.
|
||||
pkVarBuffer constants;
|
||||
|
||||
// All the variable names, globals name, attribute name etc, are stored in
|
||||
// the [names] buffer. They can be stored in the constants but to make it
|
||||
// more clear different between string literal and names they're stored in
|
||||
// a different location.
|
||||
pkStringBuffer names;
|
||||
|
||||
// TODO:
|
||||
// Consider merging names and constants. Java's class file doesn't have
|
||||
// a seperation between string literals and names in it's constant pool.
|
||||
|
||||
// Globals is an array of global variables of the module. All the names
|
||||
// (including global variables) are stored in the names buffer of the module
|
||||
// (defined bellow). The (i)th global variables names is located at index (j)
|
||||
// in the names buffer where j = global_names[i].
|
||||
// (including global variables) are stored in the constant pool of the
|
||||
// module. The (i)th global variable's names is located at index (j)
|
||||
// in the constant pool where j = global_names[i].
|
||||
pkVarBuffer globals;
|
||||
pkUintBuffer global_names;
|
||||
|
||||
@ -493,9 +483,8 @@ struct Class {
|
||||
// The module that owns this class.
|
||||
Module* owner;
|
||||
|
||||
// The index of the name of this class in the owner module's names
|
||||
// buffer.
|
||||
uint32_t name;
|
||||
// Name of the class.
|
||||
String* name;
|
||||
|
||||
Closure* ctor; //< The constructor function.
|
||||
pkUintBuffer field_names; //< Buffer of field names.
|
||||
@ -525,11 +514,8 @@ struct Instance {
|
||||
/* "CONSTRUCTORS" */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Initialize the object with it's default value.
|
||||
void varInitObject(Object* self, PKVM* vm, ObjectType type);
|
||||
|
||||
// Allocate new String object with from [text] with a given [length] and return
|
||||
// String*.
|
||||
String* newStringLength(PKVM* vm, const char* text, uint32_t length);
|
||||
|
||||
// An inline function/macro implementation of newString(). Set below 0 to 1, to
|
||||
@ -547,32 +533,29 @@ String* newStringLength(PKVM* vm, const char* text, uint32_t length);
|
||||
(newStringLength(vm, text, (!(text)) ? 0 : (uint32_t)strlen(text)))
|
||||
#endif
|
||||
|
||||
// Allocate new List and return List*.
|
||||
List* newList(PKVM* vm, uint32_t size);
|
||||
|
||||
// Allocate new Map and return Map*.
|
||||
Map* newMap(PKVM* vm);
|
||||
|
||||
// Allocate new Range object and return Range*.
|
||||
Range* newRange(PKVM* vm, double from, double to);
|
||||
|
||||
// FIXME:
|
||||
// We may need 2 different constructor for native and script modules.
|
||||
Module* newModule(PKVM* vm, String* name, bool is_native);
|
||||
Module* newModule(PKVM* vm);
|
||||
|
||||
// FIXME:
|
||||
// We may need 2 different constuctor for native and script functions.
|
||||
Function* newFunction(PKVM* vm, const char* name, int length, Module* owner,
|
||||
// The docstring should be allocated and stored in the module's constants
|
||||
// as a string if it's not a native function. (native function's docs are
|
||||
// C string liteals).
|
||||
//
|
||||
// Allocate a new function and return it.
|
||||
Function* newFunction(PKVM* vm, const char* name, int length,
|
||||
Module* owner,
|
||||
bool is_native, const char* docstring,
|
||||
int* fn_index);
|
||||
|
||||
// Allocate a new closure object and return it.
|
||||
Closure* newClosure(PKVM* vm, Function* fn);
|
||||
|
||||
// Allocate a new upvalue object for the [value] and return it.
|
||||
Upvalue* newUpvalue(PKVM* vm, Var* value);
|
||||
|
||||
// Allocate new Fiber object for the [closure] and return Fiber*.
|
||||
Fiber* newFiber(PKVM* vm, Closure* closure);
|
||||
|
||||
// FIXME:
|
||||
@ -689,10 +672,16 @@ bool fiberHasError(Fiber* fiber);
|
||||
// constant buffer and return it's index.
|
||||
uint32_t moduleAddConstant(PKVM* vm, Module* module, Var value);
|
||||
|
||||
// Add the name (string literal) to the string buffer if not already exists and
|
||||
// return it's index in the buffer.
|
||||
uint32_t moduleAddName(Module* module, PKVM* vm, const char* name,
|
||||
uint32_t length);
|
||||
// Add a string literal to the module's constant buffer if not already exists
|
||||
// and return it. If the [index] isn't NULL, the index of the string will be
|
||||
// written on it.
|
||||
String* moduleAddString(Module* module, PKVM* vm, const char* name,
|
||||
uint32_t length, int* index);
|
||||
|
||||
// Returns a string at the index of the module, if the index is invalid or the
|
||||
// constant at the index is not a string, it'll return NULL. (however if the
|
||||
// index is negative i'll fail an assertion).
|
||||
String* moduleGetStringAt(Module* module, int index);
|
||||
|
||||
// Add a global [value] to the [module] and return its index.
|
||||
uint32_t moduleAddGlobal(PKVM* vm, Module* module,
|
||||
|
76
src/pk_vm.c
76
src/pk_vm.c
@ -69,9 +69,14 @@ PKVM* pkNewVM(PkConfiguration* config) {
|
||||
vm->heap_fill_percent = HEAP_FILL_PERCENT;
|
||||
|
||||
vm->modules = newMap(vm);
|
||||
vm->core_libs = newMap(vm);
|
||||
vm->builtins_count = 0;
|
||||
|
||||
// This is necessary to prevent garbage collection skip the entry in this
|
||||
// array while we're building it.
|
||||
for (int i = 0; i < OBJ_INST; i++) {
|
||||
vm->primitives[i] = NULL;
|
||||
}
|
||||
|
||||
initializeCore(vm);
|
||||
return vm;
|
||||
}
|
||||
@ -132,21 +137,23 @@ void pkReleaseHandle(PKVM* vm, PkHandle* handle) {
|
||||
PkResult pkInterpretSource(PKVM* vm, PkStringPtr source, PkStringPtr path,
|
||||
const PkCompileOptions* options) {
|
||||
|
||||
String* path_name = newString(vm, path.string);
|
||||
String* path_ = newString(vm, path.string);
|
||||
if (path.on_done) path.on_done(vm, path);
|
||||
vmPushTempRef(vm, &path_name->_super); // path_name.
|
||||
vmPushTempRef(vm, &path_->_super); // path_
|
||||
|
||||
// TODO: Should I clean the module if it already exists before compiling it?
|
||||
// FIXME:
|
||||
// Should I clean the module if it already exists before compiling it?
|
||||
|
||||
// Load a new module to the vm's modules cache.
|
||||
Module* module = vmGetModule(vm, path_name);
|
||||
Module* module = vmGetModule(vm, path_);
|
||||
if (module == NULL) {
|
||||
module = newModule(vm, path_name, false);
|
||||
module = newModule(vm);
|
||||
module->path = path_;
|
||||
vmPushTempRef(vm, &module->_super); // module.
|
||||
mapSet(vm, vm->modules, VAR_OBJ(path_name), VAR_OBJ(module));
|
||||
vmRegisterModule(vm, module, path_);
|
||||
vmPopTempRef(vm); // module.
|
||||
}
|
||||
vmPopTempRef(vm); // path_name.
|
||||
vmPopTempRef(vm); // path_
|
||||
|
||||
// Compile the source.
|
||||
PkResult result = compile(vm, module, source.string, options);
|
||||
@ -241,8 +248,17 @@ void vmPopTempRef(PKVM* vm) {
|
||||
vm->temp_reference_count--;
|
||||
}
|
||||
|
||||
Module* vmGetModule(PKVM* vm, String* path) {
|
||||
Var module = mapGet(vm->modules, VAR_OBJ(path));
|
||||
void vmRegisterModule(PKVM* vm, Module* module, String* key) {
|
||||
ASSERT((((module->name != NULL) && IS_STR_EQ(module->name, key)) ||
|
||||
IS_STR_EQ(module->path, key)), OOPS);
|
||||
// FIXME:
|
||||
// Not sure what to do, if a module the the same key already exists. Should
|
||||
// I override or assert.
|
||||
mapSet(vm, vm->modules, VAR_OBJ(key), VAR_OBJ(module));
|
||||
}
|
||||
|
||||
Module* vmGetModule(PKVM* vm, String* key) {
|
||||
Var module = mapGet(vm->modules, VAR_OBJ(key));
|
||||
if (IS_UNDEF(module)) return NULL;
|
||||
ASSERT(AS_OBJ(module)->type == OBJ_MODULE, OOPS);
|
||||
return (Module*)AS_OBJ(module);
|
||||
@ -254,13 +270,25 @@ void vmCollectGarbage(PKVM* vm) {
|
||||
// required to know the size of each object that'll be freeing.
|
||||
vm->bytes_allocated = 0;
|
||||
|
||||
// Mark the core libs and builtin functions.
|
||||
markObject(vm, &vm->core_libs->_super);
|
||||
// Mark builtin functions.
|
||||
for (int i = 0; i < vm->builtins_count; i++) {
|
||||
markObject(vm, &vm->builtins[i]->_super);
|
||||
}
|
||||
|
||||
// Mark the modules cache.
|
||||
// Mark primitive types' classes.
|
||||
for (int i = 0; i < (int)OBJ_INST; i++) {
|
||||
// Upvalue and functions aren't first class objects and they doesn't
|
||||
// require classes.
|
||||
if (i == OBJ_UPVALUE || i == OBJ_FUNC) continue;
|
||||
|
||||
// It's possible that a garbage collection could be triggered while we're
|
||||
// building the primitives and the class could be NULL.
|
||||
if (vm->primitives[i] == NULL) continue;
|
||||
|
||||
markObject(vm, &vm->primitives[i]->_super);
|
||||
}
|
||||
|
||||
// Mark the modules.
|
||||
markObject(vm, &vm->modules->_super);
|
||||
|
||||
// Mark temp references.
|
||||
@ -450,14 +478,9 @@ static void* defaultRealloc(void* memory, size_t new_size, void* user_data) {
|
||||
//
|
||||
// Import and return the Module object with the [name] (if it's a scirpt
|
||||
// doesn't have a module name, the name would be it's resolved path).
|
||||
static inline Var importModule(PKVM* vm, String* name) {
|
||||
static inline Var importModule(PKVM* vm, String* key) {
|
||||
|
||||
// Check in the core libs.
|
||||
Module* module = getCoreLib(vm, name);
|
||||
if (module != NULL) return VAR_OBJ(module);
|
||||
|
||||
// Check in the modules cache.
|
||||
Var entry = mapGet(vm->modules, VAR_OBJ(name));
|
||||
Var entry = mapGet(vm->modules, VAR_OBJ(key));
|
||||
if (!IS_UNDEF(entry)) {
|
||||
ASSERT(AS_OBJ(entry)->type == OBJ_MODULE, OOPS);
|
||||
return entry;
|
||||
@ -1005,7 +1028,9 @@ L_vm_main_loop:
|
||||
|
||||
OPCODE(IMPORT):
|
||||
{
|
||||
String* name = module->names.data[READ_SHORT()];
|
||||
uint16_t index = READ_SHORT();
|
||||
String* name = moduleGetStringAt(module, (int)index);
|
||||
ASSERT(name != NULL, OOPS);
|
||||
|
||||
Var _imported = importModule(vm, name);
|
||||
ASSERT(IS_OBJ_TYPE(_imported, OBJ_MODULE), OOPS);
|
||||
@ -1332,7 +1357,8 @@ L_vm_main_loop:
|
||||
OPCODE(GET_ATTRIB):
|
||||
{
|
||||
Var on = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||
String* name = module->names.data[READ_SHORT()];
|
||||
String* name = moduleGetStringAt(module, READ_SHORT());
|
||||
ASSERT(name != NULL, OOPS);
|
||||
Var value = varGetAttrib(vm, on, name);
|
||||
DROP(); // on
|
||||
PUSH(value);
|
||||
@ -1344,7 +1370,8 @@ L_vm_main_loop:
|
||||
OPCODE(GET_ATTRIB_KEEP):
|
||||
{
|
||||
Var on = PEEK(-1);
|
||||
String* name = module->names.data[READ_SHORT()];
|
||||
String* name = moduleGetStringAt(module, READ_SHORT());
|
||||
ASSERT(name != NULL, OOPS);
|
||||
PUSH(varGetAttrib(vm, on, name));
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
@ -1354,7 +1381,8 @@ L_vm_main_loop:
|
||||
{
|
||||
Var value = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||
Var on = PEEK(-2); // Don't pop yet, we need the reference for gc.
|
||||
String* name = module->names.data[READ_SHORT()];
|
||||
String* name = moduleGetStringAt(module, READ_SHORT());
|
||||
ASSERT(name != NULL, OOPS);
|
||||
varSetAttrib(vm, on, name, value);
|
||||
|
||||
DROP(); // value
|
||||
|
28
src/pk_vm.h
28
src/pk_vm.h
@ -105,18 +105,23 @@ struct PKVM {
|
||||
// a new module is being imported and compiled at compiletime.
|
||||
Compiler* compiler;
|
||||
|
||||
// A cache of the compiled modules with their path as key and the Scrpit
|
||||
// object as the value.
|
||||
// A map of all the modules which are compiled or natively registered.
|
||||
// The key of the modules will be:
|
||||
// 1. Native modules : name of the module.
|
||||
// 2. Compiled script :
|
||||
// - module name if one defined with the module keyword
|
||||
// - otherwise path of the module.
|
||||
Map* modules;
|
||||
|
||||
// A map of core libraries with their name as the key and the Module object
|
||||
// as the value.
|
||||
Map* core_libs;
|
||||
|
||||
// Array of all builtin functions.
|
||||
Closure* builtins[BUILTIN_FN_CAPACITY];
|
||||
int builtins_count;
|
||||
|
||||
// An array of all the primitive types' class except for OBJ_INST. Since the
|
||||
// type of the objects are enums starting from 0 we can directly get the
|
||||
// class by using their enum (ex: primitives[OBJ_LIST]).
|
||||
Class* primitives[(int)OBJ_INST];
|
||||
|
||||
// Current fiber.
|
||||
Fiber* fiber;
|
||||
};
|
||||
@ -183,9 +188,14 @@ void vmPushTempRef(PKVM* vm, Object* obj);
|
||||
// Pop the top most object from temporary reference stack.
|
||||
void vmPopTempRef(PKVM* vm);
|
||||
|
||||
// Returns the module with the resolved [path] (also the key) in the VM's
|
||||
// modules cache. If not found itll return NULL.
|
||||
Module* vmGetModule(PKVM* vm, String* path);
|
||||
// Regsiter a module to the VM's modules map, the key could be either it's
|
||||
// name (for core module) or it's path (if it's a compiled script). If the
|
||||
// key doesn't match either of it's name or path an assertion will fail.
|
||||
void vmRegisterModule(PKVM* vm, Module* module, String* key);
|
||||
|
||||
// Returns the module, where the [key] could be either it's name or path that
|
||||
// was used to register the module. If it doesn't exists, returns NULL.
|
||||
Module* vmGetModule(PKVM* vm, String* key);
|
||||
|
||||
// ((Context switching - start))
|
||||
// Prepare a new fiber for execution with the given arguments. That can be used
|
||||
|
Loading…
Reference in New Issue
Block a user