Merge pull request #192 from ThakeeNathees/script-type-rename

Scripts renamed to Modules
This commit is contained in:
Thakee Nathees 2022-04-12 01:26:39 +05:30 committed by GitHub
commit 3b5da9cad3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 447 additions and 440 deletions

View File

@ -27,7 +27,8 @@
#define CLI_NOTICE \ #define CLI_NOTICE \
"PocketLang " PK_VERSION_STRING " (https://github.com/ThakeeNathees/pocketlang/)\n" \ "PocketLang " PK_VERSION_STRING " (https://github.com/ThakeeNathees/pocketlang/)\n" \
"Copyright(c) 2020 - 2021 ThakeeNathees.\n" \ "Copyright (c) 2020 - 2021 ThakeeNathees\n" \
"Copyright (c) 2021-2022 Pocketlang Contributors\n" \
"Free and open source software under the terms of the MIT license.\n" "Free and open source software under the terms of the MIT license.\n"
// FIXME: the vm user data of cli. // FIXME: the vm user data of cli.

View File

@ -84,7 +84,7 @@ typedef enum {
PK_LIST, PK_LIST,
PK_MAP, PK_MAP,
PK_RANGE, PK_RANGE,
PK_SCRIPT, PK_MODULE,
PK_FUNCTION, PK_FUNCTION,
PK_FIBER, PK_FIBER,
PK_CLASS, PK_CLASS,

View File

@ -12,12 +12,12 @@
#include "pk_vm.h" #include "pk_vm.h"
#include "pk_debug.h" #include "pk_debug.h"
// The maximum number of variables (or global if compiling top level script) // The maximum number of locals or global (if compiling top level module)
// to lookup from the compiling context. Also it's limited by it's opcode // to lookup from the compiling context. Also it's limited by it's opcode
// which is using a single byte value to identify the local. // which is using a single byte value to identify the local.
#define MAX_VARIABLES 256 #define MAX_VARIABLES 256
// The maximum number of constant literal a script can contain. Also it's // The maximum number of constant literal a module can contain. Also it's
// limited by it's opcode which is using a short value to identify. // limited by it's opcode which is using a short value to identify.
#define MAX_CONSTANTS (1 << 16) #define MAX_CONSTANTS (1 << 16)
@ -237,14 +237,14 @@ typedef struct {
} GrammarRule; } GrammarRule;
typedef enum { typedef enum {
DEPTH_SCRIPT = -2, //< Only used for script body function's depth. DEPTH_MODULE = -2, //< Only used for module body function's depth.
DEPTH_GLOBAL = -1, //< Global variables. DEPTH_GLOBAL = -1, //< Global variables.
DEPTH_LOCAL, //< Local scope. Increase with inner scope. DEPTH_LOCAL, //< Local scope. Increase with inner scope.
} Depth; } Depth;
typedef enum { typedef enum {
FN_NATIVE, //< Native C function. FN_NATIVE, //< Native C function.
FN_SCRIPT, //< Script level functions defined with 'def'. FN_SCRIPT, //< Script functions defined with 'def'.
FN_LITERAL, //< Literal functions defined with 'function(){...}' FN_LITERAL, //< Literal functions defined with 'function(){...}'
} FuncType; } FuncType;
@ -285,8 +285,8 @@ typedef struct sLoop {
// compile time we can allow access to them at the global scope. // compile time we can allow access to them at the global scope.
typedef struct sForwardName { typedef struct sForwardName {
// Index of the short instruction that has the value of the name (in the // Index of the short instruction that has the value of the global's name
// names buffer of the script). // (in the names buffer of the module).
int instruction; int instruction;
// The function where the name is used, and the instruction is belongs to. // The function where the name is used, and the instruction is belongs to.
@ -303,8 +303,8 @@ typedef struct sForwardName {
typedef struct sFunc { typedef struct sFunc {
// Scope of the function. -2 for script body, -1 for top level function and // Scope of the function. -2 for module body function, -1 for top level
// literal functions will have the scope where it declared. // function and literal functions will have the scope where it declared.
int depth; int depth;
// The actual function pointer which is being compiled. // The actual function pointer which is being compiled.
@ -313,8 +313,8 @@ typedef struct sFunc {
// The index of the function in its module. // The index of the function in its module.
int index; int index;
// If outer function of a literal or the script body function of a script // If outer function of this function, for top level function the outer
// function. Null for script body function. // function will be the module's body function.
struct sFunc* outer_func; struct sFunc* outer_func;
} Func; } Func;
@ -377,7 +377,7 @@ typedef struct sParser {
char si_name_quote; char si_name_quote;
// An array of implicitly forward declared names, which will be resolved once // An array of implicitly forward declared names, which will be resolved once
// the script is completely compiled. // the module is completely compiled.
ForwardName forwards[MAX_FORWARD_NAMES]; ForwardName forwards[MAX_FORWARD_NAMES];
int forwards_count; int forwards_count;
@ -393,11 +393,11 @@ struct Compiler {
// current compilation. // current compilation.
Parser parser; Parser parser;
// Each module (ie. script) will be compiled with it's own compiler and a // Each module will be compiled with it's own compiler and a module is
// module is imported, a new compiler is created for that module and it'll // imported, a new compiler is created for that module and it'll be added to
// be added to the linked list of compilers at the begining. PKVM will use // the linked list of compilers at the begining. PKVM will use this compiler
// this compiler reference as a root object (objects which won't garbage // reference as a root object (objects which won't garbage collected) and
// collected) and the chain of compilers will be marked at the marking phase. // the chain of compilers will be marked at the marking phase.
// //
// Here is how the chain change when a new compiler (compiler_3) created. // Here is how the chain change when a new compiler (compiler_3) created.
// //
@ -409,9 +409,9 @@ struct Compiler {
const PkCompileOptions* options; //< To configure the compilation. const PkCompileOptions* options; //< To configure the compilation.
Script* script; //< Current script. Module* module; //< Current module that's being compiled.
Loop* loop; //< Current loop. Loop* loop; //< Current loop the we're parsing.
Func* func; //< Current function. Func* func; //< Current function we're parsing.
// Current depth the compiler in (-1 means top level) 0 means function // Current depth the compiler in (-1 means top level) 0 means function
// level and > 0 is inner scope. // level and > 0 is inner scope.
@ -495,11 +495,11 @@ static void parserInit(Parser* parser, PKVM* vm, Compiler* compiler,
} }
static void compilerInit(Compiler* compiler, PKVM* vm, const char* source, static void compilerInit(Compiler* compiler, PKVM* vm, const char* source,
Script* script, const PkCompileOptions* options) { Module* module, const PkCompileOptions* options) {
compiler->next_compiler = NULL; compiler->next_compiler = NULL;
compiler->script = script; compiler->module = module;
compiler->options = options; compiler->options = options;
compiler->scope_depth = DEPTH_GLOBAL; compiler->scope_depth = DEPTH_GLOBAL;
@ -512,7 +512,7 @@ static void compilerInit(Compiler* compiler, PKVM* vm, const char* source,
compiler->new_local = false; compiler->new_local = false;
compiler->is_last_call = false; compiler->is_last_call = false;
parserInit(&compiler->parser, vm, compiler, source, script->path->data); parserInit(&compiler->parser, vm, compiler, source, module->path->data);
// Cache the required built functions. // Cache the required built functions.
compiler->bifn_list_join = findBuiltinFunction(vm, "list_join", 9); compiler->bifn_list_join = findBuiltinFunction(vm, "list_join", 9);
@ -578,7 +578,7 @@ static void parseError(Compiler* compiler, const char* fmt, ...) {
} }
// Error caused when trying to resolve forward names (maybe more in the // Error caused when trying to resolve forward names (maybe more in the
// future), Which will be called once after compiling the script and thus we // future), Which will be called once after compiling the module and thus we
// need to pass the line number the error originated from. // need to pass the line number the error originated from.
static void resolveError(Compiler* compiler, int line, const char* fmt, ...) { static void resolveError(Compiler* compiler, int line, const char* fmt, ...) {
va_list args; va_list args;
@ -1270,7 +1270,7 @@ static NameSearchResult compilerSearchName(Compiler* compiler,
int index; // For storing the search result below. int index; // For storing the search result below.
// Search through globals. // Search through globals.
index = scriptGetGlobalIndex(compiler->script, name, length); index = moduleGetGlobalIndex(compiler->module, name, length);
if (index != -1) { if (index != -1) {
result.type = NAME_GLOBAL_VAR; result.type = NAME_GLOBAL_VAR;
result.index = index; result.index = index;
@ -1525,7 +1525,6 @@ static void exprFunc(Compiler* compiler) {
emitShort(compiler, fn_index); emitShort(compiler, fn_index);
} }
// Local/global variables, script/native/builtin functions name.
static void exprName(Compiler* compiler) { static void exprName(Compiler* compiler) {
const char* start = compiler->parser.previous.start; const char* start = compiler->parser.previous.start;
@ -1767,8 +1766,8 @@ static void exprAttrib(Compiler* compiler) {
const char* name = compiler->parser.previous.start; const char* name = compiler->parser.previous.start;
int length = compiler->parser.previous.length; int length = compiler->parser.previous.length;
// Store the name in script's names. // Store the name in module's names buffer.
int index = scriptAddName(compiler->script, compiler->parser.vm, int index = moduleAddName(compiler->module, compiler->parser.vm,
name, length); name, length);
if (compiler->l_value && matchAssignment(compiler)) { if (compiler->l_value && matchAssignment(compiler)) {
@ -1875,7 +1874,7 @@ static int compilerAddVariable(Compiler* compiler, const char* name,
bool max_vars_reached = false; bool max_vars_reached = false;
const char* var_type = ""; // For max variables reached error message. const char* var_type = ""; // For max variables reached error message.
if (compiler->scope_depth == DEPTH_GLOBAL) { if (compiler->scope_depth == DEPTH_GLOBAL) {
if (compiler->script->globals.count >= MAX_VARIABLES) { if (compiler->module->globals.count >= MAX_VARIABLES) {
max_vars_reached = true; max_vars_reached = true;
var_type = "globals"; var_type = "globals";
} }
@ -1886,7 +1885,7 @@ static int compilerAddVariable(Compiler* compiler, const char* name,
} }
} }
if (max_vars_reached) { if (max_vars_reached) {
parseError(compiler, "A script should contain at most %d %s.", parseError(compiler, "A module should contain at most %d %s.",
MAX_VARIABLES, var_type); MAX_VARIABLES, var_type);
return -1; return -1;
} }
@ -1894,7 +1893,7 @@ static int compilerAddVariable(Compiler* compiler, const char* name,
// Add the variable and return it's index. // Add the variable and return it's index.
if (compiler->scope_depth == DEPTH_GLOBAL) { if (compiler->scope_depth == DEPTH_GLOBAL) {
return (int)scriptAddGlobal(compiler->parser.vm, compiler->script, return (int)moduleAddGlobal(compiler->parser.vm, compiler->module,
name, length, VAR_NULL); name, length, VAR_NULL);
} else { } else {
Local* local = &compiler->locals [compiler->local_count]; Local* local = &compiler->locals [compiler->local_count];
@ -1911,7 +1910,7 @@ static int compilerAddVariable(Compiler* compiler, const char* name,
static void compilerAddForward(Compiler* compiler, int instruction, Fn* fn, static void compilerAddForward(Compiler* compiler, int instruction, Fn* fn,
const char* name, int length, int line) { const char* name, int length, int line) {
if (compiler->parser.forwards_count == MAX_FORWARD_NAMES) { if (compiler->parser.forwards_count == MAX_FORWARD_NAMES) {
parseError(compiler, "A script should contain at most %d implicit forward " parseError(compiler, "A module should contain at most %d implicit forward "
"function declarations.", MAX_FORWARD_NAMES); "function declarations.", MAX_FORWARD_NAMES);
return; return;
} }
@ -1925,14 +1924,14 @@ static void compilerAddForward(Compiler* compiler, int instruction, Fn* fn,
forward->line = line; forward->line = line;
} }
// Add a literal constant to scripts literals and return it's index. // Add a literal constant to module literals and return it's index.
static int compilerAddConstant(Compiler* compiler, Var value) { static int compilerAddConstant(Compiler* compiler, Var value) {
pkVarBuffer* constants = &compiler->script->constants; pkVarBuffer* constants = &compiler->module->constants;
uint32_t index = scriptAddConstant(compiler->parser.vm, uint32_t index = moduleAddConstant(compiler->parser.vm,
compiler->script, value); compiler->module, value);
if (index >= MAX_CONSTANTS) { if (index >= MAX_CONSTANTS) {
parseError(compiler, "A script should contain at most %d " parseError(compiler, "A module should contain at most %d "
"unique constants.", MAX_CONSTANTS); "unique constants.", MAX_CONSTANTS);
} }
return (int)index; return (int)index;
@ -2105,7 +2104,7 @@ typedef enum {
static void compileStatement(Compiler* compiler); static void compileStatement(Compiler* compiler);
static void compileBlockBody(Compiler* compiler, BlockType type); static void compileBlockBody(Compiler* compiler, BlockType type);
// Compile a class and return it's index in the script's types buffer. // Compile a class and return it's index in the module's types buffer.
static int compileClass(Compiler* compiler) { static int compileClass(Compiler* compiler) {
// Consume the name of the type. // Consume the name of the type.
@ -2115,7 +2114,7 @@ static int compileClass(Compiler* compiler) {
// Create a new class. // Create a new class.
int cls_index, ctor_index; int cls_index, ctor_index;
Class* cls = newClass(compiler->parser.vm, compiler->script, Class* cls = newClass(compiler->parser.vm, compiler->module,
name, (uint32_t)name_len, &cls_index, &ctor_index); name, (uint32_t)name_len, &cls_index, &ctor_index);
cls->ctor->arity = 0; cls->ctor->arity = 0;
@ -2126,16 +2125,16 @@ static int compileClass(Compiler* compiler) {
compiler->parser.previous.start, compiler->parser.previous.start,
compiler->parser.previous.length, compiler->parser.previous.length,
compiler->parser.previous.line); compiler->parser.previous.line);
scriptSetGlobal(compiler->script, index, VAR_OBJ(cls)); moduleSetGlobal(compiler->module, index, VAR_OBJ(cls));
// Check count exceeded. // Check count exceeded.
if (cls_index >= MAX_CONSTANTS || ctor_index >= MAX_CONSTANTS) { if (cls_index >= MAX_CONSTANTS || ctor_index >= MAX_CONSTANTS) {
parseError(compiler, "A script should contain at most %d " parseError(compiler, "A module should contain at most %d "
"unique constants.", MAX_CONSTANTS); "unique constants.", MAX_CONSTANTS);
} }
// Compile the constructor function. // Compile the constructor function.
ASSERT(compiler->func->ptr == compiler->script->body, OOPS); ASSERT(compiler->func->ptr == compiler->module->body, OOPS);
Func curr_fn; Func curr_fn;
compilerPushFunc(compiler, &curr_fn, cls->ctor, ctor_index); compilerPushFunc(compiler, &curr_fn, cls->ctor, ctor_index);
compilerEnterBlock(compiler); compilerEnterBlock(compiler);
@ -2153,12 +2152,12 @@ static int compileClass(Compiler* compiler) {
const char* f_name = compiler->parser.previous.start; const char* f_name = compiler->parser.previous.start;
int f_len = compiler->parser.previous.length; int f_len = compiler->parser.previous.length;
uint32_t f_index = scriptAddName(compiler->script, compiler->parser.vm, uint32_t f_index = moduleAddName(compiler->module, compiler->parser.vm,
f_name, f_len); f_name, f_len);
String* new_name = compiler->script->names.data[f_index]; String* new_name = compiler->module->names.data[f_index];
for (uint32_t i = 0; i < cls->field_names.count; i++) { for (uint32_t i = 0; i < cls->field_names.count; i++) {
String* prev = compiler->script->names.data[cls->field_names.data[i]]; String* prev = compiler->module->names.data[cls->field_names.data[i]];
if (IS_STR_EQ(new_name, prev)) { if (IS_STR_EQ(new_name, prev)) {
parseError(compiler, "Class field with name '%s' already exists.", parseError(compiler, "Class field with name '%s' already exists.",
new_name->data); new_name->data);
@ -2194,7 +2193,7 @@ static int compileClass(Compiler* compiler) {
return -1; // TODO; return -1; // TODO;
} }
// Compile a function and return it's index in the script's function buffer. // Compile a function and return it's index in the module's function buffer.
static int compileFunction(Compiler* compiler, FuncType fn_type) { static int compileFunction(Compiler* compiler, FuncType fn_type) {
const char* name; const char* name;
@ -2212,10 +2211,10 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) {
int fn_index; int fn_index;
Function* func = newFunction(compiler->parser.vm, name, name_length, Function* func = newFunction(compiler->parser.vm, name, name_length,
compiler->script, fn_type == FN_NATIVE, NULL, compiler->module, fn_type == FN_NATIVE, NULL,
&fn_index); &fn_index);
if (fn_index >= MAX_CONSTANTS) { if (fn_index >= MAX_CONSTANTS) {
parseError(compiler, "A script should contain at most %d " parseError(compiler, "A module should contain at most %d "
"unique constants.", MAX_CONSTANTS); "unique constants.", MAX_CONSTANTS);
} }
@ -2225,7 +2224,7 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) {
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
int name_line = compiler->parser.previous.line; int name_line = compiler->parser.previous.line;
int g_index = compilerAddVariable(compiler, name, name_length, name_line); int g_index = compilerAddVariable(compiler, name, name_length, name_line);
scriptSetGlobal(compiler->script, g_index, VAR_OBJ(func)); moduleSetGlobal(compiler->module, g_index, VAR_OBJ(func));
} }
Func curr_fn; Func curr_fn;
@ -2330,9 +2329,9 @@ static void compileBlockBody(Compiler* compiler, BlockType type) {
} }
// Import a file at the given path (first it'll be resolved from the current // Import a file at the given path (first it'll be resolved from the current
// path) and return it as a script pointer. And it'll emit opcodes to push // path) and return it as a module pointer. And it'll emit opcodes to push
// that script to the stack. // that module to the stack.
static Script* importFile(Compiler* compiler, const char* path) { static Module* importFile(Compiler* compiler, const char* path) {
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
PKVM* vm = compiler->parser.vm; PKVM* vm = compiler->parser.vm;
@ -2340,33 +2339,34 @@ static Script* importFile(Compiler* compiler, const char* path) {
// Resolve the path. // Resolve the path.
PkStringPtr resolved = { path, NULL, NULL }; PkStringPtr resolved = { path, NULL, NULL };
if (vm->config.resolve_path_fn != NULL) { if (vm->config.resolve_path_fn != NULL) {
resolved = vm->config.resolve_path_fn(vm, compiler->script->path->data, resolved = vm->config.resolve_path_fn(vm, compiler->module->path->data,
path); path);
} }
if (resolved.string == NULL) { if (resolved.string == NULL) {
parseError(compiler, "Cannot resolve path '%s' from '%s'", path, parseError(compiler, "Cannot resolve path '%s' from '%s'", path,
compiler->script->path->data); compiler->module->path->data);
} }
// Create new string for the resolved path. And free the resolved path. // Create new string for the resolved path. And free the resolved path.
int index = (int)scriptAddName(compiler->script, compiler->parser.vm, int index = (int)moduleAddName(compiler->module, compiler->parser.vm,
resolved.string, (uint32_t)strlen(resolved.string)); resolved.string, (uint32_t)strlen(resolved.string));
String* path_name = compiler->script->names.data[index]; String* path_name = compiler->module->names.data[index];
if (resolved.on_done != NULL) resolved.on_done(vm, resolved); if (resolved.on_done != NULL) resolved.on_done(vm, resolved);
// Check if the script already exists. // Check if the script already compiled and cached in the PKVM.
Var entry = mapGet(vm->scripts, VAR_OBJ(path_name)); Var entry = mapGet(vm->modules, VAR_OBJ(path_name));
if (!IS_UNDEF(entry)) { if (!IS_UNDEF(entry)) {
ASSERT(IS_OBJ_TYPE(entry, OBJ_SCRIPT), OOPS); ASSERT(IS_OBJ_TYPE(entry, OBJ_MODULE), OOPS);
// Push the script on the stack. // Push the compiled script on the stack.
emitOpcode(compiler, OP_IMPORT); emitOpcode(compiler, OP_IMPORT);
emitShort(compiler, index); emitShort(compiler, index);
return (Script*)AS_OBJ(entry); return (Module*)AS_OBJ(entry);
} }
// The script not exists, make sure we have the script loading api function. // The script not exists in the VM, make sure we have the script loading
// api function.
if (vm->config.load_script_fn == NULL) { if (vm->config.load_script_fn == NULL) {
parseError(compiler, "Cannot import. The hosting application haven't " parseError(compiler, "Cannot import. The hosting application haven't "
"registered the script loading API"); "registered the script loading API");
@ -2380,24 +2380,24 @@ static Script* importFile(Compiler* compiler, const char* path) {
return NULL; return NULL;
} }
// Make a new script and to compile it. // Make a new module and to compile it.
Script* scr = newScript(vm, path_name, false); Module* module = newModule(vm, path_name, false);
vmPushTempRef(vm, &scr->_super); // scr. vmPushTempRef(vm, &module->_super); // scr.
mapSet(vm, vm->scripts, VAR_OBJ(path_name), VAR_OBJ(scr)); mapSet(vm, vm->modules, VAR_OBJ(path_name), VAR_OBJ(module));
vmPopTempRef(vm); // scr. vmPopTempRef(vm); // scr.
// Push the script on the stack. // Push the compiled script on the stack.
emitOpcode(compiler, OP_IMPORT); emitOpcode(compiler, OP_IMPORT);
emitShort(compiler, index); emitShort(compiler, index);
// Option for the compilation, even if we're running on repl mode the // Even if we're running on repl mode the imported module cannot run on
// imported script cannot run on repl mode. // repl mode.
PkCompileOptions options = pkNewCompilerOptions(); PkCompileOptions options = pkNewCompilerOptions();
if (compiler->options) options = *compiler->options; if (compiler->options) options = *compiler->options;
options.repl_mode = false; options.repl_mode = false;
// Compile the source to the script and clean the source. // Compile the source to the module and clean the source.
PkResult result = compile(vm, scr, source.string, &options); PkResult result = compile(vm, module, source.string, &options);
if (source.on_done != NULL) source.on_done(vm, source); if (source.on_done != NULL) source.on_done(vm, source);
if (result != PK_RESULT_SUCCESS) { if (result != PK_RESULT_SUCCESS) {
@ -2405,41 +2405,41 @@ static Script* importFile(Compiler* compiler, const char* path) {
path_name->data); path_name->data);
} }
return scr; return module;
} }
// Import the core library from the vm's core_libs and it'll emit opcodes to // Import the native module from the PKVM's core_libs and it'll emit opcodes
// push that script to the stack. // to push that module to the stack.
static Script* importCoreLib(Compiler* compiler, const char* name_start, static Module* importCoreLib(Compiler* compiler, const char* name_start,
int name_length) { int name_length) {
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
// Add the name to the script's name buffer, we need it as a key to the // Add the name to the module's name buffer, we need it as a key to the
// vm's script cache. // PKVM's module cache.
int index = (int)scriptAddName(compiler->script, compiler->parser.vm, int index = (int)moduleAddName(compiler->module, compiler->parser.vm,
name_start, name_length); name_start, name_length);
String* module = compiler->script->names.data[index]; String* module_name = compiler->module->names.data[index];
Var entry = mapGet(compiler->parser.vm->core_libs, VAR_OBJ(module)); Var entry = mapGet(compiler->parser.vm->core_libs, VAR_OBJ(module_name));
if (IS_UNDEF(entry)) { if (IS_UNDEF(entry)) {
parseError(compiler, "No module named '%s' exists.", module->data); parseError(compiler, "No module named '%s' exists.", module_name->data);
return NULL; return NULL;
} }
// Push the script on the stack. // Push the module on the stack.
emitOpcode(compiler, OP_IMPORT); emitOpcode(compiler, OP_IMPORT);
emitShort(compiler, index); emitShort(compiler, index);
ASSERT(IS_OBJ_TYPE(entry, OBJ_SCRIPT), OOPS); ASSERT(IS_OBJ_TYPE(entry, OBJ_MODULE), OOPS);
return (Script*)AS_OBJ(entry); return (Module*)AS_OBJ(entry);
} }
// Push the imported script on the stack and return the pointer. It could be // Push the imported module on the stack and return the pointer. It could be
// either core library or a local import. // either core library or a local import.
static inline Script* compilerImport(Compiler* compiler) { static inline Module* compilerImport(Compiler* compiler) {
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
// Get the script (from core libs or vm's cache or compile new one). // Get the module (from native libs or VM's cache or compile new one).
// And push it on the stack. // And push it on the stack.
if (match(compiler, TK_NAME)) { //< Core library. if (match(compiler, TK_NAME)) { //< Core library.
return importCoreLib(compiler, compiler->parser.previous.start, return importCoreLib(compiler, compiler->parser.previous.start,
@ -2489,7 +2489,7 @@ static int compilerImportName(Compiler* compiler, int line,
} }
// This will called by the compilerImportAll() function to import a single // This will called by the compilerImportAll() function to import a single
// entry from the imported script. (could be a function or global variable). // entry from the imported module. (could be a function or global variable).
static void compilerImportSingleEntry(Compiler* compiler, static void compilerImportSingleEntry(Compiler* compiler,
const char* name, uint32_t length) { const char* name, uint32_t length) {
@ -2500,11 +2500,11 @@ static void compilerImportSingleEntry(Compiler* compiler,
// Line number of the variables which will be bind to the imported symbol. // Line number of the variables which will be bind to the imported symbol.
int line = compiler->parser.previous.line; int line = compiler->parser.previous.line;
// Add the name to the **current** script's name buffer. // Add the name to the **current** module's name buffer.
int name_index = (int)scriptAddName(compiler->script, compiler->parser.vm, int name_index = (int)moduleAddName(compiler->module, compiler->parser.vm,
name, length); name, length);
// Get the function from the script. // Get the global/function/class from the module.
emitOpcode(compiler, OP_GET_ATTRIB_KEEP); emitOpcode(compiler, OP_GET_ATTRIB_KEEP);
emitShort(compiler, name_index); emitShort(compiler, name_index);
@ -2513,18 +2513,18 @@ static void compilerImportSingleEntry(Compiler* compiler,
emitOpcode(compiler, OP_POP); emitOpcode(compiler, OP_POP);
} }
// Import all from the script, which is also would be at the top of the stack // Import all from the module, 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, Module* module) {
ASSERT(script != NULL, OOPS); ASSERT(module != NULL, OOPS);
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
// Import all globals. // Import all globals.
ASSERT(script->global_names.count == script->globals.count, OOPS); ASSERT(module->global_names.count == module->globals.count, OOPS);
for (uint32_t i = 0; i < script->globals.count; i++) { for (uint32_t i = 0; i < module->globals.count; i++) {
ASSERT(script->global_names.data[i] < script->names.count, OOPS); ASSERT(module->global_names.data[i] < module->names.count, OOPS);
const String* name = script->names.data[script->global_names.data[i]]; const String* name = module->names.data[module->global_names.data[i]];
compilerImportSingleEntry(compiler, name->data, name->length); compilerImportSingleEntry(compiler, name->data, name->length);
} }
@ -2536,9 +2536,9 @@ static void compileFromImport(Compiler* compiler) {
// Import the library and push it on the stack. If the import failed // Import the library and push it on the stack. If the import failed
// lib_from would be NULL. // lib_from would be NULL.
Script* lib_from = compilerImport(compiler); Module* lib_from = compilerImport(compiler);
// At this point the script would be on the stack before executing the next // At this point the module would be on the stack before executing the next
// instruction. // instruction.
consume(compiler, TK_IMPORT, "Expected keyword 'import'."); consume(compiler, TK_IMPORT, "Expected keyword 'import'.");
@ -2548,14 +2548,14 @@ static void compileFromImport(Compiler* compiler) {
} else { } else {
do { do {
// Consume the symbol name to import from the script. // Consume the symbol name to import from the module.
consume(compiler, TK_NAME, "Expected symbol to import."); consume(compiler, TK_NAME, "Expected symbol to import.");
const char* name = compiler->parser.previous.start; const char* name = compiler->parser.previous.start;
uint32_t length = (uint32_t)compiler->parser.previous.length; uint32_t length = (uint32_t)compiler->parser.previous.length;
int line = compiler->parser.previous.line; int line = compiler->parser.previous.line;
// Add the name of the symbol to the names buffer. // Add the name of the symbol to the names buffer.
int name_index = (int)scriptAddName(compiler->script, int name_index = (int)moduleAddName(compiler->module,
compiler->parser.vm, compiler->parser.vm,
name, length); name, length);
@ -2600,9 +2600,9 @@ static void compileRegularImport(Compiler* compiler) {
// Import the library and push it on the stack. If it cannot import, // Import the library and push it on the stack. If it cannot import,
// the lib would be null, but we're not terminating here, just continue // the lib would be null, but we're not terminating here, just continue
// parsing for cascaded errors. // parsing for cascaded errors.
Script* lib = compilerImport(compiler); Module* lib = compilerImport(compiler);
// variable to bind the imported script. // variable to bind the imported module.
int var_index = -1; int var_index = -1;
// Check if it has an alias, if so bind the variable with that name. // Check if it has an alias, if so bind the variable with that name.
@ -2621,7 +2621,7 @@ static void compileRegularImport(Compiler* compiler) {
} else { } else {
// If it has a module name use it as binding variable. // If it has a module name use it as binding variable.
// Core libs names are it's module name but for local libs it's optional // Core libs names are it's module name but for local libs it's optional
// to define a module name for a script. // to define a module name for a module.
if (lib && lib->name != NULL) { if (lib && lib->name != NULL) {
// Get the variable to bind the imported symbol, if we already have a // Get the variable to bind the imported symbol, if we already have a
@ -2879,7 +2879,7 @@ static void compileStatement(Compiler* compiler) {
// If running REPL mode, print the expression's evaluated value. // If running REPL mode, print the expression's evaluated value.
if (compiler->options && compiler->options->repl_mode && if (compiler->options && compiler->options->repl_mode &&
compiler->func->ptr == compiler->script->body && compiler->func->ptr == compiler->module->body &&
is_expression /*&& compiler->scope_depth == DEPTH_GLOBAL*/) { is_expression /*&& compiler->scope_depth == DEPTH_GLOBAL*/) {
emitOpcode(compiler, OP_REPL_PRINT); emitOpcode(compiler, OP_REPL_PRINT);
} }
@ -2887,7 +2887,7 @@ static void compileStatement(Compiler* compiler) {
if (is_temporary) emitOpcode(compiler, OP_POP); if (is_temporary) emitOpcode(compiler, OP_POP);
} }
// Compile statements that are only valid at the top level of the script. Such // Compile statements that are only valid at the top level of the module. Such
// 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) {
@ -2925,7 +2925,7 @@ static void compileTopLevelStatement(Compiler* compiler) {
} }
PkResult compile(PKVM* vm, Script* script, const char* source, PkResult compile(PKVM* vm, Module* module, const char* source,
const PkCompileOptions* options) { const PkCompileOptions* options) {
// Skip utf8 BOM if there is any. // Skip utf8 BOM if there is any.
@ -2933,33 +2933,33 @@ PkResult compile(PKVM* vm, Script* script, const char* source,
Compiler _compiler; Compiler _compiler;
Compiler* compiler = &_compiler; //< Compiler pointer for quick access. Compiler* compiler = &_compiler; //< Compiler pointer for quick access.
compilerInit(compiler, vm, source, script, options); compilerInit(compiler, vm, source, module, options);
// If compiling for an imported script the vm->compiler would be the compiler // If compiling for an imported module the vm->compiler would be the compiler
// of the script that imported this script. Add the all the compilers into a // of the module that imported this module. Add the all the compilers into a
// link list. // link list.
compiler->next_compiler = vm->compiler; compiler->next_compiler = vm->compiler;
vm->compiler = compiler; vm->compiler = compiler;
// If the script doesn't has a body by default, it's probably was created by // If the module doesn't has a body by default, it's probably was created by
// the native api function (pkNewModule() that'll return a module without a // the native api function (pkNewModule() that'll return a module without a
// main function) so just create and add the function here. // main function) so just create and add the function here.
if (script->body == NULL) scriptAddMain(vm, script); if (module->body == NULL) moduleAddMain(vm, module);
// If we're compiling for a script that was already compiled (when running // If we're compiling for a module that was already compiled (when running
// REPL or evaluating an expression) we don't need the old main anymore. // REPL or evaluating an expression) we don't need the old main anymore.
// just use the globals and functions of the script and use a new body func. // just use the globals and functions of the module and use a new body func.
pkByteBufferClear(&script->body->fn->opcodes, vm); pkByteBufferClear(&module->body->fn->opcodes, vm);
// Remember the count of constants, names, and globals, If the compilation // Remember the count of constants, names, and globals, If the compilation
// failed discard all of them and roll back. // failed discard all of them and roll back.
uint32_t constants_count = script->constants.count; uint32_t constants_count = module->constants.count;
uint32_t names_count = script->names.count; uint32_t names_count = module->names.count;
uint32_t globals_count = script->globals.count; uint32_t globals_count = module->globals.count;
Func curr_fn; Func curr_fn;
curr_fn.depth = DEPTH_SCRIPT; curr_fn.depth = DEPTH_MODULE;
curr_fn.ptr = script->body; curr_fn.ptr = module->body;
curr_fn.outer_func = NULL; curr_fn.outer_func = NULL;
compiler->func = &curr_fn; compiler->func = &curr_fn;
@ -2970,17 +2970,17 @@ PkResult compile(PKVM* vm, Script* script, const char* source,
if (match(compiler, TK_MODULE)) { if (match(compiler, TK_MODULE)) {
// If the script running a REPL or compiled multiple times by hosting // If the module running a REPL or compiled multiple times by hosting
// application module attribute might already set. In that case make it // application module attribute might already set. In that case make it
// Compile error. // Compile error.
if (script->name != NULL) { if (module->name != NULL) {
parseError(compiler, "Module name already defined."); parseError(compiler, "Module name already defined.");
} else { } else {
consume(compiler, TK_NAME, "Expected a name for the module."); consume(compiler, TK_NAME, "Expected a name for the module.");
const char* name = compiler->parser.previous.start; const char* name = compiler->parser.previous.start;
uint32_t len = compiler->parser.previous.length; uint32_t len = compiler->parser.previous.length;
script->name = newStringLength(vm, name, len); module->name = newStringLength(vm, name, len);
consumeEndStatement(compiler); consumeEndStatement(compiler);
} }
} }
@ -2997,7 +2997,7 @@ PkResult compile(PKVM* vm, Script* script, const char* source,
ForwardName* forward = &compiler->parser.forwards[i]; ForwardName* forward = &compiler->parser.forwards[i];
const char* name = forward->name; const char* name = forward->name;
int length = forward->length; int length = forward->length;
int index = scriptGetGlobalIndex(compiler->script, name, (uint32_t)length); int index = moduleGetGlobalIndex(compiler->module, name, (uint32_t)length);
if (index != -1) { if (index != -1) {
patchForward(compiler, forward->func, forward->instruction, index); patchForward(compiler, forward->func, forward->instruction, index);
} else { } else {
@ -3014,13 +3014,13 @@ 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->parser.has_errors) { if (compiler->parser.has_errors) {
script->constants.count = constants_count; module->constants.count = constants_count;
script->names.count = names_count; module->names.count = names_count;
script->globals.count = script->global_names.count = globals_count; module->globals.count = module->global_names.count = globals_count;
} }
#if DUMP_BYTECODE #if DUMP_BYTECODE
dumpFunctionCode(compiler->parser.vm, script->body); dumpFunctionCode(compiler->parser.vm, module->body);
#endif #endif
// Return the compilation result. // Return the compilation result.
@ -3033,24 +3033,24 @@ PkResult compile(PKVM* vm, Script* script, const char* source,
return PK_RESULT_SUCCESS; return PK_RESULT_SUCCESS;
} }
PkResult pkCompileModule(PKVM* vm, PkHandle* module, PkStringPtr source, PkResult pkCompileModule(PKVM* vm, PkHandle* module_handle, PkStringPtr source,
const PkCompileOptions* options) { const PkCompileOptions* options) {
__ASSERT(module != NULL, "Argument module was NULL."); __ASSERT(module_handle != NULL, "Argument module was NULL.");
Var scr = module->value; __ASSERT(IS_OBJ_TYPE(module_handle->value, OBJ_MODULE),
__ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), "Given handle is not a module"); "Given handle is not a module.");
Script* script = (Script*)AS_OBJ(scr); Module* module = (Module*)AS_OBJ(module_handle->value);
PkResult result = compile(vm, script, source.string, options); PkResult result = compile(vm, module, source.string, options);
if (source.on_done) source.on_done(vm, source); if (source.on_done) source.on_done(vm, source);
return result; return result;
} }
void compilerMarkObjects(PKVM* vm, Compiler* compiler) { void compilerMarkObjects(PKVM* vm, Compiler* compiler) {
// Mark the script which is currently being compiled. // Mark the module which is currently being compiled.
markObject(vm, &compiler->script->_super); markObject(vm, &compiler->module->_super);
// Mark the string literals (they haven't added to the script's literal // Mark the string literals (they haven't added to the module's literal
// buffer yet). // buffer yet).
markValue(vm, compiler->parser.current.value); markValue(vm, compiler->parser.current.value);
markValue(vm, compiler->parser.previous.value); markValue(vm, compiler->parser.previous.value);

View File

@ -25,11 +25,11 @@ typedef enum {
typedef struct Compiler Compiler; typedef struct Compiler Compiler;
// This will take source code as a cstring, compiles it to pocketlang bytecodes // This will take source code as a cstring, compiles it to pocketlang bytecodes
// and append them to the script's implicit main function ("$(SourceBody)"). // and append them to the module's implicit main function. On a successfull
// On a successfull compilation it'll return PK_RESULT_SUCCESS, otherwise it'll // compilation it'll return PK_RESULT_SUCCESS, otherwise it'll return
// return PK_RESULT_COMPILE_ERROR but if repl_mode set in the [options], and // PK_RESULT_COMPILE_ERROR but if repl_mode set in the [options], and we've
// we've reached and unexpected EOF it'll return PK_RESULT_UNEXPECTED_EOF. // reached and unexpected EOF it'll return PK_RESULT_UNEXPECTED_EOF.
PkResult compile(PKVM* vm, Script* script, const char* source, PkResult compile(PKVM* vm, Module* module, const char* source,
const PkCompileOptions* options); const PkCompileOptions* options);
// Mark the heap allocated objects of the compiler at the garbage collection // Mark the heap allocated objects of the compiler at the garbage collection

View File

@ -36,55 +36,53 @@
/* CORE PUBLIC API */ /* CORE PUBLIC API */
/*****************************************************************************/ /*****************************************************************************/
// Create a new module with the given [name] and returns as a Script* for // Create a new module with the given [name] and returns as a Module* for
// internal. Which will be wrapped by pkNewModule to return a pkHandle*. // internal. Which will be wrapped by pkNewModule to return a pkHandle*.
static Script* newModuleInternal(PKVM* vm, const char* name); static Module* newModuleInternal(PKVM* vm, const char* name);
// Adds a function to the script with the give properties and add the function // Adds a function to the module with the give properties and add the function
// to the module's globals variables. // to the module's globals variables.
static void moduleAddFunctionInternal(PKVM* vm, Script* script, static void moduleAddFunctionInternal(PKVM* vm, Module* module,
const char* name, pkNativeFn fptr, const char* name, pkNativeFn fptr,
int arity, const char* docstring); int arity, const char* docstring);
// pkNewModule implementation (see pocketlang.h for description).
PkHandle* pkNewModule(PKVM* vm, const char* name) { PkHandle* pkNewModule(PKVM* vm, const char* name) {
Script* module = newModuleInternal(vm, name); Module* module = newModuleInternal(vm, name);
return vmNewHandle(vm, VAR_OBJ(module)); return vmNewHandle(vm, VAR_OBJ(module));
} }
// pkModuleAddGlobal implementation (see pocketlang.h for description).
PK_PUBLIC void pkModuleAddGlobal(PKVM* vm, PkHandle* module, PK_PUBLIC void pkModuleAddGlobal(PKVM* vm, PkHandle* module,
const char* name, PkHandle* value) { const char* name, PkHandle* value) {
__ASSERT(module != NULL, "Argument module was NULL."); __ASSERT(module != NULL, "Argument module was NULL.");
__ASSERT(value != NULL, "Argument value was NULL."); __ASSERT(value != NULL, "Argument value was NULL.");
Var scr = module->value; __ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
__ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), "Given handle is not a module"); "Given handle is not a module.");
scriptAddGlobal(vm, (Script*)AS_OBJ(scr), name, (uint32_t)strlen(name), moduleAddGlobal(vm, (Module*)AS_OBJ(module->value),
value->value); name, (uint32_t)strlen(name), value->value);
} }
// pkModuleAddFunction implementation (see pocketlang.h for description).
void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name, void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
pkNativeFn fptr, int arity) { pkNativeFn fptr, int arity) {
__ASSERT(module != NULL, "Argument module was NULL."); __ASSERT(module != NULL, "Argument module was NULL.");
Var scr = module->value; __ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
__ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), "Given handle is not a module"); "Given handle is not a module.");
moduleAddFunctionInternal(vm, (Script*)AS_OBJ(scr), name, fptr, arity, moduleAddFunctionInternal(vm, (Module*)AS_OBJ(module->value),
name, fptr, arity,
NULL /*TODO: Public API for function docstring.*/); NULL /*TODO: Public API for function docstring.*/);
} }
PkHandle* pkGetMainFunction(PKVM* vm, PkHandle* module) { PkHandle* pkGetMainFunction(PKVM* vm, PkHandle* module) {
__ASSERT(module != NULL, "Argument module was NULL."); __ASSERT(module != NULL, "Argument module was NULL.");
Var scr = module->value; __ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
__ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), "Given handle is not a module"); "Given handle is not a module.");
Script* script = (Script*)AS_OBJ(scr); Module* _module = (Module*)AS_OBJ(module->value);
int main_index = scriptGetGlobalIndex(script, IMPLICIT_MAIN_NAME, int main_index = moduleGetGlobalIndex(_module, IMPLICIT_MAIN_NAME,
(uint32_t)strlen(IMPLICIT_MAIN_NAME)); (uint32_t)strlen(IMPLICIT_MAIN_NAME));
if (main_index == -1) return NULL; if (main_index == -1) return NULL;
ASSERT_INDEX(main_index, (int)script->constants.count); ASSERT_INDEX(main_index, (int)_module->constants.count);
return vmNewHandle(vm, script->constants.data[main_index]); return vmNewHandle(vm, _module->constants.data[main_index]);
} }
// A convenient macro to get the nth (1 based) argument of the current // A convenient macro to get the nth (1 based) argument of the current
@ -131,13 +129,11 @@ do { \
} \ } \
} while (false) } while (false)
// pkGetArgc implementation (see pocketlang.h for description).
int pkGetArgc(const PKVM* vm) { int pkGetArgc(const PKVM* vm) {
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime."); __ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
return ARGC; return ARGC;
} }
// pkCheckArgcRange implementation (see pocketlang.h for description).
bool pkCheckArgcRange(PKVM* vm, int argc, int min, int max) { bool pkCheckArgcRange(PKVM* vm, int argc, int min, int max) {
ASSERT(min <= max, "invalid argc range (min > max)."); ASSERT(min <= max, "invalid argc range (min > max).");
@ -157,7 +153,6 @@ bool pkCheckArgcRange(PKVM* vm, int argc, int min, int max) {
return true; return true;
} }
// pkGetArg implementation (see pocketlang.h for description).
PkVar pkGetArg(const PKVM* vm, int arg) { PkVar pkGetArg(const PKVM* vm, int arg) {
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime."); __ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
__ASSERT(arg > 0 || arg <= ARGC, "Invalid argument index."); __ASSERT(arg > 0 || arg <= ARGC, "Invalid argument index.");
@ -165,7 +160,6 @@ PkVar pkGetArg(const PKVM* vm, int arg) {
return &(ARG(arg)); return &(ARG(arg));
} }
// pkGetArgBool implementation (see pocketlang.h for description).
bool pkGetArgBool(PKVM* vm, int arg, bool* value) { bool pkGetArgBool(PKVM* vm, int arg, bool* value) {
CHECK_GET_ARG_API_ERRORS(); CHECK_GET_ARG_API_ERRORS();
@ -174,7 +168,6 @@ bool pkGetArgBool(PKVM* vm, int arg, bool* value) {
return true; return true;
} }
// pkGetArgNumber implementation (see pocketlang.h for description).
bool pkGetArgNumber(PKVM* vm, int arg, double* value) { bool pkGetArgNumber(PKVM* vm, int arg, double* value) {
CHECK_GET_ARG_API_ERRORS(); CHECK_GET_ARG_API_ERRORS();
@ -193,7 +186,6 @@ bool pkGetArgNumber(PKVM* vm, int arg, double* value) {
return true; return true;
} }
// pkGetArgString implementation (see pocketlang.h for description).
bool pkGetArgString(PKVM* vm, int arg, const char** value, uint32_t* length) { bool pkGetArgString(PKVM* vm, int arg, const char** value, uint32_t* length) {
CHECK_GET_ARG_API_ERRORS(); CHECK_GET_ARG_API_ERRORS();
@ -211,7 +203,6 @@ bool pkGetArgString(PKVM* vm, int arg, const char** value, uint32_t* length) {
return true; return true;
} }
// pkGetArgInstance implementation (see pocketlang.h for description).
bool pkGetArgInst(PKVM* vm, int arg, uint32_t id, void** value) { bool pkGetArgInst(PKVM* vm, int arg, uint32_t id, void** value) {
CHECK_GET_ARG_API_ERRORS(); CHECK_GET_ARG_API_ERRORS();
@ -239,7 +230,6 @@ bool pkGetArgInst(PKVM* vm, int arg, uint32_t id, void** value) {
return true; return true;
} }
// pkGetArgValue implementation (see pocketlang.h for description).
bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value) { bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value) {
CHECK_GET_ARG_API_ERRORS(); CHECK_GET_ARG_API_ERRORS();
@ -255,42 +245,34 @@ bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value) {
return true; return true;
} }
// pkReturnNull implementation (see pocketlang.h for description).
void pkReturnNull(PKVM* vm) { void pkReturnNull(PKVM* vm) {
RET(VAR_NULL); RET(VAR_NULL);
} }
// pkReturnBool implementation (see pocketlang.h for description).
void pkReturnBool(PKVM* vm, bool value) { void pkReturnBool(PKVM* vm, bool value) {
RET(VAR_BOOL(value)); RET(VAR_BOOL(value));
} }
// pkReturnNumber implementation (see pocketlang.h for description).
void pkReturnNumber(PKVM* vm, double value) { void pkReturnNumber(PKVM* vm, double value) {
RET(VAR_NUM(value)); RET(VAR_NUM(value));
} }
// pkReturnString implementation (see pocketlang.h for description).
void pkReturnString(PKVM* vm, const char* value) { void pkReturnString(PKVM* vm, const char* value) {
RET(VAR_OBJ(newString(vm, value))); RET(VAR_OBJ(newString(vm, value)));
} }
// pkReturnStringLength implementation (see pocketlang.h for description).
void pkReturnStringLength(PKVM* vm, const char* value, size_t length) { void pkReturnStringLength(PKVM* vm, const char* value, size_t length) {
RET(VAR_OBJ(newStringLength(vm, value, (uint32_t)length))); RET(VAR_OBJ(newStringLength(vm, value, (uint32_t)length)));
} }
// pkReturnValue implementation (see pocketlang.h for description).
void pkReturnValue(PKVM* vm, PkVar value) { void pkReturnValue(PKVM* vm, PkVar value) {
RET(*(Var*)value); RET(*(Var*)value);
} }
// pkReturnHandle implementation (see pocketlang.h for description).
void pkReturnHandle(PKVM* vm, PkHandle* handle) { void pkReturnHandle(PKVM* vm, PkHandle* handle) {
RET(handle->value); RET(handle->value);
} }
// pkReturnInstNative implementation (see pocketlang.h for description).
void pkReturnInstNative(PKVM* vm, void* data, uint32_t id) { void pkReturnInstNative(PKVM* vm, void* data, uint32_t id) {
RET(VAR_OBJ(newInstanceNative(vm, data, id))); RET(VAR_OBJ(newInstanceNative(vm, data, id)));
} }
@ -417,7 +399,6 @@ static inline bool validateCond(PKVM* vm, bool condition, const char* err) {
/* SHARED FUNCTIONS */ /* SHARED FUNCTIONS */
/*****************************************************************************/ /*****************************************************************************/
// findBuiltinFunction implementation (see core.h for description).
int findBuiltinFunction(const PKVM* vm, const char* name, uint32_t length) { int findBuiltinFunction(const PKVM* vm, const char* name, uint32_t length) {
for (uint32_t i = 0; i < vm->builtins_count; i++) { for (uint32_t i = 0; i < vm->builtins_count; i++) {
if (length == vm->builtins[i].length && if (length == vm->builtins[i].length &&
@ -428,24 +409,21 @@ int findBuiltinFunction(const PKVM* vm, const char* name, uint32_t length) {
return -1; return -1;
} }
// getBuiltinFunction implementation (see core.h for description).
Function* getBuiltinFunction(const PKVM* vm, int index) { Function* getBuiltinFunction(const PKVM* vm, int index) {
ASSERT_INDEX((uint32_t)index, vm->builtins_count); ASSERT_INDEX((uint32_t)index, vm->builtins_count);
return vm->builtins[index].fn; return vm->builtins[index].fn;
} }
// getBuiltinFunctionName implementation (see core.h for description).
const char* getBuiltinFunctionName(const PKVM* vm, int index) { const char* getBuiltinFunctionName(const PKVM* vm, int index) {
ASSERT_INDEX((uint32_t)index, vm->builtins_count); ASSERT_INDEX((uint32_t)index, vm->builtins_count);
return vm->builtins[index].name; return vm->builtins[index].name;
} }
// getCoreLib implementation (see core.h for description). Module* getCoreLib(const PKVM* vm, String* name) {
Script* getCoreLib(const PKVM* vm, String* name) {
Var lib = mapGet(vm->core_libs, VAR_OBJ(name)); Var lib = mapGet(vm->core_libs, VAR_OBJ(name));
if (IS_UNDEF(lib)) return NULL; if (IS_UNDEF(lib)) return NULL;
ASSERT(IS_OBJ_TYPE(lib, OBJ_SCRIPT), OOPS); ASSERT(IS_OBJ_TYPE(lib, OBJ_MODULE), OOPS);
return (Script*)AS_OBJ(lib); return (Module*)AS_OBJ(lib);
} }
/*****************************************************************************/ /*****************************************************************************/
@ -777,42 +755,40 @@ DEF(coreMapRemove,
/* CORE MODULE METHODS */ /* CORE MODULE METHODS */
/*****************************************************************************/ /*****************************************************************************/
// Create a module and add it to the vm's core modules, returns the script. // Create a module and add it to the vm's core modules, returns the module.
static Script* newModuleInternal(PKVM* vm, const char* name) { static Module* newModuleInternal(PKVM* vm, const char* name) {
// Create a new Script for the module.
String* _name = newString(vm, name); String* _name = newString(vm, name);
vmPushTempRef(vm, &_name->_super); vmPushTempRef(vm, &_name->_super); // _name
// Check if any module with the same name already exists and assert to the // Check if any module with the same name already exists and assert to the
// hosting application. // hosting application.
if (!IS_UNDEF(mapGet(vm->core_libs, VAR_OBJ(_name)))) { if (!IS_UNDEF(mapGet(vm->core_libs, VAR_OBJ(_name)))) {
vmPopTempRef(vm); // _name
__ASSERT(false, stringFormat(vm, __ASSERT(false, stringFormat(vm,
"A module named '$' already exists", name)->data); "A module named '$' already exists", name)->data);
} }
Script* scr = newScript(vm, _name, true); Module* module = newModule(vm, _name, true);
vmPopTempRef(vm); // _name vmPopTempRef(vm); // _name
// Add the script to core_libs. // Add the module to core_libs.
vmPushTempRef(vm, &scr->_super); vmPushTempRef(vm, &module->_super); // module.
mapSet(vm, vm->core_libs, VAR_OBJ(_name), VAR_OBJ(scr)); mapSet(vm, vm->core_libs, VAR_OBJ(_name), VAR_OBJ(module));
vmPopTempRef(vm); vmPopTempRef(vm); // module.
return scr; return module;
} }
// An internal function to add a function to the given [script]. // An internal function to add a function to the given [module].
static void moduleAddFunctionInternal(PKVM* vm, Script* script, static void moduleAddFunctionInternal(PKVM* vm, Module* module,
const char* name, pkNativeFn fptr, const char* name, pkNativeFn fptr,
int arity, const char* docstring) { int arity, const char* docstring) {
Function* fn = newFunction(vm, name, (int)strlen(name), Function* fn = newFunction(vm, name, (int)strlen(name),
script, true, docstring, NULL); module, true, docstring, NULL);
fn->native = fptr; fn->native = fptr;
fn->arity = arity; fn->arity = arity;
scriptAddGlobal(vm, script, name, (uint32_t)strlen(name), VAR_OBJ(fn)); moduleAddGlobal(vm, module, name, (uint32_t)strlen(name), VAR_OBJ(fn));
} }
// 'lang' library methods. // 'lang' library methods.
@ -1261,7 +1237,7 @@ void initializeCore(PKVM* vm) {
// Core Modules ///////////////////////////////////////////////////////////// // Core Modules /////////////////////////////////////////////////////////////
Script* lang = newModuleInternal(vm, "lang"); Module* lang = newModuleInternal(vm, "lang");
MODULE_ADD_FN(lang, "clock", stdLangClock, 0); MODULE_ADD_FN(lang, "clock", stdLangClock, 0);
MODULE_ADD_FN(lang, "gc", stdLangGC, 0); MODULE_ADD_FN(lang, "gc", stdLangGC, 0);
MODULE_ADD_FN(lang, "disas", stdLangDisas, 1); MODULE_ADD_FN(lang, "disas", stdLangDisas, 1);
@ -1270,7 +1246,7 @@ void initializeCore(PKVM* vm) {
MODULE_ADD_FN(lang, "debug_break", stdLangDebugBreak, 0); MODULE_ADD_FN(lang, "debug_break", stdLangDebugBreak, 0);
#endif #endif
Script* math = newModuleInternal(vm, "math"); Module* math = newModuleInternal(vm, "math");
MODULE_ADD_FN(math, "floor", stdMathFloor, 1); MODULE_ADD_FN(math, "floor", stdMathFloor, 1);
MODULE_ADD_FN(math, "ceil", stdMathCeil, 1); MODULE_ADD_FN(math, "ceil", stdMathCeil, 1);
MODULE_ADD_FN(math, "pow", stdMathPow, 2); MODULE_ADD_FN(math, "pow", stdMathPow, 2);
@ -1300,9 +1276,9 @@ void initializeCore(PKVM* vm) {
// Note that currently it's mutable (since it's a global variable, not // Note that currently it's mutable (since it's a global variable, not
// constant and pocketlang doesn't support constant) so the user shouldn't // constant and pocketlang doesn't support constant) so the user shouldn't
// modify the PI, like in python. // modify the PI, like in python.
scriptAddGlobal(vm, math, "PI", 2, VAR_NUM(M_PI)); moduleAddGlobal(vm, math, "PI", 2, VAR_NUM(M_PI));
Script* fiber = newModuleInternal(vm, "Fiber"); Module* fiber = newModuleInternal(vm, "Fiber");
MODULE_ADD_FN(fiber, "new", stdFiberNew, 1); MODULE_ADD_FN(fiber, "new", stdFiberNew, 1);
MODULE_ADD_FN(fiber, "run", stdFiberRun, -1); MODULE_ADD_FN(fiber, "run", stdFiberRun, -1);
MODULE_ADD_FN(fiber, "resume", stdFiberResume, -1); MODULE_ADD_FN(fiber, "resume", stdFiberResume, -1);
@ -1349,7 +1325,7 @@ Var varAdd(PKVM* vm, Var v1, Var v2) {
case OBJ_MAP: case OBJ_MAP:
case OBJ_RANGE: case OBJ_RANGE:
case OBJ_SCRIPT: case OBJ_MODULE:
case OBJ_FUNC: case OBJ_FUNC:
case OBJ_CLOSURE: case OBJ_CLOSURE:
case OBJ_UPVALUE: case OBJ_UPVALUE:
@ -1562,7 +1538,7 @@ bool varContains(PKVM* vm, Var elem, Var container) {
} break; } break;
case OBJ_RANGE: case OBJ_RANGE:
case OBJ_SCRIPT: case OBJ_MODULE:
case OBJ_FUNC: case OBJ_FUNC:
case OBJ_CLOSURE: case OBJ_CLOSURE:
case OBJ_UPVALUE: case OBJ_UPVALUE:
@ -1670,15 +1646,15 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
UNREACHABLE(); UNREACHABLE();
} }
case OBJ_SCRIPT: case OBJ_MODULE:
{ {
Script* scr = (Script*)obj; Module* module = (Module*)obj;
// Search in globals. // Search in globals.
int index = scriptGetGlobalIndex(scr, attrib->data, attrib->length); int index = moduleGetGlobalIndex(module, attrib->data, attrib->length);
if (index != -1) { if (index != -1) {
ASSERT_INDEX((uint32_t)index, scr->globals.count); ASSERT_INDEX((uint32_t)index, module->globals.count);
return scr->globals.data[index]; return module->globals.data[index];
} }
ERR_NO_ATTRIB(vm, on, attrib); ERR_NO_ATTRIB(vm, on, attrib);
@ -1795,14 +1771,14 @@ do { \
ERR_NO_ATTRIB(vm, on, attrib); ERR_NO_ATTRIB(vm, on, attrib);
return; return;
case OBJ_SCRIPT: { case OBJ_MODULE: {
Script* scr = (Script*)obj; Module* module = (Module*)obj;
// Check globals. // Check globals.
int index = scriptGetGlobalIndex(scr, attrib->data, attrib->length); int index = moduleGetGlobalIndex(module, attrib->data, attrib->length);
if (index != -1) { if (index != -1) {
ASSERT_INDEX((uint32_t)index, scr->globals.count); ASSERT_INDEX((uint32_t)index, module->globals.count);
scr->globals.data[index] = value; module->globals.data[index] = value;
return; return;
} }
@ -1909,7 +1885,7 @@ Var varGetSubscript(PKVM* vm, Var on, Var key) {
} }
case OBJ_RANGE: case OBJ_RANGE:
case OBJ_SCRIPT: case OBJ_MODULE:
case OBJ_FUNC: case OBJ_FUNC:
case OBJ_CLOSURE: case OBJ_CLOSURE:
case OBJ_UPVALUE: case OBJ_UPVALUE:
@ -1961,7 +1937,7 @@ void varsetSubscript(PKVM* vm, Var on, Var key, Var value) {
} }
case OBJ_RANGE: case OBJ_RANGE:
case OBJ_SCRIPT: case OBJ_MODULE:
case OBJ_FUNC: case OBJ_FUNC:
case OBJ_CLOSURE: case OBJ_CLOSURE:
case OBJ_UPVALUE: case OBJ_UPVALUE:

View File

@ -25,7 +25,7 @@ const char* getBuiltinFunctionName(const PKVM* vm, int index);
// Return the core library with the [name] if exists in the core libs, // Return the core library with the [name] if exists in the core libs,
// otherwise returns NULL. // otherwise returns NULL.
Script* getCoreLib(const PKVM* vm, String* name); Module* getCoreLib(const PKVM* vm, String* name);
/*****************************************************************************/ /*****************************************************************************/
/* OPERATORS */ /* OPERATORS */

View File

@ -365,11 +365,11 @@ void dumpGlobalValues(PKVM* vm) {
int frame_ind = fiber->frame_count - 1; int frame_ind = fiber->frame_count - 1;
ASSERT(frame_ind >= 0, OOPS); ASSERT(frame_ind >= 0, OOPS);
CallFrame* frame = &fiber->frames[frame_ind]; CallFrame* frame = &fiber->frames[frame_ind];
Script* scr = frame->fn->owner; Module* module = frame->fn->owner;
for (uint32_t i = 0; i < scr->global_names.count; i++) { for (uint32_t i = 0; i < module->global_names.count; i++) {
String* name = scr->names.data[scr->global_names.data[i]]; String* name = module->names.data[module->global_names.data[i]];
Var value = scr->globals.data[i]; Var value = module->globals.data[i];
printf("%10s = ", name->data); printf("%10s = ", name->data);
dumpValue(vm, value); dumpValue(vm, value);
printf("\n"); printf("\n");

View File

@ -32,7 +32,7 @@ PkVarType pkGetValueType(const PkVar value) {
case OBJ_LIST: return PK_LIST; case OBJ_LIST: return PK_LIST;
case OBJ_MAP: return PK_MAP; case OBJ_MAP: return PK_MAP;
case OBJ_RANGE: return PK_RANGE; case OBJ_RANGE: return PK_RANGE;
case OBJ_SCRIPT: return PK_SCRIPT; case OBJ_MODULE: return PK_MODULE;
case OBJ_FUNC: return PK_FUNCTION; case OBJ_FUNC: return PK_FUNCTION;
case OBJ_FIBER: return PK_FIBER; case OBJ_FIBER: return PK_FIBER;
case OBJ_CLASS: return PK_CLASS; case OBJ_CLASS: return PK_CLASS;
@ -194,27 +194,27 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
vm->bytes_allocated += sizeof(Range); vm->bytes_allocated += sizeof(Range);
} break; } break;
case OBJ_SCRIPT: case OBJ_MODULE:
{ {
Script* scr = (Script*)obj; Module* module = (Module*)obj;
vm->bytes_allocated += sizeof(Script); vm->bytes_allocated += sizeof(Module);
markObject(vm, &scr->path->_super); markObject(vm, &module->path->_super);
markObject(vm, &scr->name->_super); markObject(vm, &module->name->_super);
markVarBuffer(vm, &scr->globals); markVarBuffer(vm, &module->globals);
vm->bytes_allocated += sizeof(Var) * scr->globals.capacity; vm->bytes_allocated += sizeof(Var) * module->globals.capacity;
// Integer buffer has no gray call. // Integer buffer has no gray call.
vm->bytes_allocated += sizeof(uint32_t) * scr->global_names.capacity; vm->bytes_allocated += sizeof(uint32_t) * module->global_names.capacity;
markVarBuffer(vm, &scr->constants); markVarBuffer(vm, &module->constants);
vm->bytes_allocated += sizeof(Var) * scr->constants.capacity; vm->bytes_allocated += sizeof(Var) * module->constants.capacity;
markStringBuffer(vm, &scr->names); markStringBuffer(vm, &module->names);
vm->bytes_allocated += sizeof(String*) * scr->names.capacity; vm->bytes_allocated += sizeof(String*) * module->names.capacity;
markObject(vm, &scr->body->_super); markObject(vm, &module->body->_super);
} break; } break;
case OBJ_FUNC: case OBJ_FUNC:
@ -379,46 +379,47 @@ Range* newRange(PKVM* vm, double from, double to) {
return range; return range;
} }
Script* newScript(PKVM* vm, String* name, bool is_core) { Module* newModule(PKVM* vm, String* name, bool is_core) {
Script* script = ALLOCATE(vm, Script); Module* module = ALLOCATE(vm, Module);
varInitObject(&script->_super, vm, OBJ_SCRIPT); varInitObject(&module->_super, vm, OBJ_MODULE);
ASSERT(name != NULL && name->length > 0, OOPS); ASSERT(name != NULL && name->length > 0, OOPS);
script->path = name; module->path = name;
script->name = NULL; module->name = NULL;
script->initialized = is_core; module->initialized = is_core;
script->body = NULL; module->body = NULL;
// Core modules has its name as the module name. // Core modules has its name as the module name.
if (is_core) script->name = name; if (is_core) module->name = name;
pkVarBufferInit(&script->globals); pkVarBufferInit(&module->globals);
pkUintBufferInit(&script->global_names); pkUintBufferInit(&module->global_names);
pkVarBufferInit(&script->constants); pkVarBufferInit(&module->constants);
pkStringBufferInit(&script->names); pkStringBufferInit(&module->names);
// Add a implicit main function and the '__file__' global to the module, only // Add a implicit main function and the '__file__' global to the module, only
// if it's not a core module. // if it's not a core module.
if (!is_core) { if (!is_core) {
vmPushTempRef(vm, &script->_super); vmPushTempRef(vm, &module->_super); // module.
scriptAddMain(vm, script);
moduleAddMain(vm, module);
// Add '__file__' variable with it's path as value. If the path starts with // 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__. // '@' It's a special file (@(REPL) or @(TRY)) and don't define __file__.
if (script->path->data[0] != SPECIAL_NAME_CHAR) { if (module->path->data[0] != SPECIAL_NAME_CHAR) {
scriptAddGlobal(vm, script, "__file__", 8, VAR_OBJ(script->path)); moduleAddGlobal(vm, module, "__file__", 8, VAR_OBJ(module->path));
} }
// TODO: Add ARGV as a global. // TODO: Add ARGV as a global.
vmPopTempRef(vm); // script. vmPopTempRef(vm); // module.
} }
return script; return module;
} }
Function* newFunction(PKVM* vm, const char* name, int length, Script* owner, Function* newFunction(PKVM* vm, const char* name, int length, Module* owner,
bool is_native, const char* docstring, bool is_native, const char* docstring,
int* fn_index) { int* fn_index) {
@ -433,10 +434,10 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner,
func->owner = NULL; func->owner = NULL;
} else { } else {
uint32_t _fn_index = scriptAddConstant(vm, owner, VAR_OBJ(func)); uint32_t _fn_index = moduleAddConstant(vm, owner, VAR_OBJ(func));
if (fn_index) *fn_index = _fn_index; if (fn_index) *fn_index = _fn_index;
uint32_t name_index = scriptAddName(owner, vm, name, length); uint32_t name_index = moduleAddName(owner, vm, name, length);
func->name = owner->names.data[name_index]->data; func->name = owner->names.data[name_index]->data;
func->owner = owner; func->owner = owner;
@ -457,7 +458,6 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner,
func->fn = fn; func->fn = fn;
} }
// Both native and script (TODO:) functions support docstring.
func->docstring = docstring; func->docstring = docstring;
vmPopTempRef(vm); // func vmPopTempRef(vm); // func
@ -536,34 +536,35 @@ Fiber* newFiber(PKVM* vm, Function* fn) {
return fiber; return fiber;
} }
Class* newClass(PKVM* vm, Script* scr, const char* name, uint32_t length, Class* newClass(PKVM* vm, Module* module, const char* name, uint32_t length,
int* cls_index, int* ctor_index) { int* cls_index, int* ctor_index) {
Class* cls = ALLOCATE(vm, Class); Class* cls = ALLOCATE(vm, Class);
varInitObject(&cls->_super, vm, OBJ_CLASS); varInitObject(&cls->_super, vm, OBJ_CLASS);
vmPushTempRef(vm, &cls->_super); // type. vmPushTempRef(vm, &cls->_super); // class.
uint32_t _cls_index = scriptAddConstant(vm, scr, VAR_OBJ(cls)); uint32_t _cls_index = moduleAddConstant(vm, module, VAR_OBJ(cls));
if (cls_index) *cls_index = (int)_cls_index; if (cls_index) *cls_index = (int)_cls_index;
pkUintBufferInit(&cls->field_names); pkUintBufferInit(&cls->field_names);
cls->owner = scr; cls->owner = module;
cls->name = scriptAddName(scr, vm, name, length); cls->name = moduleAddName(module, vm, name, length);
// FIXME: // Since characters '@' and '$' are special in stringFormat, and they
// Make it possible to escape '@' and '$' character in formated string and // currently cannot be escaped (TODO), a string (char array) created
// replace below '%' with excaped '\@' (SPECIAL_NAME_CHAR) character. // for that character and passed as C string format.
String* ty_name = scr->names.data[cls->name]; char special[2] = { SPECIAL_NAME_CHAR, '\0' };
String* ctor_name = stringFormat(vm, "%(Ctor:@)", ty_name); String* cls_name = module->names.data[cls->name];
String* ctor_name = stringFormat(vm, "$(Ctor:@)", special, cls_name);
// Constructor. // Constructor.
vmPushTempRef(vm, &ctor_name->_super); // ctor_name vmPushTempRef(vm, &ctor_name->_super); // ctor_name
cls->ctor = newFunction(vm, ctor_name->data, ctor_name->length, cls->ctor = newFunction(vm, ctor_name->data, ctor_name->length,
scr, false, NULL, ctor_index); module, false, NULL, ctor_index);
vmPopTempRef(vm); // ctor_name vmPopTempRef(vm); // ctor_name
vmPopTempRef(vm); // type. vmPopTempRef(vm); // class.
return cls; return cls;
} }
@ -849,7 +850,7 @@ static uint32_t _hashObject(Object* obj) {
return utilHashNumber(range->from) ^ utilHashNumber(range->to); return utilHashNumber(range->from) ^ utilHashNumber(range->to);
} }
case OBJ_SCRIPT: case OBJ_MODULE:
case OBJ_FUNC: case OBJ_FUNC:
case OBJ_FIBER: case OBJ_FIBER:
case OBJ_CLASS: case OBJ_CLASS:
@ -1068,12 +1069,12 @@ void freeObject(PKVM* vm, Object* self) {
case OBJ_RANGE: case OBJ_RANGE:
break; break;
case OBJ_SCRIPT: { case OBJ_MODULE: {
Script* scr = (Script*)self; Module* module = (Module*)self;
pkVarBufferClear(&scr->globals, vm); pkVarBufferClear(&module->globals, vm);
pkUintBufferClear(&scr->global_names, vm); pkUintBufferClear(&module->global_names, vm);
pkVarBufferClear(&scr->constants, vm); pkVarBufferClear(&module->constants, vm);
pkStringBufferClear(&scr->names, vm); pkStringBufferClear(&module->names, vm);
} break; } break;
case OBJ_FUNC: { case OBJ_FUNC: {
@ -1123,21 +1124,21 @@ void freeObject(PKVM* vm, Object* self) {
DEALLOCATE(vm, self); DEALLOCATE(vm, self);
} }
uint32_t scriptAddConstant(PKVM* vm, Script* script, Var value) { uint32_t moduleAddConstant(PKVM* vm, Module* module, Var value) {
for (uint32_t i = 0; i < script->constants.count; i++) { for (uint32_t i = 0; i < module->constants.count; i++) {
if (isValuesSame(script->constants.data[i], value)) { if (isValuesSame(module->constants.data[i], value)) {
return i; return i;
} }
} }
pkVarBufferWrite(&script->constants, vm, value); pkVarBufferWrite(&module->constants, vm, value);
return (int)script->constants.count - 1; return (int)module->constants.count - 1;
} }
uint32_t scriptAddName(Script* self, PKVM* vm, const char* name, uint32_t moduleAddName(Module* module, PKVM* vm, const char* name,
uint32_t length) { uint32_t length) {
for (uint32_t i = 0; i < self->names.count; i++) { for (uint32_t i = 0; i < module->names.count; i++) {
String* _name = self->names.data[i]; String* _name = module->names.data[i];
if (_name->length == length && strncmp(_name->data, name, length) == 0) { if (_name->length == length && strncmp(_name->data, name, length) == 0) {
// Name already exists in the buffer. // Name already exists in the buffer.
return i; return i;
@ -1148,35 +1149,35 @@ uint32_t scriptAddName(Script* self, PKVM* vm, const char* name,
// return the index. // return the index.
String* new_name = newStringLength(vm, name, length); String* new_name = newStringLength(vm, name, length);
vmPushTempRef(vm, &new_name->_super); vmPushTempRef(vm, &new_name->_super);
pkStringBufferWrite(&self->names, vm, new_name); pkStringBufferWrite(&module->names, vm, new_name);
vmPopTempRef(vm); vmPopTempRef(vm);
return self->names.count - 1; return module->names.count - 1;
} }
uint32_t scriptAddGlobal(PKVM* vm, Script* script, uint32_t moduleAddGlobal(PKVM* vm, Module* module,
const char* name, uint32_t length, const char* name, uint32_t length,
Var value) { Var value) {
// If already exists update the value. // If already exists update the value.
int g_index = scriptGetGlobalIndex(script, name, length); int g_index = moduleGetGlobalIndex(module, name, length);
if (g_index != -1) { if (g_index != -1) {
ASSERT(g_index < (int)script->globals.count, OOPS); ASSERT(g_index < (int)module->globals.count, OOPS);
script->globals.data[g_index] = value; module->globals.data[g_index] = value;
return g_index; return g_index;
} }
// If we're reached here that means we don't already have a variable with // If we're reached here that means we don't already have a variable with
// that name, create new one and set the value. // that name, create new one and set the value.
uint32_t name_ind = scriptAddName(script, vm, name, length); uint32_t name_ind = moduleAddName(module, vm, name, length);
pkUintBufferWrite(&script->global_names, vm, name_ind); pkUintBufferWrite(&module->global_names, vm, name_ind);
pkVarBufferWrite(&script->globals, vm, value); pkVarBufferWrite(&module->globals, vm, value);
return script->globals.count - 1; return module->globals.count - 1;
} }
int scriptGetGlobalIndex(Script* script, const char* name, uint32_t length) { int moduleGetGlobalIndex(Module* module, const char* name, uint32_t length) {
for (uint32_t i = 0; i < script->global_names.count; i++) { for (uint32_t i = 0; i < module->global_names.count; i++) {
uint32_t name_index = script->global_names.data[i]; uint32_t name_index = module->global_names.data[i];
String* g_name = script->names.data[name_index]; String* g_name = module->names.data[name_index];
if (g_name->length == length && strncmp(g_name->data, name, length) == 0) { if (g_name->length == length && strncmp(g_name->data, name, length) == 0) {
return (int)i; return (int)i;
} }
@ -1184,23 +1185,23 @@ int scriptGetGlobalIndex(Script* script, const char* name, uint32_t length) {
return -1; return -1;
} }
void scriptSetGlobal(Script* script, int index, Var value) { void moduleSetGlobal(Module* module, int index, Var value) {
ASSERT_INDEX(index, script->globals.count); ASSERT_INDEX(index, (int)module->globals.count);
script->globals.data[index] = value; module->globals.data[index] = value;
} }
void scriptAddMain(PKVM* vm, Script* script) { void moduleAddMain(PKVM* vm, Module* module) {
ASSERT(script->body == NULL, OOPS); ASSERT(module->body == NULL, OOPS);
const char* fn_name = IMPLICIT_MAIN_NAME; const char* fn_name = IMPLICIT_MAIN_NAME;
script->body = newFunction(vm, fn_name, (int)strlen(fn_name), module->body = newFunction(vm, fn_name, (int)strlen(fn_name),
script, false, NULL/*TODO*/, NULL); module, false, NULL/*TODO*/, NULL);
script->body->arity = 0; module->body->arity = 0;
script->initialized = false; module->initialized = false;
scriptAddGlobal(vm, script, moduleAddGlobal(vm, module,
IMPLICIT_MAIN_NAME, (uint32_t)strlen(IMPLICIT_MAIN_NAME), IMPLICIT_MAIN_NAME, (uint32_t)strlen(IMPLICIT_MAIN_NAME),
VAR_OBJ(script->body)); VAR_OBJ(module->body));
} }
bool instGetAttrib(PKVM* vm, Instance* inst, String* attrib, Var* value) { bool instGetAttrib(PKVM* vm, Instance* inst, String* attrib, Var* value) {
@ -1340,7 +1341,7 @@ const char* getPkVarTypeName(PkVarType type) {
case PK_LIST: return "List"; case PK_LIST: return "List";
case PK_MAP: return "Map"; case PK_MAP: return "Map";
case PK_RANGE: return "Range"; case PK_RANGE: return "Range";
case PK_SCRIPT: return "Script"; case PK_MODULE: return "Module";
// TODO: since functions are not first class citizens anymore, remove it // TODO: since functions are not first class citizens anymore, remove it
// and add closure (maybe with the same name PK_FUNCTION). // and add closure (maybe with the same name PK_FUNCTION).
@ -1360,7 +1361,7 @@ const char* getObjectTypeName(ObjectType type) {
case OBJ_LIST: return "List"; case OBJ_LIST: return "List";
case OBJ_MAP: return "Map"; case OBJ_MAP: return "Map";
case OBJ_RANGE: return "Range"; case OBJ_RANGE: return "Range";
case OBJ_SCRIPT: return "Script"; case OBJ_MODULE: return "Module";
case OBJ_FUNC: return "Func"; case OBJ_FUNC: return "Func";
case OBJ_CLOSURE: return "Closure"; case OBJ_CLOSURE: return "Closure";
case OBJ_UPVALUE: return "Upvalue"; case OBJ_UPVALUE: return "Upvalue";
@ -1616,15 +1617,16 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
return; return;
} }
case OBJ_SCRIPT: { case OBJ_MODULE: {
const Script* scr = (const Script*)obj; const Module* module = (const Module*)obj;
pkByteBufferAddString(buff, vm, "[Module:", 8); pkByteBufferAddString(buff, vm, "[Module:", 8);
if (scr->name != NULL) { if (module->name != NULL) {
pkByteBufferAddString(buff, vm, scr->name->data, pkByteBufferAddString(buff, vm, module->name->data,
scr->name->length); module->name->length);
} else { } else {
pkByteBufferWrite(buff, vm, '"'); pkByteBufferWrite(buff, vm, '"');
pkByteBufferAddString(buff, vm, scr->path->data, scr->path->length); pkByteBufferAddString(buff, vm, module->path->data,
module->path->length);
pkByteBufferWrite(buff, vm, '"'); pkByteBufferWrite(buff, vm, '"');
} }
pkByteBufferWrite(buff, vm, ']'); pkByteBufferWrite(buff, vm, ']');
@ -1751,7 +1753,7 @@ bool toBool(Var v) {
case OBJ_LIST: return ((List*)o)->elements.count != 0; case OBJ_LIST: return ((List*)o)->elements.count != 0;
case OBJ_MAP: return ((Map*)o)->count != 0; case OBJ_MAP: return ((Map*)o)->count != 0;
case OBJ_RANGE: // [[FALLTHROUGH]] case OBJ_RANGE: // [[FALLTHROUGH]]
case OBJ_SCRIPT: case OBJ_MODULE:
case OBJ_FUNC: case OBJ_FUNC:
case OBJ_FIBER: case OBJ_FIBER:
case OBJ_CLASS: case OBJ_CLASS:

View File

@ -188,7 +188,7 @@ typedef struct String String;
typedef struct List List; typedef struct List List;
typedef struct Map Map; typedef struct Map Map;
typedef struct Range Range; typedef struct Range Range;
typedef struct Script Script; typedef struct Module Module;
typedef struct Function Function; typedef struct Function Function;
typedef struct Closure Closure; typedef struct Closure Closure;
typedef struct Upvalue Upvalue; typedef struct Upvalue Upvalue;
@ -214,7 +214,7 @@ typedef enum {
OBJ_LIST, OBJ_LIST,
OBJ_MAP, OBJ_MAP,
OBJ_RANGE, OBJ_RANGE,
OBJ_SCRIPT, OBJ_MODULE,
OBJ_FUNC, OBJ_FUNC,
OBJ_CLOSURE, OBJ_CLOSURE,
OBJ_UPVALUE, OBJ_UPVALUE,
@ -269,15 +269,20 @@ struct Range {
double to; //< End of the range exclusive. double to; //< End of the range exclusive.
}; };
// In pocketlang, the terms Script and Module are interchangable. (Consider // Module in pocketlang is a collection of globals, functions, classes and top
// renaming it to Module to be consistance with the terms). // level statements, they can be imported in other modules generally a
struct Script { // pocketlang script will compiled to a module.
struct Module {
Object _super; Object _super;
// For core libraries the name and the path are same and points to the // The [name] is the module name defined with either 'module' statement
// same String objects. // in the script or the provided name for native modules when creating.
String* name; //< Module name of the script. // For core modules the name and the path are same and will points to the
String* path; //< Path of the script. // same String objects. For modules compiled from a script the path will
// be it's resolved path (could be absolute path but thats depend on the
// path resolver).
String* name;
String* path;
// The constant pool of the module, which contains literal values like // The constant pool of the module, which contains literal values like
// numbers, strings, and functions which are considered constants to // numbers, strings, and functions which are considered constants to
@ -295,21 +300,24 @@ struct Script {
// a seperation between string literals and names in it's constant pool. // 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 // Globals is an array of global variables of the module. All the names
// (including global variables) are stored in the names buffer of the script // (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) // (defined bellow). The (i)th global variables names is located at index (j)
// in the names buffer where j = global_names[i]. // in the names buffer where j = global_names[i].
pkVarBuffer globals; pkVarBuffer globals;
pkUintBuffer global_names; pkUintBuffer global_names;
Function* body; //< Script body is an anonymous function. // Top level statements of a module are compiled to an implicit function
// body whic will be executed if it's imported for the first time.
Function* body;
// When a script has globals, it's body need to be executed to initialize the // If the [initialized] boolean is false, the body function of the module
// global values, this will be false if the module isn't initialized yet and // will be executed when it's first imported and the 'initialized' boolean
// we need to execute the script's body whe we're importing it. // will be set to true. If a module doesn't have globals, We can safely set
// it to true to prevent from running the above body function, if it has one.
bool initialized; bool initialized;
}; };
// Script function pointer. // A struct contain opcodes and other information of a compiled function.
typedef struct { typedef struct {
pkByteBuffer opcodes; //< Buffer of opcodes. pkByteBuffer opcodes; //< Buffer of opcodes.
pkUintBuffer oplines; //< Line number of opcodes for debug (1 based). pkUintBuffer oplines; //< Line number of opcodes for debug (1 based).
@ -319,8 +327,23 @@ typedef struct {
struct Function { struct Function {
Object _super; Object _super;
const char* name; //< Name in the script [owner] or C literal. // The module that owns this function. Since built in functions doesn't
Script* owner; //< Owner script of the function. // belongs to a module it'll be NULL for them.
Module* owner;
// FIXME:
// Because of the builtin function cannot have modules, we cannot reference
// the name of a function with a index which points to the name entry in the
// owner module's names buffer.
//
// The [name] is the name of the function which the function won't have a
// reference to that (to prevent it from garbage collected), it's either
// a C literal string or a name entry in the owner modules names buffer.
// Either way it's guranteed to be alive till the function is alive.
//
// For embedding pocketlang the user must ensure the name exists till the
// function is alive, and it's recomented to use literal C string for that.
const char* name;
// Number of argument the function expects. If the arity is -1 that means // Number of argument the function expects. If the arity is -1 that means
// the function has a variadic number of parameters. When a function is // the function has a variadic number of parameters. When a function is
@ -337,10 +360,12 @@ struct Function {
// native functions to provide a docstring. // native functions to provide a docstring.
const char* docstring; const char* docstring;
bool is_native; //< True if Native function. // Function can be either native C function pointers or compiled pocket
// functions.
bool is_native;
union { union {
pkNativeFn native; //< Native function pointer. pkNativeFn native; //< Native function pointer.
Fn* fn; //< Script function pointer. Fn* fn; //< Pocket function pointer.
}; };
}; };
@ -429,8 +454,7 @@ struct Fiber {
FiberState state; FiberState state;
// The root function of the fiber. (For script it'll be the script's implicit // The root function of the fiber.
// body function).
Function* func; Function* func;
// The stack of the execution holding locals and temps. A heap will be // The stack of the execution holding locals and temps. A heap will be
@ -462,8 +486,12 @@ struct Fiber {
struct Class { struct Class {
Object _super; Object _super;
Script* owner; //< The script it belongs to. // The module that owns this class.
uint32_t name; //< Index of the type's name in the script's name buffer. Module* owner;
// The index of the name of this class in the owner module's names
// buffer.
uint32_t name;
Function* ctor; //< The constructor function. Function* ctor; //< The constructor function.
pkUintBuffer field_names; //< Buffer of field names. pkUintBuffer field_names; //< Buffer of field names.
@ -524,22 +552,13 @@ Map* newMap(PKVM* vm);
// Allocate new Range object and return Range*. // Allocate new Range object and return Range*.
Range* newRange(PKVM* vm, double from, double to); Range* newRange(PKVM* vm, double from, double to);
// Allocate new Script object and return Script*, if the argument [is_core] is // FIXME:
// true the script will be used as a core module and the body of the script // We may need 2 different constructor for native and script modules.
// would be NULL and the [name] will be used as the module name. Otherwise the Module* newModule(PKVM* vm, String* name, bool is_core);
// [name] will be used as the path of the module and a main function will be
// allocated for the module.
Script* newScript(PKVM* vm, String* name, bool is_core);
// FIXME: // FIXME:
// This bellow function will only to be used for module functions and the // We may need 2 different constuctor for native and script functions.
// parameter native is used for builtin functions which will be it's own Function* newFunction(PKVM* vm, const char* name, int length, Module* owner,
// closures (closures should have their own native function pointers, rather
// than having a function that has native pointer which is in-efficient).
//
// TODO:
// Document the bellow function once after the native function move to closure.
Function* newFunction(PKVM* vm, const char* name, int length, Script* owner,
bool is_native, const char* docstring, bool is_native, const char* docstring,
int* fn_index); int* fn_index);
@ -556,7 +575,7 @@ Fiber* newFiber(PKVM* vm, Function* fn);
// Same fix has to applied as newFunction() (see above). // Same fix has to applied as newFunction() (see above).
// //
// Allocate new Class object and return Class* with name [name]. // Allocate new Class object and return Class* with name [name].
Class* newClass(PKVM* vm, Script* scr, const char* name, uint32_t length, Class* newClass(PKVM* vm, Module* scr, const char* name, uint32_t length,
int* cls_index, int* ctor_index); int* cls_index, int* ctor_index);
// Allocate new instance with of the base [type]. Note that if [initialize] is // Allocate new instance with of the base [type]. Note that if [initialize] is
@ -662,32 +681,32 @@ Var mapRemoveKey(PKVM* vm, Map* self, Var key);
// resumed anymore. // resumed anymore.
bool fiberHasError(Fiber* fiber); bool fiberHasError(Fiber* fiber);
// Add a constant [value] to the [script] if it doesn't already present in the // Add a constant [value] to the [module] if it doesn't already present in the
// constant buffer and return it's index. // constant buffer and return it's index.
uint32_t scriptAddConstant(PKVM* vm, Script* script, Var value); uint32_t moduleAddConstant(PKVM* vm, Module* module, Var value);
// Add the name (string literal) to the string buffer if not already exists and // Add the name (string literal) to the string buffer if not already exists and
// return it's index in the buffer. // return it's index in the buffer.
uint32_t scriptAddName(Script* self, PKVM* vm, const char* name, uint32_t moduleAddName(Module* module, PKVM* vm, const char* name,
uint32_t length); uint32_t length);
// Add a global [value] to the [scrpt] and return its index. // Add a global [value] to the [module] and return its index.
uint32_t scriptAddGlobal(PKVM* vm, Script* script, uint32_t moduleAddGlobal(PKVM* vm, Module* module,
const char* name, uint32_t length, const char* name, uint32_t length,
Var value); Var value);
// Search for the [name] in the script's globals and return it's index. // Search for the [name] in the module's globals and return it's index.
// If not found it'll return -1. // If not found it'll return -1.
int scriptGetGlobalIndex(Script* script, const char* name, uint32_t length); int moduleGetGlobalIndex(Module* module, const char* name, uint32_t length);
// Set the global value at [index] in the global buffer with the [value]. // Set the global value at [index] in the global buffer with the [value].
void scriptSetGlobal(Script* script, int index, Var value); void moduleSetGlobal(Module* module, int index, Var value);
// This will allocate a new implicit main function for the script and assign to // This will allocate a new implicit main function for the module and assign to
// the script's body attribute. And the attribute initialized will be set to // the module's body attribute. And the attribute initialized will be set to
// false for the new function. Note that the body of the script should be NULL // false. Note that the body of the module should be NULL before calling this
// before calling this function. // function.
void scriptAddMain(PKVM* vm, Script* script); void moduleAddMain(PKVM* vm, Module* module);
// Get the attribut from the instance and set it [value]. On success return // Get the attribut from the instance and set it [value]. On success return
// true, if the attribute not exists it'll return false but won't set an error. // true, if the attribute not exists it'll return false but won't set an error.

View File

@ -68,7 +68,7 @@ PKVM* pkNewVM(PkConfiguration* config) {
vm->min_heap_size = MIN_HEAP_SIZE; vm->min_heap_size = MIN_HEAP_SIZE;
vm->heap_fill_percent = HEAP_FILL_PERCENT; vm->heap_fill_percent = HEAP_FILL_PERCENT;
vm->scripts = newMap(vm); vm->modules = newMap(vm);
vm->core_libs = newMap(vm); vm->core_libs = newMap(vm);
vm->builtins_count = 0; vm->builtins_count = 0;
@ -136,28 +136,28 @@ PkResult pkInterpretSource(PKVM* vm, PkStringPtr source, PkStringPtr path,
if (path.on_done) path.on_done(vm, path); if (path.on_done) path.on_done(vm, path);
vmPushTempRef(vm, &path_name->_super); // path_name. vmPushTempRef(vm, &path_name->_super); // path_name.
// TODO: Should I clean the script if it already exists before compiling it? // TODO: Should I clean the module if it already exists before compiling it?
// Load a new script to the vm's scripts cache. // Load a new module to the vm's modules cache.
Script* scr = vmGetScript(vm, path_name); Module* module = vmGetModule(vm, path_name);
if (scr == NULL) { if (module == NULL) {
scr = newScript(vm, path_name, false); module = newModule(vm, path_name, false);
vmPushTempRef(vm, &scr->_super); // scr. vmPushTempRef(vm, &module->_super); // module.
mapSet(vm, vm->scripts, VAR_OBJ(path_name), VAR_OBJ(scr)); mapSet(vm, vm->modules, VAR_OBJ(path_name), VAR_OBJ(module));
vmPopTempRef(vm); // scr. vmPopTempRef(vm); // module.
} }
vmPopTempRef(vm); // path_name. vmPopTempRef(vm); // path_name.
// Compile the source. // Compile the source.
PkResult result = compile(vm, scr, source.string, options); PkResult result = compile(vm, module, source.string, options);
if (source.on_done) source.on_done(vm, source); if (source.on_done) source.on_done(vm, source);
if (result != PK_RESULT_SUCCESS) return result; if (result != PK_RESULT_SUCCESS) return result;
// Set script initialized to true before the execution ends to prevent cyclic // Set module initialized to true before the execution ends to prevent cyclic
// inclusion cause a crash. // inclusion cause a crash.
scr->initialized = true; module->initialized = true;
return runFiber(vm, newFiber(vm, scr->body)); return runFiber(vm, newFiber(vm, module->body));
} }
PkResult pkRunFiber(PKVM* vm, PkHandle* fiber, PkResult pkRunFiber(PKVM* vm, PkHandle* fiber,
@ -241,11 +241,11 @@ void vmPopTempRef(PKVM* vm) {
vm->temp_reference_count--; vm->temp_reference_count--;
} }
Script* vmGetScript(PKVM* vm, String* path) { Module* vmGetModule(PKVM* vm, String* path) {
Var scr = mapGet(vm->scripts, VAR_OBJ(path)); Var module = mapGet(vm->modules, VAR_OBJ(path));
if (IS_UNDEF(scr)) return NULL; if (IS_UNDEF(module)) return NULL;
ASSERT(AS_OBJ(scr)->type == OBJ_SCRIPT, OOPS); ASSERT(AS_OBJ(module)->type == OBJ_MODULE, OOPS);
return (Script*)AS_OBJ(scr); return (Module*)AS_OBJ(module);
} }
void vmCollectGarbage(PKVM* vm) { void vmCollectGarbage(PKVM* vm) {
@ -260,8 +260,8 @@ void vmCollectGarbage(PKVM* vm) {
markObject(vm, &vm->builtins[i].fn->_super); markObject(vm, &vm->builtins[i].fn->_super);
} }
// Mark the scripts cache. // Mark the modules cache.
markObject(vm, &vm->scripts->_super); markObject(vm, &vm->modules->_super);
// Mark temp references. // Mark temp references.
for (int i = 0; i < vm->temp_reference_count; i++) { for (int i = 0; i < vm->temp_reference_count; i++) {
@ -436,23 +436,33 @@ static void* defaultRealloc(void* memory, size_t new_size, void* user_data) {
return realloc(memory, new_size); return realloc(memory, new_size);
} }
// Import and return Script object as Var. If the script is imported and // FIXME:
// compiled here it'll set [is_new_script] to true otherwise (using the cached // We're assuming that the module should be available at the VM's modules cache
// script) set to false. // which is added by the compilation pahse, but we cannot rely on the
static inline Var importScript(PKVM* vm, String* path_name) { // compilation phase here as it could be a seperate system from the runtime and
// should throw a runtime error if the module is not present in the modules
// cache (or try to load).
// Example: If we may support to store the compiled script as a separate file
// (like python's ".pyc" or java's ".class" the runtime cannot ensure that the
// module it import is already cached.
//
// 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) {
// Check in the core libs. // Check in the core libs.
Script* scr = getCoreLib(vm, path_name); Module* module = getCoreLib(vm, name);
if (scr != NULL) return VAR_OBJ(scr); if (module != NULL) return VAR_OBJ(module);
// Check in the scripts cache. // Check in the modules cache.
Var entry = mapGet(vm->scripts, VAR_OBJ(path_name)); Var entry = mapGet(vm->modules, VAR_OBJ(name));
if (!IS_UNDEF(entry)) { if (!IS_UNDEF(entry)) {
ASSERT(AS_OBJ(entry)->type == OBJ_SCRIPT, OOPS); ASSERT(AS_OBJ(entry)->type == OBJ_MODULE, OOPS);
return entry; return entry;
} }
// Imported scripts were resolved at compile time. // FIXME: Should be a runtime error.
// Imported modules were resolved at compile time.
UNREACHABLE(); UNREACHABLE();
return VAR_NULL; return VAR_NULL;
@ -590,7 +600,7 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
register Var* rbp; //< Stack base pointer register. register Var* rbp; //< Stack base pointer register.
register CallFrame* frame; //< Current call frame. register CallFrame* frame; //< Current call frame.
register Script* script; //< Currently executing script. register Module* module; //< Currently executing module.
#if DEBUG #if DEBUG
#define PUSH(value) \ #define PUSH(value) \
@ -648,7 +658,7 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
frame = &vm->fiber->frames[vm->fiber->frame_count-1]; \ frame = &vm->fiber->frames[vm->fiber->frame_count-1]; \
ip = frame->ip; \ ip = frame->ip; \
rbp = frame->rbp; \ rbp = frame->rbp; \
script = frame->fn->owner; \ module = frame->fn->owner; \
} while (false) } while (false)
// Update the frame's execution variables before pushing another call frame. // Update the frame's execution variables before pushing another call frame.
@ -683,8 +693,8 @@ L_vm_main_loop:
OPCODE(PUSH_CONSTANT): OPCODE(PUSH_CONSTANT):
{ {
uint16_t index = READ_SHORT(); uint16_t index = READ_SHORT();
ASSERT_INDEX(index, script->constants.count); ASSERT_INDEX(index, module->constants.count);
PUSH(script->constants.data[index]); PUSH(module->constants.data[index]);
DISPATCH(); DISPATCH();
} }
@ -729,10 +739,10 @@ L_vm_main_loop:
OPCODE(PUSH_INSTANCE): OPCODE(PUSH_INSTANCE):
{ {
uint8_t index = READ_SHORT(); uint8_t index = READ_SHORT();
ASSERT_INDEX(index, script->constants.count); ASSERT_INDEX(index, module->constants.count);
ASSERT(IS_OBJ_TYPE(script->constants.data[index], OBJ_CLASS), OOPS); ASSERT(IS_OBJ_TYPE(module->constants.data[index], OBJ_CLASS), OOPS);
Instance* inst = newInstance(vm, Instance* inst = newInstance(vm,
(Class*)AS_OBJ(script->constants.data[index]), false); (Class*)AS_OBJ(module->constants.data[index]), false);
PUSH(VAR_OBJ(inst)); PUSH(VAR_OBJ(inst));
DISPATCH(); DISPATCH();
} }
@ -827,16 +837,16 @@ L_vm_main_loop:
OPCODE(PUSH_GLOBAL): OPCODE(PUSH_GLOBAL):
{ {
uint8_t index = READ_BYTE(); uint8_t index = READ_BYTE();
ASSERT_INDEX(index, script->globals.count); ASSERT_INDEX(index, module->globals.count);
PUSH(script->globals.data[index]); PUSH(module->globals.data[index]);
DISPATCH(); DISPATCH();
} }
OPCODE(STORE_GLOBAL): OPCODE(STORE_GLOBAL):
{ {
uint8_t index = READ_BYTE(); uint8_t index = READ_BYTE();
ASSERT_INDEX(index, script->globals.count); ASSERT_INDEX(index, module->globals.count);
script->globals.data[index] = PEEK(-1); module->globals.data[index] = PEEK(-1);
DISPATCH(); DISPATCH();
} }
@ -855,32 +865,32 @@ L_vm_main_loop:
OPCODE(IMPORT): OPCODE(IMPORT):
{ {
String* name = script->names.data[READ_SHORT()]; String* name = module->names.data[READ_SHORT()];
Var scr = importScript(vm, name);
ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), OOPS); Var _imported = importModule(vm, name);
Script* module = (Script*)AS_OBJ(scr); ASSERT(IS_OBJ_TYPE(_imported, OBJ_MODULE), OOPS);
PUSH(scr); PUSH(_imported);
// TODO: If the body doesn't have any statements (just the functions). // TODO: If the body doesn't have any statements (just the functions).
// This initialization call is un-necessary. // This initialization call is un-necessary.
if (!module->initialized) { Module* imported = (Module*)AS_OBJ(_imported);
module->initialized = true; if (!imported->initialized) {
imported->initialized = true;
ASSERT(module->body != NULL, OOPS); ASSERT(imported->body != NULL, OOPS);
// Note that we're setting the main function's return address to the // Note that we're setting the main function's return address to the
// module itself (for every other function we'll push a null at the rbp // module itself (for every other function we'll push a null at the rbp
// before calling them and it'll be returned without modified if the // before calling them and it'll be returned without modified if the
// function doesn't returned anything). Also We can't return from the // function doesn't returned anything). Also We can't return from the
// body of the script, so the main function will return what's at the // body of the module, so the main function will return what's at the
// rbp without modifying it. So at the end of the main function the // rbp without modifying it. So at the end of the main function the
// stack top would be the module itself. // stack top would be the module itself.
Var* module_ret = vm->fiber->sp - 1; Var* module_ret = vm->fiber->sp - 1;
UPDATE_FRAME(); //< Update the current frame's ip. UPDATE_FRAME(); //< Update the current frame's ip.
pushCallFrame(vm, module->body, module_ret); pushCallFrame(vm, imported->body, module_ret);
LOAD_FRAME(); //< Load the top frame to vm's execution variables. LOAD_FRAME(); //< Load the top frame to vm's execution variables.
} }
@ -1065,7 +1075,7 @@ L_vm_main_loop:
} DISPATCH(); } DISPATCH();
case OBJ_SCRIPT: case OBJ_MODULE:
case OBJ_FUNC: case OBJ_FUNC:
case OBJ_CLOSURE: case OBJ_CLOSURE:
case OBJ_UPVALUE: case OBJ_UPVALUE:
@ -1174,7 +1184,7 @@ L_vm_main_loop:
OPCODE(GET_ATTRIB): OPCODE(GET_ATTRIB):
{ {
Var on = PEEK(-1); // Don't pop yet, we need the reference for gc. Var on = PEEK(-1); // Don't pop yet, we need the reference for gc.
String* name = script->names.data[READ_SHORT()]; String* name = module->names.data[READ_SHORT()];
Var value = varGetAttrib(vm, on, name); Var value = varGetAttrib(vm, on, name);
DROP(); // on DROP(); // on
PUSH(value); PUSH(value);
@ -1186,7 +1196,7 @@ L_vm_main_loop:
OPCODE(GET_ATTRIB_KEEP): OPCODE(GET_ATTRIB_KEEP):
{ {
Var on = PEEK(-1); Var on = PEEK(-1);
String* name = script->names.data[READ_SHORT()]; String* name = module->names.data[READ_SHORT()];
PUSH(varGetAttrib(vm, on, name)); PUSH(varGetAttrib(vm, on, name));
CHECK_ERROR(); CHECK_ERROR();
DISPATCH(); DISPATCH();
@ -1196,7 +1206,7 @@ L_vm_main_loop:
{ {
Var value = PEEK(-1); // Don't pop yet, we need the reference for gc. 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. Var on = PEEK(-2); // Don't pop yet, we need the reference for gc.
String* name = script->names.data[READ_SHORT()]; String* name = module->names.data[READ_SHORT()];
varSetAttrib(vm, on, name, value); varSetAttrib(vm, on, name, value);
DROP(); // value DROP(); // value

View File

@ -46,9 +46,8 @@
(vm->fiber->error = err); \ (vm->fiber->error = err); \
} while (false) } while (false)
// Builtin functions are stored in an array in the VM (unlike script functions // Builtin functions are stored in an array in the VM unlike other functions
// they're member of function buffer of the script) and this struct is a single // builtin function's doesn't belongs to any module.
// entry of the array.
typedef struct { typedef struct {
const char* name; //< Name of the function. const char* name; //< Name of the function.
uint32_t length; //< Length of the name. uint32_t length; //< Length of the name.
@ -111,14 +110,14 @@ struct PKVM {
// Current compiler reference to mark it's heap allocated objects. Note that // Current compiler reference to mark it's heap allocated objects. Note that
// The compiler isn't heap allocated. It'll be a link list of all the // The compiler isn't heap allocated. It'll be a link list of all the
// compiler we have so far. A new compiler will be created and appended when // compiler we have so far. A new compiler will be created and appended when
// a new script is being imported and compiled at compiletime. // a new module is being imported and compiled at compiletime.
Compiler* compiler; Compiler* compiler;
// A cache of the compiled scripts with their path as key and the Scrpit // A cache of the compiled modules with their path as key and the Scrpit
// object as the value. // object as the value.
Map* scripts; Map* modules;
// A map of core libraries with their name as the key and the Script object // A map of core libraries with their name as the key and the Module object
// as the value. // as the value.
Map* core_libs; Map* core_libs;
@ -192,9 +191,9 @@ void vmPushTempRef(PKVM* vm, Object* obj);
// Pop the top most object from temporary reference stack. // Pop the top most object from temporary reference stack.
void vmPopTempRef(PKVM* vm); void vmPopTempRef(PKVM* vm);
// Returns the scrpt with the resolved [path] (also the key) in the vm's script // Returns the module with the resolved [path] (also the key) in the VM's
// cache. If not found itll return NULL. // modules cache. If not found itll return NULL.
Script* vmGetScript(PKVM* vm, String* path); Module* vmGetModule(PKVM* vm, String* path);
// ((Context switching - start)) // ((Context switching - start))
// Prepare a new fiber for execution with the given arguments. That can be used // Prepare a new fiber for execution with the given arguments. That can be used