mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 15:16:41 +08:00
script renamed to modules
The name script is missleading as it only refering to the scripts (the files that contain the statements) where as it could also be the native module objects containing collection of native functions. After this commit, native functions can also have set owner module and it won't be as confusing as before.
This commit is contained in:
parent
133a560283
commit
20b99c60b3
@ -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.
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
130
src/pk_core.c
130
src/pk_core.c
@ -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:
|
||||||
|
@ -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 */
|
||||||
|
@ -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");
|
||||||
|
196
src/pk_value.c
196
src/pk_value.c
@ -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:
|
||||||
|
123
src/pk_value.h
123
src/pk_value.h
@ -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.
|
||||||
|
120
src/pk_vm.c
120
src/pk_vm.c
@ -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
|
||||||
|
19
src/pk_vm.h
19
src/pk_vm.h
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user