diff --git a/cli/internal.h b/cli/internal.h index bb586c1..890b8b9 100644 --- a/cli/internal.h +++ b/cli/internal.h @@ -27,7 +27,8 @@ #define CLI_NOTICE \ "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" // FIXME: the vm user data of cli. diff --git a/src/include/pocketlang.h b/src/include/pocketlang.h index 84a5185..8cb55fc 100644 --- a/src/include/pocketlang.h +++ b/src/include/pocketlang.h @@ -84,7 +84,7 @@ typedef enum { PK_LIST, PK_MAP, PK_RANGE, - PK_SCRIPT, + PK_MODULE, PK_FUNCTION, PK_FIBER, PK_CLASS, diff --git a/src/pk_compiler.c b/src/pk_compiler.c index 8c575e9..6556d15 100644 --- a/src/pk_compiler.c +++ b/src/pk_compiler.c @@ -12,12 +12,12 @@ #include "pk_vm.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 // which is using a single byte value to identify the local. #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. #define MAX_CONSTANTS (1 << 16) @@ -237,14 +237,14 @@ typedef struct { } GrammarRule; 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_LOCAL, //< Local scope. Increase with inner scope. } Depth; typedef enum { 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(){...}' } FuncType; @@ -285,8 +285,8 @@ typedef struct sLoop { // compile time we can allow access to them at the global scope. typedef struct sForwardName { - // Index of the short instruction that has the value of the name (in the - // names buffer of the script). + // Index of the short instruction that has the value of the global's name + // (in the names buffer of the module). int instruction; // The function where the name is used, and the instruction is belongs to. @@ -303,8 +303,8 @@ typedef struct sForwardName { typedef struct sFunc { - // Scope of the function. -2 for script body, -1 for top level function and - // literal functions will have the scope where it declared. + // Scope of the function. -2 for module body function, -1 for top level + // function and literal functions will have the scope where it declared. int depth; // The actual function pointer which is being compiled. @@ -313,8 +313,8 @@ typedef struct sFunc { // The index of the function in its module. int index; - // If outer function of a literal or the script body function of a script - // function. Null for script body function. + // If outer function of this function, for top level function the outer + // function will be the module's body function. struct sFunc* outer_func; } Func; @@ -377,7 +377,7 @@ typedef struct sParser { char si_name_quote; // 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]; int forwards_count; @@ -393,11 +393,11 @@ struct Compiler { // current compilation. Parser parser; - // Each module (ie. script) will be compiled with it's own compiler and a - // module is imported, a new compiler is created for that module and it'll - // be added to the linked list of compilers at the begining. PKVM will use - // this compiler reference as a root object (objects which won't garbage - // collected) and the chain of compilers will be marked at the marking phase. + // Each module will be compiled with it's own compiler and a module is + // imported, a new compiler is created for that module and it'll be added to + // the linked list of compilers at the begining. PKVM will use this compiler + // reference as a root object (objects which won't garbage collected) and + // the chain of compilers will be marked at the marking phase. // // 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. - Script* script; //< Current script. - Loop* loop; //< Current loop. - Func* func; //< Current function. + Module* module; //< Current module that's being compiled. + Loop* loop; //< Current loop the we're parsing. + Func* func; //< Current function we're parsing. // Current depth the compiler in (-1 means top level) 0 means function // 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, - Script* script, const PkCompileOptions* options) { + Module* module, const PkCompileOptions* options) { compiler->next_compiler = NULL; - compiler->script = script; + compiler->module = module; compiler->options = options; compiler->scope_depth = DEPTH_GLOBAL; @@ -512,7 +512,7 @@ static void compilerInit(Compiler* compiler, PKVM* vm, const char* source, compiler->new_local = 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. 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 -// 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. static void resolveError(Compiler* compiler, int line, const char* fmt, ...) { va_list args; @@ -1270,7 +1270,7 @@ static NameSearchResult compilerSearchName(Compiler* compiler, int index; // For storing the search result below. // Search through globals. - index = scriptGetGlobalIndex(compiler->script, name, length); + index = moduleGetGlobalIndex(compiler->module, name, length); if (index != -1) { result.type = NAME_GLOBAL_VAR; result.index = index; @@ -1525,7 +1525,6 @@ static void exprFunc(Compiler* compiler) { emitShort(compiler, fn_index); } -// Local/global variables, script/native/builtin functions name. static void exprName(Compiler* compiler) { const char* start = compiler->parser.previous.start; @@ -1767,8 +1766,8 @@ static void exprAttrib(Compiler* compiler) { const char* name = compiler->parser.previous.start; int length = compiler->parser.previous.length; - // Store the name in script's names. - int index = scriptAddName(compiler->script, compiler->parser.vm, + // Store the name in module's names buffer. + int index = moduleAddName(compiler->module, compiler->parser.vm, name, length); if (compiler->l_value && matchAssignment(compiler)) { @@ -1875,7 +1874,7 @@ static int compilerAddVariable(Compiler* compiler, const char* name, bool max_vars_reached = false; const char* var_type = ""; // For max variables reached error message. if (compiler->scope_depth == DEPTH_GLOBAL) { - if (compiler->script->globals.count >= MAX_VARIABLES) { + if (compiler->module->globals.count >= MAX_VARIABLES) { max_vars_reached = true; var_type = "globals"; } @@ -1886,7 +1885,7 @@ static int compilerAddVariable(Compiler* compiler, const char* name, } } 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); return -1; } @@ -1894,7 +1893,7 @@ static int compilerAddVariable(Compiler* compiler, const char* name, // Add the variable and return it's index. 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); } else { 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, const char* name, int length, int line) { 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); return; } @@ -1925,14 +1924,14 @@ static void compilerAddForward(Compiler* compiler, int instruction, Fn* fn, 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) { - pkVarBuffer* constants = &compiler->script->constants; + pkVarBuffer* constants = &compiler->module->constants; - uint32_t index = scriptAddConstant(compiler->parser.vm, - compiler->script, value); + uint32_t index = moduleAddConstant(compiler->parser.vm, + compiler->module, value); 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); } return (int)index; @@ -2105,7 +2104,7 @@ typedef enum { static void compileStatement(Compiler* compiler); 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) { // Consume the name of the type. @@ -2115,7 +2114,7 @@ static int compileClass(Compiler* compiler) { // Create a new class. 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); cls->ctor->arity = 0; @@ -2126,16 +2125,16 @@ static int compileClass(Compiler* compiler) { compiler->parser.previous.start, compiler->parser.previous.length, compiler->parser.previous.line); - scriptSetGlobal(compiler->script, index, VAR_OBJ(cls)); + moduleSetGlobal(compiler->module, index, VAR_OBJ(cls)); // Check count exceeded. 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); } // Compile the constructor function. - ASSERT(compiler->func->ptr == compiler->script->body, OOPS); + ASSERT(compiler->func->ptr == compiler->module->body, OOPS); Func curr_fn; compilerPushFunc(compiler, &curr_fn, cls->ctor, ctor_index); compilerEnterBlock(compiler); @@ -2153,12 +2152,12 @@ static int compileClass(Compiler* compiler) { const char* f_name = compiler->parser.previous.start; 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); - 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++) { - 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)) { parseError(compiler, "Class field with name '%s' already exists.", new_name->data); @@ -2194,7 +2193,7 @@ static int compileClass(Compiler* compiler) { 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) { const char* name; @@ -2212,10 +2211,10 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) { int fn_index; 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); 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); } @@ -2225,7 +2224,7 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) { ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); int name_line = compiler->parser.previous.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; @@ -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 -// path) and return it as a script pointer. And it'll emit opcodes to push -// that script to the stack. -static Script* importFile(Compiler* compiler, const char* path) { +// path) and return it as a module pointer. And it'll emit opcodes to push +// that module to the stack. +static Module* importFile(Compiler* compiler, const char* path) { ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); PKVM* vm = compiler->parser.vm; @@ -2340,33 +2339,34 @@ static Script* importFile(Compiler* compiler, const char* path) { // Resolve the path. PkStringPtr resolved = { path, NULL, 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); } if (resolved.string == NULL) { 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. - 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)); - 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); - // Check if the script already exists. - Var entry = mapGet(vm->scripts, VAR_OBJ(path_name)); + // Check if the script already compiled and cached in the PKVM. + Var entry = mapGet(vm->modules, VAR_OBJ(path_name)); 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); 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) { parseError(compiler, "Cannot import. The hosting application haven't " "registered the script loading API"); @@ -2380,24 +2380,24 @@ static Script* importFile(Compiler* compiler, const char* path) { return NULL; } - // Make a new script and to compile it. - Script* scr = newScript(vm, path_name, false); - vmPushTempRef(vm, &scr->_super); // scr. - mapSet(vm, vm->scripts, VAR_OBJ(path_name), VAR_OBJ(scr)); + // Make a new module and to compile it. + Module* module = newModule(vm, path_name, false); + vmPushTempRef(vm, &module->_super); // scr. + mapSet(vm, vm->modules, VAR_OBJ(path_name), VAR_OBJ(module)); vmPopTempRef(vm); // scr. - // Push the script on the stack. + // Push the compiled script on the stack. emitOpcode(compiler, OP_IMPORT); emitShort(compiler, index); - // Option for the compilation, even if we're running on repl mode the - // imported script cannot run on repl mode. + // Even if we're running on repl mode the imported module cannot run on + // repl mode. PkCompileOptions options = pkNewCompilerOptions(); if (compiler->options) options = *compiler->options; options.repl_mode = false; - // Compile the source to the script and clean the source. - PkResult result = compile(vm, scr, source.string, &options); + // Compile the source to the module and clean the source. + PkResult result = compile(vm, module, source.string, &options); if (source.on_done != NULL) source.on_done(vm, source); if (result != PK_RESULT_SUCCESS) { @@ -2405,41 +2405,41 @@ static Script* importFile(Compiler* compiler, const char* path) { path_name->data); } - return scr; + return module; } -// Import the core library from the vm's core_libs and it'll emit opcodes to -// push that script to the stack. -static Script* importCoreLib(Compiler* compiler, const char* name_start, +// Import the native module from the PKVM's core_libs and it'll emit opcodes +// to push that module to the stack. +static Module* importCoreLib(Compiler* compiler, const char* name_start, int name_length) { ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); - // Add the name to the script's name buffer, we need it as a key to the - // vm's script cache. - int index = (int)scriptAddName(compiler->script, compiler->parser.vm, + // Add the name to the module's name buffer, we need it as a key to the + // PKVM's module cache. + int index = (int)moduleAddName(compiler->module, compiler->parser.vm, name_start, name_length); - String* module = 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)) { - parseError(compiler, "No module named '%s' exists.", module->data); + parseError(compiler, "No module named '%s' exists.", module_name->data); return NULL; } - // Push the script on the stack. + // Push the module on the stack. emitOpcode(compiler, OP_IMPORT); emitShort(compiler, index); - ASSERT(IS_OBJ_TYPE(entry, OBJ_SCRIPT), OOPS); - return (Script*)AS_OBJ(entry); + ASSERT(IS_OBJ_TYPE(entry, OBJ_MODULE), OOPS); + 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. -static inline Script* compilerImport(Compiler* compiler) { +static inline Module* compilerImport(Compiler* compiler) { 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. if (match(compiler, TK_NAME)) { //< Core library. 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 -// 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, 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. int line = compiler->parser.previous.line; - // Add the name to the **current** script's name buffer. - int name_index = (int)scriptAddName(compiler->script, compiler->parser.vm, + // Add the name to the **current** module's name buffer. + int name_index = (int)moduleAddName(compiler->module, compiler->parser.vm, name, length); - // Get the function from the script. + // Get the global/function/class from the module. emitOpcode(compiler, OP_GET_ATTRIB_KEEP); emitShort(compiler, name_index); @@ -2513,18 +2513,18 @@ static void compilerImportSingleEntry(Compiler* compiler, 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. -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); // Import all globals. - ASSERT(script->global_names.count == script->globals.count, OOPS); - for (uint32_t i = 0; i < script->globals.count; i++) { - ASSERT(script->global_names.data[i] < script->names.count, OOPS); - const String* name = script->names.data[script->global_names.data[i]]; + ASSERT(module->global_names.count == module->globals.count, OOPS); + for (uint32_t i = 0; i < module->globals.count; i++) { + ASSERT(module->global_names.data[i] < module->names.count, OOPS); + const String* name = module->names.data[module->global_names.data[i]]; 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 // 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. consume(compiler, TK_IMPORT, "Expected keyword 'import'."); @@ -2548,14 +2548,14 @@ static void compileFromImport(Compiler* compiler) { } else { 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."); const char* name = compiler->parser.previous.start; uint32_t length = (uint32_t)compiler->parser.previous.length; int line = compiler->parser.previous.line; // 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, name, length); @@ -2600,9 +2600,9 @@ static void compileRegularImport(Compiler* compiler) { // 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 // 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; // Check if it has an alias, if so bind the variable with that name. @@ -2621,7 +2621,7 @@ static void compileRegularImport(Compiler* compiler) { } else { // 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 - // to define a module name for a script. + // to define a module name for a module. if (lib && lib->name != NULL) { // 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 (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*/) { emitOpcode(compiler, OP_REPL_PRINT); } @@ -2887,7 +2887,7 @@ static void compileStatement(Compiler* compiler) { 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 // level expression's evaluated value will be printed. 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) { // 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 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 - // of the script that imported this script. Add the all the compilers into a + // If compiling for an imported module the vm->compiler would be the compiler + // of the module that imported this module. Add the all the compilers into a // link list. compiler->next_compiler = vm->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 // 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. - // just use the globals and functions of the script and use a new body func. - pkByteBufferClear(&script->body->fn->opcodes, vm); + // just use the globals and functions of the module and use a new body func. + pkByteBufferClear(&module->body->fn->opcodes, vm); // Remember the count of constants, names, and globals, If the compilation // failed discard all of them and roll back. - uint32_t constants_count = script->constants.count; - uint32_t names_count = script->names.count; - uint32_t globals_count = script->globals.count; + uint32_t constants_count = module->constants.count; + uint32_t names_count = module->names.count; + uint32_t globals_count = module->globals.count; Func curr_fn; - curr_fn.depth = DEPTH_SCRIPT; - curr_fn.ptr = script->body; + curr_fn.depth = DEPTH_MODULE; + curr_fn.ptr = module->body; curr_fn.outer_func = NULL; compiler->func = &curr_fn; @@ -2970,17 +2970,17 @@ PkResult compile(PKVM* vm, Script* script, const char* source, 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 // Compile error. - if (script->name != NULL) { + if (module->name != NULL) { parseError(compiler, "Module name already defined."); } else { consume(compiler, TK_NAME, "Expected a name for the module."); const char* name = compiler->parser.previous.start; uint32_t len = compiler->parser.previous.length; - script->name = newStringLength(vm, name, len); + module->name = newStringLength(vm, name, len); consumeEndStatement(compiler); } } @@ -2997,7 +2997,7 @@ PkResult compile(PKVM* vm, Script* script, const char* source, ForwardName* forward = &compiler->parser.forwards[i]; const char* name = forward->name; 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) { patchForward(compiler, forward->func, forward->instruction, index); } 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 (compiler->parser.has_errors) { - script->constants.count = constants_count; - script->names.count = names_count; - script->globals.count = script->global_names.count = globals_count; + module->constants.count = constants_count; + module->names.count = names_count; + module->globals.count = module->global_names.count = globals_count; } #if DUMP_BYTECODE - dumpFunctionCode(compiler->parser.vm, script->body); + dumpFunctionCode(compiler->parser.vm, module->body); #endif // Return the compilation result. @@ -3033,24 +3033,24 @@ PkResult compile(PKVM* vm, Script* script, const char* source, return PK_RESULT_SUCCESS; } -PkResult pkCompileModule(PKVM* vm, PkHandle* module, PkStringPtr source, +PkResult pkCompileModule(PKVM* vm, PkHandle* module_handle, PkStringPtr source, const PkCompileOptions* options) { - __ASSERT(module != NULL, "Argument module was NULL."); - Var scr = module->value; - __ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), "Given handle is not a module"); - Script* script = (Script*)AS_OBJ(scr); + __ASSERT(module_handle != NULL, "Argument module was NULL."); + __ASSERT(IS_OBJ_TYPE(module_handle->value, OBJ_MODULE), + "Given handle is not a module."); + 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); return result; } void compilerMarkObjects(PKVM* vm, Compiler* compiler) { - // Mark the script which is currently being compiled. - markObject(vm, &compiler->script->_super); + // Mark the module which is currently being compiled. + 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). markValue(vm, compiler->parser.current.value); markValue(vm, compiler->parser.previous.value); diff --git a/src/pk_compiler.h b/src/pk_compiler.h index cb1c24f..7d483c7 100644 --- a/src/pk_compiler.h +++ b/src/pk_compiler.h @@ -25,11 +25,11 @@ typedef enum { typedef struct Compiler Compiler; // This will take source code as a cstring, compiles it to pocketlang bytecodes -// and append them to the script's implicit main function ("$(SourceBody)"). -// On a successfull compilation it'll return PK_RESULT_SUCCESS, otherwise it'll -// return PK_RESULT_COMPILE_ERROR but if repl_mode set in the [options], and -// we've reached and unexpected EOF it'll return PK_RESULT_UNEXPECTED_EOF. -PkResult compile(PKVM* vm, Script* script, const char* source, +// and append them to the module's implicit main function. On a successfull +// compilation it'll return PK_RESULT_SUCCESS, otherwise it'll return +// PK_RESULT_COMPILE_ERROR but if repl_mode set in the [options], and we've +// reached and unexpected EOF it'll return PK_RESULT_UNEXPECTED_EOF. +PkResult compile(PKVM* vm, Module* module, const char* source, const PkCompileOptions* options); // Mark the heap allocated objects of the compiler at the garbage collection diff --git a/src/pk_core.c b/src/pk_core.c index 0b58470..a497985 100644 --- a/src/pk_core.c +++ b/src/pk_core.c @@ -36,55 +36,53 @@ /* 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*. -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. -static void moduleAddFunctionInternal(PKVM* vm, Script* script, +static void moduleAddFunctionInternal(PKVM* vm, Module* module, const char* name, pkNativeFn fptr, int arity, const char* docstring); -// pkNewModule implementation (see pocketlang.h for description). PkHandle* pkNewModule(PKVM* vm, const char* name) { - Script* module = newModuleInternal(vm, name); + Module* module = newModuleInternal(vm, name); return vmNewHandle(vm, VAR_OBJ(module)); } -// pkModuleAddGlobal implementation (see pocketlang.h for description). PK_PUBLIC void pkModuleAddGlobal(PKVM* vm, PkHandle* module, const char* name, PkHandle* value) { __ASSERT(module != NULL, "Argument module was NULL."); __ASSERT(value != NULL, "Argument value was NULL."); - Var scr = module->value; - __ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), "Given handle is not a module"); + __ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE), + "Given handle is not a module."); - scriptAddGlobal(vm, (Script*)AS_OBJ(scr), name, (uint32_t)strlen(name), - value->value); + moduleAddGlobal(vm, (Module*)AS_OBJ(module->value), + name, (uint32_t)strlen(name), value->value); } -// pkModuleAddFunction implementation (see pocketlang.h for description). void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name, pkNativeFn fptr, int arity) { __ASSERT(module != NULL, "Argument module was NULL."); - Var scr = module->value; - __ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), "Given handle is not a module"); - moduleAddFunctionInternal(vm, (Script*)AS_OBJ(scr), name, fptr, arity, + __ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE), + "Given handle is not a module."); + moduleAddFunctionInternal(vm, (Module*)AS_OBJ(module->value), + name, fptr, arity, NULL /*TODO: Public API for function docstring.*/); } PkHandle* pkGetMainFunction(PKVM* vm, PkHandle* module) { __ASSERT(module != NULL, "Argument module was NULL."); - Var scr = module->value; - __ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), "Given handle is not a module"); - Script* script = (Script*)AS_OBJ(scr); + __ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE), + "Given handle is not a module."); + 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)); if (main_index == -1) return NULL; - ASSERT_INDEX(main_index, (int)script->constants.count); - return vmNewHandle(vm, script->constants.data[main_index]); + ASSERT_INDEX(main_index, (int)_module->constants.count); + return vmNewHandle(vm, _module->constants.data[main_index]); } // A convenient macro to get the nth (1 based) argument of the current @@ -131,13 +129,11 @@ do { \ } \ } while (false) -// pkGetArgc implementation (see pocketlang.h for description). int pkGetArgc(const PKVM* vm) { __ASSERT(vm->fiber != NULL, "This function can only be called at runtime."); return ARGC; } -// pkCheckArgcRange implementation (see pocketlang.h for description). bool pkCheckArgcRange(PKVM* vm, int argc, int min, int 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; } -// pkGetArg implementation (see pocketlang.h for description). PkVar pkGetArg(const PKVM* vm, int arg) { __ASSERT(vm->fiber != NULL, "This function can only be called at runtime."); __ASSERT(arg > 0 || arg <= ARGC, "Invalid argument index."); @@ -165,7 +160,6 @@ PkVar pkGetArg(const PKVM* vm, int arg) { return &(ARG(arg)); } -// pkGetArgBool implementation (see pocketlang.h for description). bool pkGetArgBool(PKVM* vm, int arg, bool* value) { CHECK_GET_ARG_API_ERRORS(); @@ -174,7 +168,6 @@ bool pkGetArgBool(PKVM* vm, int arg, bool* value) { return true; } -// pkGetArgNumber implementation (see pocketlang.h for description). bool pkGetArgNumber(PKVM* vm, int arg, double* value) { CHECK_GET_ARG_API_ERRORS(); @@ -193,7 +186,6 @@ bool pkGetArgNumber(PKVM* vm, int arg, double* value) { return true; } -// pkGetArgString implementation (see pocketlang.h for description). bool pkGetArgString(PKVM* vm, int arg, const char** value, uint32_t* length) { CHECK_GET_ARG_API_ERRORS(); @@ -211,7 +203,6 @@ bool pkGetArgString(PKVM* vm, int arg, const char** value, uint32_t* length) { return true; } -// pkGetArgInstance implementation (see pocketlang.h for description). bool pkGetArgInst(PKVM* vm, int arg, uint32_t id, void** value) { CHECK_GET_ARG_API_ERRORS(); @@ -239,7 +230,6 @@ bool pkGetArgInst(PKVM* vm, int arg, uint32_t id, void** value) { return true; } -// pkGetArgValue implementation (see pocketlang.h for description). bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value) { CHECK_GET_ARG_API_ERRORS(); @@ -255,42 +245,34 @@ bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value) { return true; } -// pkReturnNull implementation (see pocketlang.h for description). void pkReturnNull(PKVM* vm) { RET(VAR_NULL); } -// pkReturnBool implementation (see pocketlang.h for description). void pkReturnBool(PKVM* vm, bool value) { RET(VAR_BOOL(value)); } -// pkReturnNumber implementation (see pocketlang.h for description). void pkReturnNumber(PKVM* vm, double value) { RET(VAR_NUM(value)); } -// pkReturnString implementation (see pocketlang.h for description). void pkReturnString(PKVM* vm, const char* value) { RET(VAR_OBJ(newString(vm, value))); } -// pkReturnStringLength implementation (see pocketlang.h for description). void pkReturnStringLength(PKVM* vm, const char* value, size_t length) { RET(VAR_OBJ(newStringLength(vm, value, (uint32_t)length))); } -// pkReturnValue implementation (see pocketlang.h for description). void pkReturnValue(PKVM* vm, PkVar value) { RET(*(Var*)value); } -// pkReturnHandle implementation (see pocketlang.h for description). void pkReturnHandle(PKVM* vm, PkHandle* handle) { RET(handle->value); } -// pkReturnInstNative implementation (see pocketlang.h for description). void pkReturnInstNative(PKVM* vm, void* data, uint32_t 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 */ /*****************************************************************************/ -// findBuiltinFunction implementation (see core.h for description). int findBuiltinFunction(const PKVM* vm, const char* name, uint32_t length) { for (uint32_t i = 0; i < vm->builtins_count; i++) { if (length == vm->builtins[i].length && @@ -428,24 +409,21 @@ int findBuiltinFunction(const PKVM* vm, const char* name, uint32_t length) { return -1; } -// getBuiltinFunction implementation (see core.h for description). Function* getBuiltinFunction(const PKVM* vm, int index) { ASSERT_INDEX((uint32_t)index, vm->builtins_count); return vm->builtins[index].fn; } -// getBuiltinFunctionName implementation (see core.h for description). const char* getBuiltinFunctionName(const PKVM* vm, int index) { ASSERT_INDEX((uint32_t)index, vm->builtins_count); return vm->builtins[index].name; } -// getCoreLib implementation (see core.h for description). -Script* getCoreLib(const PKVM* vm, String* name) { +Module* getCoreLib(const PKVM* vm, String* name) { Var lib = mapGet(vm->core_libs, VAR_OBJ(name)); if (IS_UNDEF(lib)) return NULL; - ASSERT(IS_OBJ_TYPE(lib, OBJ_SCRIPT), OOPS); - return (Script*)AS_OBJ(lib); + ASSERT(IS_OBJ_TYPE(lib, OBJ_MODULE), OOPS); + return (Module*)AS_OBJ(lib); } /*****************************************************************************/ @@ -777,42 +755,40 @@ DEF(coreMapRemove, /* CORE MODULE METHODS */ /*****************************************************************************/ -// Create a module and add it to the vm's core modules, returns the script. -static Script* newModuleInternal(PKVM* vm, const char* name) { +// Create a module and add it to the vm's core modules, returns the module. +static Module* newModuleInternal(PKVM* vm, const char* name) { - // Create a new Script for the module. 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 // hosting application. if (!IS_UNDEF(mapGet(vm->core_libs, VAR_OBJ(_name)))) { - vmPopTempRef(vm); // _name __ASSERT(false, stringFormat(vm, "A module named '$' already exists", name)->data); } - Script* scr = newScript(vm, _name, true); + Module* module = newModule(vm, _name, true); vmPopTempRef(vm); // _name - // Add the script to core_libs. - vmPushTempRef(vm, &scr->_super); - mapSet(vm, vm->core_libs, VAR_OBJ(_name), VAR_OBJ(scr)); - vmPopTempRef(vm); + // Add the module to core_libs. + vmPushTempRef(vm, &module->_super); // module. + mapSet(vm, vm->core_libs, VAR_OBJ(_name), VAR_OBJ(module)); + vmPopTempRef(vm); // module. - return scr; + return module; } -// An internal function to add a function to the given [script]. -static void moduleAddFunctionInternal(PKVM* vm, Script* script, +// An internal function to add a function to the given [module]. +static void moduleAddFunctionInternal(PKVM* vm, Module* module, const char* name, pkNativeFn fptr, int arity, const char* docstring) { Function* fn = newFunction(vm, name, (int)strlen(name), - script, true, docstring, NULL); + module, true, docstring, NULL); fn->native = fptr; 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. @@ -1261,7 +1237,7 @@ void initializeCore(PKVM* vm) { // Core Modules ///////////////////////////////////////////////////////////// - Script* lang = newModuleInternal(vm, "lang"); + Module* lang = newModuleInternal(vm, "lang"); MODULE_ADD_FN(lang, "clock", stdLangClock, 0); MODULE_ADD_FN(lang, "gc", stdLangGC, 0); MODULE_ADD_FN(lang, "disas", stdLangDisas, 1); @@ -1270,7 +1246,7 @@ void initializeCore(PKVM* vm) { MODULE_ADD_FN(lang, "debug_break", stdLangDebugBreak, 0); #endif - Script* math = newModuleInternal(vm, "math"); + Module* math = newModuleInternal(vm, "math"); MODULE_ADD_FN(math, "floor", stdMathFloor, 1); MODULE_ADD_FN(math, "ceil", stdMathCeil, 1); 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 // constant and pocketlang doesn't support constant) so the user shouldn't // 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, "run", stdFiberRun, -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_RANGE: - case OBJ_SCRIPT: + case OBJ_MODULE: case OBJ_FUNC: case OBJ_CLOSURE: case OBJ_UPVALUE: @@ -1562,7 +1538,7 @@ bool varContains(PKVM* vm, Var elem, Var container) { } break; case OBJ_RANGE: - case OBJ_SCRIPT: + case OBJ_MODULE: case OBJ_FUNC: case OBJ_CLOSURE: case OBJ_UPVALUE: @@ -1670,15 +1646,15 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) { UNREACHABLE(); } - case OBJ_SCRIPT: + case OBJ_MODULE: { - Script* scr = (Script*)obj; + Module* module = (Module*)obj; // Search in globals. - int index = scriptGetGlobalIndex(scr, attrib->data, attrib->length); + int index = moduleGetGlobalIndex(module, attrib->data, attrib->length); if (index != -1) { - ASSERT_INDEX((uint32_t)index, scr->globals.count); - return scr->globals.data[index]; + ASSERT_INDEX((uint32_t)index, module->globals.count); + return module->globals.data[index]; } ERR_NO_ATTRIB(vm, on, attrib); @@ -1795,14 +1771,14 @@ do { \ ERR_NO_ATTRIB(vm, on, attrib); return; - case OBJ_SCRIPT: { - Script* scr = (Script*)obj; + case OBJ_MODULE: { + Module* module = (Module*)obj; // Check globals. - int index = scriptGetGlobalIndex(scr, attrib->data, attrib->length); + int index = moduleGetGlobalIndex(module, attrib->data, attrib->length); if (index != -1) { - ASSERT_INDEX((uint32_t)index, scr->globals.count); - scr->globals.data[index] = value; + ASSERT_INDEX((uint32_t)index, module->globals.count); + module->globals.data[index] = value; return; } @@ -1909,7 +1885,7 @@ Var varGetSubscript(PKVM* vm, Var on, Var key) { } case OBJ_RANGE: - case OBJ_SCRIPT: + case OBJ_MODULE: case OBJ_FUNC: case OBJ_CLOSURE: case OBJ_UPVALUE: @@ -1961,7 +1937,7 @@ void varsetSubscript(PKVM* vm, Var on, Var key, Var value) { } case OBJ_RANGE: - case OBJ_SCRIPT: + case OBJ_MODULE: case OBJ_FUNC: case OBJ_CLOSURE: case OBJ_UPVALUE: diff --git a/src/pk_core.h b/src/pk_core.h index e0f0382..a0ab019 100644 --- a/src/pk_core.h +++ b/src/pk_core.h @@ -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, // otherwise returns NULL. -Script* getCoreLib(const PKVM* vm, String* name); +Module* getCoreLib(const PKVM* vm, String* name); /*****************************************************************************/ /* OPERATORS */ diff --git a/src/pk_debug.c b/src/pk_debug.c index 78571bc..25e2a0a 100644 --- a/src/pk_debug.c +++ b/src/pk_debug.c @@ -365,11 +365,11 @@ void dumpGlobalValues(PKVM* vm) { int frame_ind = fiber->frame_count - 1; ASSERT(frame_ind >= 0, OOPS); 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++) { - String* name = scr->names.data[scr->global_names.data[i]]; - Var value = scr->globals.data[i]; + for (uint32_t i = 0; i < module->global_names.count; i++) { + String* name = module->names.data[module->global_names.data[i]]; + Var value = module->globals.data[i]; printf("%10s = ", name->data); dumpValue(vm, value); printf("\n"); diff --git a/src/pk_value.c b/src/pk_value.c index c68dc27..34463b0 100644 --- a/src/pk_value.c +++ b/src/pk_value.c @@ -32,7 +32,7 @@ PkVarType pkGetValueType(const PkVar value) { case OBJ_LIST: return PK_LIST; case OBJ_MAP: return PK_MAP; 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_FIBER: return PK_FIBER; case OBJ_CLASS: return PK_CLASS; @@ -194,27 +194,27 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) { vm->bytes_allocated += sizeof(Range); } break; - case OBJ_SCRIPT: + case OBJ_MODULE: { - Script* scr = (Script*)obj; - vm->bytes_allocated += sizeof(Script); + Module* module = (Module*)obj; + vm->bytes_allocated += sizeof(Module); - markObject(vm, &scr->path->_super); - markObject(vm, &scr->name->_super); + markObject(vm, &module->path->_super); + markObject(vm, &module->name->_super); - markVarBuffer(vm, &scr->globals); - vm->bytes_allocated += sizeof(Var) * scr->globals.capacity; + markVarBuffer(vm, &module->globals); + vm->bytes_allocated += sizeof(Var) * module->globals.capacity; // 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); - vm->bytes_allocated += sizeof(Var) * scr->constants.capacity; + markVarBuffer(vm, &module->constants); + vm->bytes_allocated += sizeof(Var) * module->constants.capacity; - markStringBuffer(vm, &scr->names); - vm->bytes_allocated += sizeof(String*) * scr->names.capacity; + markStringBuffer(vm, &module->names); + vm->bytes_allocated += sizeof(String*) * module->names.capacity; - markObject(vm, &scr->body->_super); + markObject(vm, &module->body->_super); } break; case OBJ_FUNC: @@ -379,46 +379,47 @@ Range* newRange(PKVM* vm, double from, double to) { return range; } -Script* newScript(PKVM* vm, String* name, bool is_core) { - Script* script = ALLOCATE(vm, Script); - varInitObject(&script->_super, vm, OBJ_SCRIPT); +Module* newModule(PKVM* vm, String* name, bool is_core) { + Module* module = ALLOCATE(vm, Module); + varInitObject(&module->_super, vm, OBJ_MODULE); ASSERT(name != NULL && name->length > 0, OOPS); - script->path = name; - script->name = NULL; - script->initialized = is_core; - script->body = NULL; + module->path = name; + module->name = NULL; + module->initialized = is_core; + module->body = NULL; // Core modules has its name as the module name. - if (is_core) script->name = name; + if (is_core) module->name = name; - pkVarBufferInit(&script->globals); - pkUintBufferInit(&script->global_names); - pkVarBufferInit(&script->constants); - pkStringBufferInit(&script->names); + pkVarBufferInit(&module->globals); + pkUintBufferInit(&module->global_names); + pkVarBufferInit(&module->constants); + pkStringBufferInit(&module->names); // Add a implicit main function and the '__file__' global to the module, only // if it's not a core module. if (!is_core) { - vmPushTempRef(vm, &script->_super); - scriptAddMain(vm, script); + vmPushTempRef(vm, &module->_super); // module. + + moduleAddMain(vm, module); // Add '__file__' variable with it's path as value. If the path starts with // '@' It's a special file (@(REPL) or @(TRY)) and don't define __file__. - if (script->path->data[0] != SPECIAL_NAME_CHAR) { - scriptAddGlobal(vm, script, "__file__", 8, VAR_OBJ(script->path)); + if (module->path->data[0] != SPECIAL_NAME_CHAR) { + moduleAddGlobal(vm, module, "__file__", 8, VAR_OBJ(module->path)); } // TODO: Add ARGV as a global. - vmPopTempRef(vm); // 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, int* fn_index) { @@ -433,10 +434,10 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner, func->owner = NULL; } 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; - 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->owner = owner; @@ -457,7 +458,6 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner, func->fn = fn; } - // Both native and script (TODO:) functions support docstring. func->docstring = docstring; vmPopTempRef(vm); // func @@ -536,34 +536,35 @@ Fiber* newFiber(PKVM* vm, Function* fn) { 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) { Class* cls = ALLOCATE(vm, 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; pkUintBufferInit(&cls->field_names); - cls->owner = scr; - cls->name = scriptAddName(scr, vm, name, length); + cls->owner = module; + cls->name = moduleAddName(module, vm, name, length); - // FIXME: - // Make it possible to escape '@' and '$' character in formated string and - // replace below '%' with excaped '\@' (SPECIAL_NAME_CHAR) character. - String* ty_name = scr->names.data[cls->name]; - String* ctor_name = stringFormat(vm, "%(Ctor:@)", ty_name); + // Since characters '@' and '$' are special in stringFormat, and they + // currently cannot be escaped (TODO), a string (char array) created + // for that character and passed as C string format. + char special[2] = { SPECIAL_NAME_CHAR, '\0' }; + String* cls_name = module->names.data[cls->name]; + String* ctor_name = stringFormat(vm, "$(Ctor:@)", special, cls_name); // Constructor. vmPushTempRef(vm, &ctor_name->_super); // ctor_name 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); // type. + vmPopTempRef(vm); // class. return cls; } @@ -849,7 +850,7 @@ static uint32_t _hashObject(Object* obj) { return utilHashNumber(range->from) ^ utilHashNumber(range->to); } - case OBJ_SCRIPT: + case OBJ_MODULE: case OBJ_FUNC: case OBJ_FIBER: case OBJ_CLASS: @@ -1068,12 +1069,12 @@ void freeObject(PKVM* vm, Object* self) { case OBJ_RANGE: break; - case OBJ_SCRIPT: { - Script* scr = (Script*)self; - pkVarBufferClear(&scr->globals, vm); - pkUintBufferClear(&scr->global_names, vm); - pkVarBufferClear(&scr->constants, vm); - pkStringBufferClear(&scr->names, vm); + case OBJ_MODULE: { + Module* module = (Module*)self; + pkVarBufferClear(&module->globals, vm); + pkUintBufferClear(&module->global_names, vm); + pkVarBufferClear(&module->constants, vm); + pkStringBufferClear(&module->names, vm); } break; case OBJ_FUNC: { @@ -1123,21 +1124,21 @@ void freeObject(PKVM* vm, Object* self) { DEALLOCATE(vm, self); } -uint32_t scriptAddConstant(PKVM* vm, Script* script, Var value) { - for (uint32_t i = 0; i < script->constants.count; i++) { - if (isValuesSame(script->constants.data[i], value)) { +uint32_t moduleAddConstant(PKVM* vm, Module* module, Var value) { + for (uint32_t i = 0; i < module->constants.count; i++) { + if (isValuesSame(module->constants.data[i], value)) { return i; } } - pkVarBufferWrite(&script->constants, vm, value); - return (int)script->constants.count - 1; + pkVarBufferWrite(&module->constants, vm, value); + 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) { - for (uint32_t i = 0; i < self->names.count; i++) { - String* _name = self->names.data[i]; + for (uint32_t i = 0; i < module->names.count; i++) { + String* _name = module->names.data[i]; if (_name->length == length && strncmp(_name->data, name, length) == 0) { // Name already exists in the buffer. return i; @@ -1148,35 +1149,35 @@ uint32_t scriptAddName(Script* self, PKVM* vm, const char* name, // return the index. String* new_name = newStringLength(vm, name, length); vmPushTempRef(vm, &new_name->_super); - pkStringBufferWrite(&self->names, vm, new_name); + pkStringBufferWrite(&module->names, vm, new_name); 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, Var 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) { - ASSERT(g_index < (int)script->globals.count, OOPS); - script->globals.data[g_index] = value; + ASSERT(g_index < (int)module->globals.count, OOPS); + module->globals.data[g_index] = value; return g_index; } // If we're reached here that means we don't already have a variable with // that name, create new one and set the value. - uint32_t name_ind = scriptAddName(script, vm, name, length); - pkUintBufferWrite(&script->global_names, vm, name_ind); - pkVarBufferWrite(&script->globals, vm, value); - return script->globals.count - 1; + uint32_t name_ind = moduleAddName(module, vm, name, length); + pkUintBufferWrite(&module->global_names, vm, name_ind); + pkVarBufferWrite(&module->globals, vm, value); + return module->globals.count - 1; } -int scriptGetGlobalIndex(Script* script, const char* name, uint32_t length) { - for (uint32_t i = 0; i < script->global_names.count; i++) { - uint32_t name_index = script->global_names.data[i]; - String* g_name = script->names.data[name_index]; +int moduleGetGlobalIndex(Module* module, const char* name, uint32_t length) { + for (uint32_t i = 0; i < module->global_names.count; i++) { + uint32_t name_index = module->global_names.data[i]; + String* g_name = module->names.data[name_index]; if (g_name->length == length && strncmp(g_name->data, name, length) == 0) { return (int)i; } @@ -1184,23 +1185,23 @@ int scriptGetGlobalIndex(Script* script, const char* name, uint32_t length) { return -1; } -void scriptSetGlobal(Script* script, int index, Var value) { - ASSERT_INDEX(index, script->globals.count); - script->globals.data[index] = value; +void moduleSetGlobal(Module* module, int index, Var value) { + ASSERT_INDEX(index, (int)module->globals.count); + module->globals.data[index] = value; } -void scriptAddMain(PKVM* vm, Script* script) { - ASSERT(script->body == NULL, OOPS); +void moduleAddMain(PKVM* vm, Module* module) { + ASSERT(module->body == NULL, OOPS); const char* fn_name = IMPLICIT_MAIN_NAME; - script->body = newFunction(vm, fn_name, (int)strlen(fn_name), - script, false, NULL/*TODO*/, NULL); - script->body->arity = 0; - script->initialized = false; + module->body = newFunction(vm, fn_name, (int)strlen(fn_name), + module, false, NULL/*TODO*/, NULL); + module->body->arity = 0; + module->initialized = false; - scriptAddGlobal(vm, script, + moduleAddGlobal(vm, module, 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) { @@ -1340,7 +1341,7 @@ const char* getPkVarTypeName(PkVarType type) { case PK_LIST: return "List"; case PK_MAP: return "Map"; 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 // 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_MAP: return "Map"; case OBJ_RANGE: return "Range"; - case OBJ_SCRIPT: return "Script"; + case OBJ_MODULE: return "Module"; case OBJ_FUNC: return "Func"; case OBJ_CLOSURE: return "Closure"; case OBJ_UPVALUE: return "Upvalue"; @@ -1616,15 +1617,16 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff, return; } - case OBJ_SCRIPT: { - const Script* scr = (const Script*)obj; + case OBJ_MODULE: { + const Module* module = (const Module*)obj; pkByteBufferAddString(buff, vm, "[Module:", 8); - if (scr->name != NULL) { - pkByteBufferAddString(buff, vm, scr->name->data, - scr->name->length); + if (module->name != NULL) { + pkByteBufferAddString(buff, vm, module->name->data, + module->name->length); } else { 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, ']'); @@ -1751,7 +1753,7 @@ bool toBool(Var v) { case OBJ_LIST: return ((List*)o)->elements.count != 0; case OBJ_MAP: return ((Map*)o)->count != 0; case OBJ_RANGE: // [[FALLTHROUGH]] - case OBJ_SCRIPT: + case OBJ_MODULE: case OBJ_FUNC: case OBJ_FIBER: case OBJ_CLASS: diff --git a/src/pk_value.h b/src/pk_value.h index 7a48a5c..2d76534 100644 --- a/src/pk_value.h +++ b/src/pk_value.h @@ -188,7 +188,7 @@ typedef struct String String; typedef struct List List; typedef struct Map Map; typedef struct Range Range; -typedef struct Script Script; +typedef struct Module Module; typedef struct Function Function; typedef struct Closure Closure; typedef struct Upvalue Upvalue; @@ -214,7 +214,7 @@ typedef enum { OBJ_LIST, OBJ_MAP, OBJ_RANGE, - OBJ_SCRIPT, + OBJ_MODULE, OBJ_FUNC, OBJ_CLOSURE, OBJ_UPVALUE, @@ -269,15 +269,20 @@ struct Range { double to; //< End of the range exclusive. }; -// In pocketlang, the terms Script and Module are interchangable. (Consider -// renaming it to Module to be consistance with the terms). -struct Script { +// Module in pocketlang is a collection of globals, functions, classes and top +// level statements, they can be imported in other modules generally a +// pocketlang script will compiled to a module. +struct Module { Object _super; - // For core libraries the name and the path are same and points to the - // same String objects. - String* name; //< Module name of the script. - String* path; //< Path of the script. + // The [name] is the module name defined with either 'module' statement + // in the script or the provided name for native modules when creating. + // For core modules the name and the path are same and will points to the + // 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 // 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. // 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) // in the names buffer where j = global_names[i]. pkVarBuffer globals; 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 - // global values, this will be false if the module isn't initialized yet and - // we need to execute the script's body whe we're importing it. + // If the [initialized] boolean is false, the body function of the module + // will be executed when it's first imported and the 'initialized' boolean + // 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; }; -// Script function pointer. +// A struct contain opcodes and other information of a compiled function. typedef struct { pkByteBuffer opcodes; //< Buffer of opcodes. pkUintBuffer oplines; //< Line number of opcodes for debug (1 based). @@ -319,8 +327,23 @@ typedef struct { struct Function { Object _super; - const char* name; //< Name in the script [owner] or C literal. - Script* owner; //< Owner script of the function. + // The module that owns this function. Since built in functions doesn't + // 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 // the function has a variadic number of parameters. When a function is @@ -337,10 +360,12 @@ struct Function { // native functions to provide a 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 { - pkNativeFn native; //< Native function pointer. - Fn* fn; //< Script function pointer. + pkNativeFn native; //< Native function pointer. + Fn* fn; //< Pocket function pointer. }; }; @@ -429,8 +454,7 @@ struct Fiber { FiberState state; - // The root function of the fiber. (For script it'll be the script's implicit - // body function). + // The root function of the fiber. Function* func; // The stack of the execution holding locals and temps. A heap will be @@ -462,8 +486,12 @@ struct Fiber { struct Class { Object _super; - Script* owner; //< The script it belongs to. - uint32_t name; //< Index of the type's name in the script's name buffer. + // The module that owns this class. + Module* owner; + + // The index of the name of this class in the owner module's names + // buffer. + uint32_t name; Function* ctor; //< The constructor function. pkUintBuffer field_names; //< Buffer of field names. @@ -524,22 +552,13 @@ Map* newMap(PKVM* vm); // Allocate new Range object and return Range*. Range* newRange(PKVM* vm, double from, double to); -// Allocate new Script object and return Script*, if the argument [is_core] is -// true the script will be used as a core module and the body of the script -// would be NULL and the [name] will be used as the module name. Otherwise the -// [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: +// We may need 2 different constructor for native and script modules. +Module* newModule(PKVM* vm, String* name, bool is_core); // FIXME: -// This bellow function will only to be used for module functions and the -// parameter native is used for builtin functions which will be it's own -// 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, +// We may need 2 different constuctor for native and script functions. +Function* newFunction(PKVM* vm, const char* name, int length, Module* owner, bool is_native, const char* docstring, int* fn_index); @@ -556,7 +575,7 @@ Fiber* newFiber(PKVM* vm, Function* fn); // Same fix has to applied as newFunction() (see above). // // 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); // 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. 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. -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 // 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); -// Add a global [value] to the [scrpt] and return its index. -uint32_t scriptAddGlobal(PKVM* vm, Script* script, +// Add a global [value] to the [module] and return its index. +uint32_t moduleAddGlobal(PKVM* vm, Module* module, const char* name, uint32_t length, 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. -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]. -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 -// the script'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 -// before calling this function. -void scriptAddMain(PKVM* vm, Script* script); +// This will allocate a new implicit main function for the module and assign to +// the module's body attribute. And the attribute initialized will be set to +// false. Note that the body of the module should be NULL before calling this +// function. +void moduleAddMain(PKVM* vm, Module* module); // 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. diff --git a/src/pk_vm.c b/src/pk_vm.c index 5fcd85d..a0140a2 100644 --- a/src/pk_vm.c +++ b/src/pk_vm.c @@ -68,7 +68,7 @@ PKVM* pkNewVM(PkConfiguration* config) { vm->min_heap_size = MIN_HEAP_SIZE; vm->heap_fill_percent = HEAP_FILL_PERCENT; - vm->scripts = newMap(vm); + vm->modules = newMap(vm); vm->core_libs = newMap(vm); 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); 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. - Script* scr = vmGetScript(vm, path_name); - if (scr == NULL) { - scr = newScript(vm, path_name, false); - vmPushTempRef(vm, &scr->_super); // scr. - mapSet(vm, vm->scripts, VAR_OBJ(path_name), VAR_OBJ(scr)); - vmPopTempRef(vm); // scr. + // Load a new module to the vm's modules cache. + Module* module = vmGetModule(vm, path_name); + if (module == NULL) { + module = newModule(vm, path_name, false); + vmPushTempRef(vm, &module->_super); // module. + mapSet(vm, vm->modules, VAR_OBJ(path_name), VAR_OBJ(module)); + vmPopTempRef(vm); // module. } vmPopTempRef(vm); // path_name. // 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 (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. - 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, @@ -241,11 +241,11 @@ void vmPopTempRef(PKVM* vm) { vm->temp_reference_count--; } -Script* vmGetScript(PKVM* vm, String* path) { - Var scr = mapGet(vm->scripts, VAR_OBJ(path)); - if (IS_UNDEF(scr)) return NULL; - ASSERT(AS_OBJ(scr)->type == OBJ_SCRIPT, OOPS); - return (Script*)AS_OBJ(scr); +Module* vmGetModule(PKVM* vm, String* path) { + Var module = mapGet(vm->modules, VAR_OBJ(path)); + if (IS_UNDEF(module)) return NULL; + ASSERT(AS_OBJ(module)->type == OBJ_MODULE, OOPS); + return (Module*)AS_OBJ(module); } void vmCollectGarbage(PKVM* vm) { @@ -260,8 +260,8 @@ void vmCollectGarbage(PKVM* vm) { markObject(vm, &vm->builtins[i].fn->_super); } - // Mark the scripts cache. - markObject(vm, &vm->scripts->_super); + // Mark the modules cache. + markObject(vm, &vm->modules->_super); // Mark temp references. 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); } -// Import and return Script object as Var. If the script is imported and -// compiled here it'll set [is_new_script] to true otherwise (using the cached -// script) set to false. -static inline Var importScript(PKVM* vm, String* path_name) { +// FIXME: +// We're assuming that the module should be available at the VM's modules cache +// which is added by the compilation pahse, but we cannot rely on the +// 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. - Script* scr = getCoreLib(vm, path_name); - if (scr != NULL) return VAR_OBJ(scr); + Module* module = getCoreLib(vm, name); + if (module != NULL) return VAR_OBJ(module); - // Check in the scripts cache. - Var entry = mapGet(vm->scripts, VAR_OBJ(path_name)); + // Check in the modules cache. + Var entry = mapGet(vm->modules, VAR_OBJ(name)); if (!IS_UNDEF(entry)) { - ASSERT(AS_OBJ(entry)->type == OBJ_SCRIPT, OOPS); + ASSERT(AS_OBJ(entry)->type == OBJ_MODULE, OOPS); return entry; } - // Imported scripts were resolved at compile time. + // FIXME: Should be a runtime error. + // Imported modules were resolved at compile time. UNREACHABLE(); return VAR_NULL; @@ -590,7 +600,7 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) { register Var* rbp; //< Stack base pointer register. register CallFrame* frame; //< Current call frame. - register Script* script; //< Currently executing script. + register Module* module; //< Currently executing module. #if DEBUG #define PUSH(value) \ @@ -648,7 +658,7 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) { frame = &vm->fiber->frames[vm->fiber->frame_count-1]; \ ip = frame->ip; \ rbp = frame->rbp; \ - script = frame->fn->owner; \ + module = frame->fn->owner; \ } while (false) // Update the frame's execution variables before pushing another call frame. @@ -683,8 +693,8 @@ L_vm_main_loop: OPCODE(PUSH_CONSTANT): { uint16_t index = READ_SHORT(); - ASSERT_INDEX(index, script->constants.count); - PUSH(script->constants.data[index]); + ASSERT_INDEX(index, module->constants.count); + PUSH(module->constants.data[index]); DISPATCH(); } @@ -729,10 +739,10 @@ L_vm_main_loop: OPCODE(PUSH_INSTANCE): { uint8_t index = READ_SHORT(); - ASSERT_INDEX(index, script->constants.count); - ASSERT(IS_OBJ_TYPE(script->constants.data[index], OBJ_CLASS), OOPS); + ASSERT_INDEX(index, module->constants.count); + ASSERT(IS_OBJ_TYPE(module->constants.data[index], OBJ_CLASS), OOPS); Instance* inst = newInstance(vm, - (Class*)AS_OBJ(script->constants.data[index]), false); + (Class*)AS_OBJ(module->constants.data[index]), false); PUSH(VAR_OBJ(inst)); DISPATCH(); } @@ -827,16 +837,16 @@ L_vm_main_loop: OPCODE(PUSH_GLOBAL): { uint8_t index = READ_BYTE(); - ASSERT_INDEX(index, script->globals.count); - PUSH(script->globals.data[index]); + ASSERT_INDEX(index, module->globals.count); + PUSH(module->globals.data[index]); DISPATCH(); } OPCODE(STORE_GLOBAL): { uint8_t index = READ_BYTE(); - ASSERT_INDEX(index, script->globals.count); - script->globals.data[index] = PEEK(-1); + ASSERT_INDEX(index, module->globals.count); + module->globals.data[index] = PEEK(-1); DISPATCH(); } @@ -855,32 +865,32 @@ L_vm_main_loop: OPCODE(IMPORT): { - String* name = script->names.data[READ_SHORT()]; - Var scr = importScript(vm, name); + String* name = module->names.data[READ_SHORT()]; - ASSERT(IS_OBJ_TYPE(scr, OBJ_SCRIPT), OOPS); - Script* module = (Script*)AS_OBJ(scr); - PUSH(scr); + Var _imported = importModule(vm, name); + ASSERT(IS_OBJ_TYPE(_imported, OBJ_MODULE), OOPS); + PUSH(_imported); // TODO: If the body doesn't have any statements (just the functions). // This initialization call is un-necessary. - if (!module->initialized) { - module->initialized = true; + Module* imported = (Module*)AS_OBJ(_imported); + 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 // 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 // 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 // stack top would be the module itself. Var* module_ret = vm->fiber->sp - 1; 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. } @@ -1065,7 +1075,7 @@ L_vm_main_loop: } DISPATCH(); - case OBJ_SCRIPT: + case OBJ_MODULE: case OBJ_FUNC: case OBJ_CLOSURE: case OBJ_UPVALUE: @@ -1174,7 +1184,7 @@ L_vm_main_loop: OPCODE(GET_ATTRIB): { 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); DROP(); // on PUSH(value); @@ -1186,7 +1196,7 @@ L_vm_main_loop: OPCODE(GET_ATTRIB_KEEP): { Var on = PEEK(-1); - String* name = script->names.data[READ_SHORT()]; + String* name = module->names.data[READ_SHORT()]; PUSH(varGetAttrib(vm, on, name)); CHECK_ERROR(); DISPATCH(); @@ -1196,7 +1206,7 @@ L_vm_main_loop: { Var value = PEEK(-1); // Don't pop yet, we need the reference for gc. Var on = PEEK(-2); // Don't pop yet, we need the reference for gc. - String* name = script->names.data[READ_SHORT()]; + String* name = module->names.data[READ_SHORT()]; varSetAttrib(vm, on, name, value); DROP(); // value diff --git a/src/pk_vm.h b/src/pk_vm.h index f272dfe..63d1dda 100644 --- a/src/pk_vm.h +++ b/src/pk_vm.h @@ -46,9 +46,8 @@ (vm->fiber->error = err); \ } while (false) -// Builtin functions are stored in an array in the VM (unlike script functions -// they're member of function buffer of the script) and this struct is a single -// entry of the array. +// Builtin functions are stored in an array in the VM unlike other functions +// builtin function's doesn't belongs to any module. typedef struct { const char* name; //< Name of the function. 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 // 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 - // a new script is being imported and compiled at compiletime. + // a new module is being imported and compiled at compiletime. 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. - 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. Map* core_libs; @@ -192,9 +191,9 @@ void vmPushTempRef(PKVM* vm, Object* obj); // Pop the top most object from temporary reference stack. void vmPopTempRef(PKVM* vm); -// Returns the scrpt with the resolved [path] (also the key) in the vm's script -// cache. If not found itll return NULL. -Script* vmGetScript(PKVM* vm, String* path); +// Returns the module with the resolved [path] (also the key) in the VM's +// modules cache. If not found itll return NULL. +Module* vmGetModule(PKVM* vm, String* path); // ((Context switching - start)) // Prepare a new fiber for execution with the given arguments. That can be used