mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-05 20:26:53 +08:00
class implemented
This commit is contained in:
parent
3f1d0e9380
commit
41ed7dd991
6
Makefile
6
Makefile
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
# ## Copyright (c) 2020-2021 Thakee Nathees
|
## Copyright (c) 2020-2021 Thakee Nathees
|
||||||
# ## Distributed Under The MIT License
|
## Distributed Under The MIT License
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -fPIC -Wno-int-to-pointer-cast
|
CFLAGS = -fPIC
|
||||||
DEBUG_CFLAGS = -D DEBUG -g3 -Og
|
DEBUG_CFLAGS = -D DEBUG -g3 -Og
|
||||||
RELEASE_CFLAGS = -g -O3
|
RELEASE_CFLAGS = -g -O3
|
||||||
LDFLAGS = -lm
|
LDFLAGS = -lm
|
||||||
|
@ -68,7 +68,7 @@ except for a c99 compatible compiler. It can be compiled with the following comm
|
|||||||
|
|
||||||
#### GCC / MinGw / Clang (alias with gcc)
|
#### GCC / MinGw / Clang (alias with gcc)
|
||||||
```
|
```
|
||||||
gcc -o pocket cli/*.c src/*.c -Isrc/include -lm -Wno-int-to-pointer-cast
|
gcc -o pocket cli/*.c src/*.c -Isrc/include -lm
|
||||||
```
|
```
|
||||||
|
|
||||||
#### MSVC
|
#### MSVC
|
||||||
|
@ -130,7 +130,7 @@ PkStringPtr loadScript(PKVM* vm, const char* path) {
|
|||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
const char* usage = "usage: pocket [-c cmd | file]\n";
|
//const char* usage = "usage: pocket [-c cmd | file]\n";
|
||||||
|
|
||||||
// TODO: implement arg parse, REPL.
|
// TODO: implement arg parse, REPL.
|
||||||
|
|
||||||
|
@ -126,10 +126,10 @@ static void _pathRelpath(PKVM* vm) {
|
|||||||
if (!pkGetArgString(vm, 2, &path)) return;
|
if (!pkGetArgString(vm, 2, &path)) return;
|
||||||
|
|
||||||
char abs_from[FILENAME_MAX];
|
char abs_from[FILENAME_MAX];
|
||||||
size_t len_from = pathAbs(from, abs_from, sizeof(abs_from));
|
pathAbs(from, abs_from, sizeof(abs_from));
|
||||||
|
|
||||||
char abs_path[FILENAME_MAX];
|
char abs_path[FILENAME_MAX];
|
||||||
size_t len_path = pathAbs(path, abs_path, sizeof(abs_path));
|
pathAbs(path, abs_path, sizeof(abs_path));
|
||||||
|
|
||||||
char result[FILENAME_MAX];
|
char result[FILENAME_MAX];
|
||||||
size_t len = cwk_path_get_relative(abs_from, abs_path,
|
size_t len = cwk_path_get_relative(abs_from, abs_path,
|
||||||
|
@ -33,7 +33,7 @@ const char* read_line(uint32_t* length) {
|
|||||||
// Read a line from stdin and returns it without the line ending.
|
// Read a line from stdin and returns it without the line ending.
|
||||||
static void readLine(ByteBuffer* buff) {
|
static void readLine(ByteBuffer* buff) {
|
||||||
do {
|
do {
|
||||||
char c = fgetc(stdin);
|
char c = (char)fgetc(stdin);
|
||||||
if (c == EOF || c == '\n') break;
|
if (c == EOF || c == '\n') break;
|
||||||
|
|
||||||
byteBufferWrite(buff, (uint8_t)c);
|
byteBufferWrite(buff, (uint8_t)c);
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
// To implement.
|
// To implement.
|
||||||
|
|
||||||
|
- no __file__ for core modules.
|
||||||
|
|
||||||
- def f(x)
|
- def f(x)
|
||||||
f(x) ## not tco, unless return f(x)
|
f(x) ## not tco, unless return f(x)
|
||||||
end
|
end
|
||||||
|
@ -89,6 +89,8 @@ typedef enum {
|
|||||||
PK_SCRIPT,
|
PK_SCRIPT,
|
||||||
PK_FUNCTION,
|
PK_FUNCTION,
|
||||||
PK_FIBER,
|
PK_FIBER,
|
||||||
|
PK_CLASS,
|
||||||
|
PK_INST,
|
||||||
} PkVarType;
|
} PkVarType;
|
||||||
|
|
||||||
typedef struct PkStringPtr PkStringPtr;
|
typedef struct PkStringPtr PkStringPtr;
|
||||||
@ -387,7 +389,6 @@ PK_PUBLIC PkHandle* pkNewFiber(PKVM* vm, PkHandle* fn);
|
|||||||
//PK_PUBLIC PkVar pkPushBool(PKVM* vm, bool value);
|
//PK_PUBLIC PkVar pkPushBool(PKVM* vm, bool value);
|
||||||
//PK_PUBLIC PkVar pkPushNumber(PKVM* vm, double value);
|
//PK_PUBLIC PkVar pkPushNumber(PKVM* vm, double value);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
@ -77,6 +77,14 @@
|
|||||||
/* COMMON MACROS */
|
/* COMMON MACROS */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
|
#elif defined(__clang__)
|
||||||
|
#pragma clang diagnostic ignored "-Wint-to-pointer-cast"
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h> //< Only needed here for ASSERT() macro and for release mode
|
#include <stdio.h> //< Only needed here for ASSERT() macro and for release mode
|
||||||
//< TODO; macro use this to print a crash report.
|
//< TODO; macro use this to print a crash report.
|
||||||
|
|
||||||
|
@ -17,9 +17,13 @@
|
|||||||
#define MAX_VARIABLES 256
|
#define MAX_VARIABLES 256
|
||||||
|
|
||||||
// The maximum number of functions a script could contain. Also it's limited by
|
// The maximum number of functions a script could contain. Also it's limited by
|
||||||
// it's opcode which is using a single byte value to identify the local.
|
// it's opcode which is using a single byte value to identify.
|
||||||
#define MAX_FUNCTIONS 256
|
#define MAX_FUNCTIONS 256
|
||||||
|
|
||||||
|
// The maximum number of classes a script could contain. Also it's limited by
|
||||||
|
// it's opcode which is using a single byte value to identify.
|
||||||
|
#define MAX_CLASSES 255
|
||||||
|
|
||||||
// The maximum number of names that were used before defined. Its just the size
|
// The maximum number of names that were used before defined. Its just the size
|
||||||
// of the Forward buffer of the compiler. Feel free to increase it if it
|
// of the Forward buffer of the compiler. Feel free to increase it if it
|
||||||
// require more.
|
// require more.
|
||||||
@ -107,6 +111,7 @@ typedef enum {
|
|||||||
|
|
||||||
// Keywords.
|
// Keywords.
|
||||||
TK_MODULE, // module
|
TK_MODULE, // module
|
||||||
|
TK_CLASS, // class
|
||||||
TK_FROM, // from
|
TK_FROM, // from
|
||||||
TK_IMPORT, // import
|
TK_IMPORT, // import
|
||||||
TK_AS, // as
|
TK_AS, // as
|
||||||
@ -170,6 +175,7 @@ typedef struct {
|
|||||||
// List of keywords mapped into their identifiers.
|
// List of keywords mapped into their identifiers.
|
||||||
static _Keyword _keywords[] = {
|
static _Keyword _keywords[] = {
|
||||||
{ "module", 6, TK_MODULE },
|
{ "module", 6, TK_MODULE },
|
||||||
|
{ "class", 5, TK_CLASS },
|
||||||
{ "from", 4, TK_FROM },
|
{ "from", 4, TK_FROM },
|
||||||
{ "import", 6, TK_IMPORT },
|
{ "import", 6, TK_IMPORT },
|
||||||
{ "as", 2, TK_AS },
|
{ "as", 2, TK_AS },
|
||||||
@ -973,6 +979,7 @@ typedef enum {
|
|||||||
NAME_LOCAL_VAR, //< Including parameter.
|
NAME_LOCAL_VAR, //< Including parameter.
|
||||||
NAME_GLOBAL_VAR,
|
NAME_GLOBAL_VAR,
|
||||||
NAME_FUNCTION,
|
NAME_FUNCTION,
|
||||||
|
NAME_CLASS,
|
||||||
NAME_BUILTIN, //< Native builtin function.
|
NAME_BUILTIN, //< Native builtin function.
|
||||||
} NameDefnType;
|
} NameDefnType;
|
||||||
|
|
||||||
@ -1025,6 +1032,14 @@ static NameSearchResult compilerSearchName(Compiler* compiler,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search through classes.
|
||||||
|
index = scriptGetClass(compiler->script, name, length);
|
||||||
|
if (index != -1) {
|
||||||
|
result.type = NAME_CLASS;
|
||||||
|
result.index = index;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Search through functions.
|
// Search through functions.
|
||||||
index = scriptGetFunc(compiler->script, name, length);
|
index = scriptGetFunc(compiler->script, name, length);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
@ -1140,6 +1155,7 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence
|
|||||||
/* TK_SRIGHT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
/* TK_SRIGHT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
||||||
/* TK_SLEFT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
/* TK_SLEFT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
||||||
/* TK_MODULE */ NO_RULE,
|
/* TK_MODULE */ NO_RULE,
|
||||||
|
/* TK_CLASS */ NO_RULE,
|
||||||
/* TK_FROM */ NO_RULE,
|
/* TK_FROM */ NO_RULE,
|
||||||
/* TK_IMPORT */ NO_RULE,
|
/* TK_IMPORT */ NO_RULE,
|
||||||
/* TK_AS */ NO_RULE,
|
/* TK_AS */ NO_RULE,
|
||||||
@ -1293,6 +1309,11 @@ static void exprName(Compiler* compiler) {
|
|||||||
emitByte(compiler, result.index);
|
emitByte(compiler, result.index);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NAME_CLASS:
|
||||||
|
emitOpcode(compiler, OP_PUSH_TYPE);
|
||||||
|
emitByte(compiler, result.index);
|
||||||
|
break;
|
||||||
|
|
||||||
case NAME_BUILTIN:
|
case NAME_BUILTIN:
|
||||||
emitOpcode(compiler, OP_PUSH_BUILTIN_FN);
|
emitOpcode(compiler, OP_PUSH_BUILTIN_FN);
|
||||||
emitByte(compiler, result.index);
|
emitByte(compiler, result.index);
|
||||||
@ -1776,6 +1797,19 @@ static void compilerExitBlock(Compiler* compiler) {
|
|||||||
compiler->scope_depth--;
|
compiler->scope_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void compilerPushFunc(Compiler* compiler, Func* fn,
|
||||||
|
Function* func, int index) {
|
||||||
|
fn->outer_func = compiler->func;
|
||||||
|
fn->ptr = func;
|
||||||
|
fn->depth = compiler->scope_depth;
|
||||||
|
fn->index = index;
|
||||||
|
compiler->func = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compilerPopFunc(Compiler* compiler) {
|
||||||
|
compiler->func = compiler->func->outer_func;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* COMPILING (EMIT BYTECODE) */
|
/* COMPILING (EMIT BYTECODE) */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -1864,6 +1898,94 @@ 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 type and return it's index in the script's types buffer.
|
||||||
|
static int compileType(Compiler* compiler) {
|
||||||
|
|
||||||
|
// Consume the name of the type.
|
||||||
|
consume(compiler, TK_NAME, "Expected a type name.");
|
||||||
|
const char* name = compiler->previous.start;
|
||||||
|
int name_len = compiler->previous.length;
|
||||||
|
NameSearchResult result = compilerSearchName(compiler, name, name_len);
|
||||||
|
if (result.type != NAME_NOT_DEFINED) {
|
||||||
|
parseError(compiler, "Name '%.*s' already exists.", name_len, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new type.
|
||||||
|
Class* type = newClass(compiler->vm, compiler->script,
|
||||||
|
name, (uint32_t)name_len);
|
||||||
|
type->ctor->arity = 0;
|
||||||
|
|
||||||
|
// Check count exceeded.
|
||||||
|
int fn_index = (int)compiler->script->functions.count - 1;
|
||||||
|
if (fn_index == MAX_FUNCTIONS) {
|
||||||
|
parseError(compiler, "A script should contain at most %d functions.",
|
||||||
|
MAX_FUNCTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ty_index = (int)(compiler->script->classes.count - 1);
|
||||||
|
if (ty_index == MAX_CLASSES) {
|
||||||
|
parseError(compiler, "A script should contain at most %d types.",
|
||||||
|
MAX_CLASSES);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile the constructor function.
|
||||||
|
ASSERT(compiler->func->ptr == compiler->script->body, OOPS);
|
||||||
|
Func curr_fn;
|
||||||
|
compilerPushFunc(compiler, &curr_fn, type->ctor, fn_index);
|
||||||
|
compilerEnterBlock(compiler);
|
||||||
|
|
||||||
|
// Push an instance on the stack.
|
||||||
|
emitOpcode(compiler, OP_PUSH_INSTANCE);
|
||||||
|
emitByte(compiler, ty_index);
|
||||||
|
|
||||||
|
skipNewLines(compiler);
|
||||||
|
TokenType next = peek(compiler);
|
||||||
|
while (next != TK_END && next != TK_EOF) {
|
||||||
|
|
||||||
|
// Compile field name.
|
||||||
|
consume(compiler, TK_NAME, "Expected a type name.");
|
||||||
|
const char* f_name = compiler->previous.start;
|
||||||
|
int f_len = compiler->previous.length;
|
||||||
|
|
||||||
|
uint32_t f_index = scriptAddName(compiler->script, compiler->vm,
|
||||||
|
f_name, f_len);
|
||||||
|
|
||||||
|
// TODO: Add a string compare macro.
|
||||||
|
String* new_name = compiler->script->names.data[f_index];
|
||||||
|
for (uint32_t i = 0; i < type->field_names.count; i++) {
|
||||||
|
String* prev = compiler->script->names.data[type->field_names.data[i]];
|
||||||
|
if (new_name->hash == prev->hash && new_name->length == prev->length &&
|
||||||
|
memcmp(new_name->data, prev->data, prev->length) == 0) {
|
||||||
|
parseError(compiler, "Class field with name '%s' already exists.",
|
||||||
|
new_name->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pkUintBufferWrite(&type->field_names, compiler->vm, f_index);
|
||||||
|
|
||||||
|
// Consume the assignment expression.
|
||||||
|
consume(compiler, TK_EQ, "Expected an assignment after field name.");
|
||||||
|
compileExpression(compiler); // Assigned value.
|
||||||
|
consumeEndStatement(compiler);
|
||||||
|
|
||||||
|
// At this point the stack top would be the expression.
|
||||||
|
emitOpcode(compiler, OP_INST_APPEND);
|
||||||
|
|
||||||
|
skipNewLines(compiler);
|
||||||
|
next = peek(compiler);
|
||||||
|
}
|
||||||
|
consume(compiler, TK_END, "Expected 'end' after type declaration end.");
|
||||||
|
|
||||||
|
compilerExitBlock(compiler);
|
||||||
|
|
||||||
|
// At this point, the stack top would be the constructed instance. Return it.
|
||||||
|
emitFunctionEnd(compiler);
|
||||||
|
|
||||||
|
compilerPopFunc(compiler);
|
||||||
|
|
||||||
|
return -1; // TODO;
|
||||||
|
}
|
||||||
|
|
||||||
// Compile a function and return it's index in the script's function buffer.
|
// Compile a function and return it's index in the script's function buffer.
|
||||||
static int compileFunction(Compiler* compiler, FuncType fn_type) {
|
static int compileFunction(Compiler* compiler, FuncType fn_type) {
|
||||||
|
|
||||||
@ -1892,13 +2014,8 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) {
|
|||||||
MAX_FUNCTIONS);
|
MAX_FUNCTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
Func curr_func;
|
Func curr_fn;
|
||||||
curr_func.outer_func = compiler->func;
|
compilerPushFunc(compiler, &curr_fn, func, fn_index);
|
||||||
curr_func.ptr = func;
|
|
||||||
curr_func.depth = compiler->scope_depth;
|
|
||||||
curr_func.index = fn_index;
|
|
||||||
|
|
||||||
compiler->func = &curr_func;
|
|
||||||
|
|
||||||
int argc = 0;
|
int argc = 0;
|
||||||
compilerEnterBlock(compiler); // Parameter depth.
|
compilerEnterBlock(compiler); // Parameter depth.
|
||||||
@ -1968,7 +2085,8 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) {
|
|||||||
printf("%s", buff.data);
|
printf("%s", buff.data);
|
||||||
pkByteBufferClear(&buff, compiler->vm);
|
pkByteBufferClear(&buff, compiler->vm);
|
||||||
#endif
|
#endif
|
||||||
compiler->func = compiler->func->outer_func;
|
|
||||||
|
compilerPopFunc(compiler);
|
||||||
|
|
||||||
return fn_index;
|
return fn_index;
|
||||||
}
|
}
|
||||||
@ -2156,6 +2274,7 @@ static int compilerImportName(Compiler* compiler, int line,
|
|||||||
return result.index;
|
return result.index;
|
||||||
|
|
||||||
case NAME_FUNCTION:
|
case NAME_FUNCTION:
|
||||||
|
case NAME_CLASS:
|
||||||
case NAME_BUILTIN:
|
case NAME_BUILTIN:
|
||||||
parseError(compiler, "Name '%.*s' already exists.", length, name);
|
parseError(compiler, "Name '%.*s' already exists.", length, name);
|
||||||
return -1;
|
return -1;
|
||||||
@ -2196,8 +2315,12 @@ static void compilerImportAll(Compiler* compiler, Script* script) {
|
|||||||
ASSERT(script != NULL, OOPS);
|
ASSERT(script != NULL, OOPS);
|
||||||
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
|
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
|
||||||
|
|
||||||
bool done = false; //< A flag to jump out of the loop.
|
// Import all types.
|
||||||
pkUintBuffer* name_buff = NULL; //< The string buffer to iterate through.
|
for (uint32_t i = 0; i < script->classes.count; i++) {
|
||||||
|
uint32_t name_ind = script->classes.data[i]->name;
|
||||||
|
String* name = script->names.data[name_ind];
|
||||||
|
compilerImportSingleEntry(compiler, name->data, name->length);
|
||||||
|
}
|
||||||
|
|
||||||
// Import all functions.
|
// Import all functions.
|
||||||
for (uint32_t i = 0; i < script->functions.count; i++) {
|
for (uint32_t i = 0; i < script->functions.count; i++) {
|
||||||
@ -2581,7 +2704,10 @@ static void compileTopLevelStatement(Compiler* compiler) {
|
|||||||
// If the statement is call, this will be set to true.
|
// If the statement is call, this will be set to true.
|
||||||
compiler->is_last_call = false;
|
compiler->is_last_call = false;
|
||||||
|
|
||||||
if (match(compiler, TK_NATIVE)) {
|
if (match(compiler, TK_CLASS)) {
|
||||||
|
compileType(compiler);
|
||||||
|
|
||||||
|
} else if (match(compiler, TK_NATIVE)) {
|
||||||
compileFunction(compiler, FN_NATIVE);
|
compileFunction(compiler, FN_NATIVE);
|
||||||
|
|
||||||
} else if (match(compiler, TK_DEF)) {
|
} else if (match(compiler, TK_DEF)) {
|
||||||
@ -2624,10 +2750,11 @@ PkResult compile(PKVM* vm, Script* script, const char* source,
|
|||||||
ASSERT(script->body != NULL, OOPS);
|
ASSERT(script->body != NULL, OOPS);
|
||||||
pkByteBufferClear(&script->body->fn->opcodes, vm);
|
pkByteBufferClear(&script->body->fn->opcodes, vm);
|
||||||
|
|
||||||
// Remember the count of the globals and functions, If the compilation failed
|
// Remember the count of the globals, functions and types, If the compilation
|
||||||
// discard all the globals and functions added by the compilation.
|
// failed discard all the globals and functions added by the compilation.
|
||||||
uint32_t globals_count = script->globals.count;
|
uint32_t globals_count = script->globals.count;
|
||||||
uint32_t functions_count = script->functions.count;
|
uint32_t functions_count = script->functions.count;
|
||||||
|
uint32_t types_count = script->classes.count;
|
||||||
|
|
||||||
Func curr_fn;
|
Func curr_fn;
|
||||||
curr_fn.depth = DEPTH_SCRIPT;
|
curr_fn.depth = DEPTH_SCRIPT;
|
||||||
@ -2688,6 +2815,7 @@ PkResult compile(PKVM* vm, Script* script, const char* source,
|
|||||||
if (compiler->has_errors) {
|
if (compiler->has_errors) {
|
||||||
script->globals.count = script->global_names.count = globals_count;
|
script->globals.count = script->global_names.count = globals_count;
|
||||||
script->functions.count = functions_count;
|
script->functions.count = functions_count;
|
||||||
|
script->classes.count = types_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_DUMP_COMPILED_CODE
|
#if DEBUG_DUMP_COMPILED_CODE
|
||||||
|
@ -815,12 +815,14 @@ DEF(stdLangDisas,
|
|||||||
RET(VAR_OBJ(dump));
|
RET(VAR_OBJ(dump));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
DEF(stdLangDebugBreak,
|
DEF(stdLangDebugBreak,
|
||||||
"debug_break() -> null\n"
|
"debug_break() -> null\n"
|
||||||
"A debug function for development (will be removed).") {
|
"A debug function for development (will be removed).") {
|
||||||
|
|
||||||
DEBUG_BREAK();
|
DEBUG_BREAK();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
DEF(stdLangWrite,
|
DEF(stdLangWrite,
|
||||||
"write(...) -> null\n"
|
"write(...) -> null\n"
|
||||||
@ -1080,7 +1082,8 @@ Var varAdd(PKVM* vm, Var v1, Var v2) {
|
|||||||
case OBJ_SCRIPT:
|
case OBJ_SCRIPT:
|
||||||
case OBJ_FUNC:
|
case OBJ_FUNC:
|
||||||
case OBJ_FIBER:
|
case OBJ_FIBER:
|
||||||
case OBJ_USER:
|
case OBJ_CLASS:
|
||||||
|
case OBJ_INST:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1339,6 +1342,7 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
|||||||
// map = { "foo" : 42, "can't access" : 32 }
|
// map = { "foo" : 42, "can't access" : 32 }
|
||||||
// val = map.foo ## 42
|
// val = map.foo ## 42
|
||||||
TODO;
|
TODO;
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
case OBJ_RANGE:
|
case OBJ_RANGE:
|
||||||
@ -1371,8 +1375,15 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
|||||||
{
|
{
|
||||||
Script* scr = (Script*)obj;
|
Script* scr = (Script*)obj;
|
||||||
|
|
||||||
|
// Search in types.
|
||||||
|
int index = scriptGetClass(scr, attrib->data, attrib->length);
|
||||||
|
if (index != -1) {
|
||||||
|
ASSERT_INDEX((uint32_t)index, scr->classes.count);
|
||||||
|
return VAR_OBJ(scr->classes.data[index]);
|
||||||
|
}
|
||||||
|
|
||||||
// Search in functions.
|
// Search in functions.
|
||||||
int index = scriptGetFunc(scr, attrib->data, attrib->length);
|
index = scriptGetFunc(scr, attrib->data, attrib->length);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
ASSERT_INDEX((uint32_t)index, scr->functions.count);
|
ASSERT_INDEX((uint32_t)index, scr->functions.count);
|
||||||
return VAR_OBJ(scr->functions.data[index]);
|
return VAR_OBJ(scr->functions.data[index]);
|
||||||
@ -1408,8 +1419,38 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case OBJ_FIBER:
|
case OBJ_FIBER:
|
||||||
case OBJ_USER:
|
|
||||||
TODO;
|
TODO;
|
||||||
|
UNREACHABLE();
|
||||||
|
|
||||||
|
case OBJ_CLASS:
|
||||||
|
TODO;
|
||||||
|
UNREACHABLE();
|
||||||
|
|
||||||
|
case OBJ_INST:
|
||||||
|
{
|
||||||
|
Instance* inst = (Instance*)obj;
|
||||||
|
if (inst->is_native) {
|
||||||
|
TODO;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// TODO: Optimize this with binary search.
|
||||||
|
Class* ty = inst->ins->type;
|
||||||
|
for (uint32_t i = 0; i < ty->field_names.count; i++) {
|
||||||
|
ASSERT_INDEX(i, ty->field_names.count);
|
||||||
|
ASSERT_INDEX(ty->field_names.data[i], ty->owner->names.count);
|
||||||
|
String* f_name = ty->owner->names.data[ty->field_names.data[i]];
|
||||||
|
if (f_name->hash == attrib->hash &&
|
||||||
|
f_name->length == attrib->length &&
|
||||||
|
memcmp(f_name->data, attrib->data, attrib->length) == 0) {
|
||||||
|
return inst->ins->fields.data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_NO_ATTRIB(vm, on, attrib);
|
||||||
|
return VAR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -1485,6 +1526,15 @@ do { \
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
index = scriptGetClass(scr, attrib->data, attrib->length);
|
||||||
|
if (index != -1) {
|
||||||
|
ASSERT_INDEX((uint32_t)index, scr->classes.count);
|
||||||
|
ASSERT_INDEX(scr->classes.data[index]->name, scr->names.count);
|
||||||
|
String* name = scr->names.data[scr->classes.data[index]->name];
|
||||||
|
ATTRIB_IMMUTABLE(name->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ERR_NO_ATTRIB(vm, on, attrib);
|
ERR_NO_ATTRIB(vm, on, attrib);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1499,10 +1549,39 @@ do { \
|
|||||||
ERR_NO_ATTRIB(vm, on, attrib);
|
ERR_NO_ATTRIB(vm, on, attrib);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case OBJ_USER:
|
case OBJ_CLASS:
|
||||||
TODO; //ERR_NO_ATTRIB(vm, on, attrib);
|
ERR_NO_ATTRIB(vm, on, attrib);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case OBJ_INST:
|
||||||
|
{
|
||||||
|
Instance* inst = (Instance*)obj;
|
||||||
|
if (inst->is_native) {
|
||||||
|
TODO;
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// TODO: Optimize this with binary search.
|
||||||
|
Class* ty = inst->ins->type;
|
||||||
|
for (uint32_t i = 0; i < ty->field_names.count; i++) {
|
||||||
|
ASSERT_INDEX(i, ty->field_names.count);
|
||||||
|
ASSERT_INDEX(ty->field_names.data[i], ty->owner->names.count);
|
||||||
|
String* f_name = ty->owner->names.data[ty->field_names.data[i]];
|
||||||
|
if (f_name->hash == attrib->hash &&
|
||||||
|
f_name->length == attrib->length &&
|
||||||
|
memcmp(f_name->data, attrib->data, attrib->length) == 0) {
|
||||||
|
inst->ins->fields.data[i] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ERR_NO_ATTRIB(vm, on, attrib);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
@ -1574,8 +1653,11 @@ Var varGetSubscript(PKVM* vm, Var on, Var key) {
|
|||||||
case OBJ_SCRIPT:
|
case OBJ_SCRIPT:
|
||||||
case OBJ_FUNC:
|
case OBJ_FUNC:
|
||||||
case OBJ_FIBER:
|
case OBJ_FIBER:
|
||||||
case OBJ_USER:
|
case OBJ_CLASS:
|
||||||
|
case OBJ_INST:
|
||||||
TODO;
|
TODO;
|
||||||
|
UNREACHABLE();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
@ -1621,8 +1703,11 @@ void varsetSubscript(PKVM* vm, Var on, Var key, Var value) {
|
|||||||
case OBJ_SCRIPT:
|
case OBJ_SCRIPT:
|
||||||
case OBJ_FUNC:
|
case OBJ_FUNC:
|
||||||
case OBJ_FIBER:
|
case OBJ_FIBER:
|
||||||
case OBJ_USER:
|
case OBJ_CLASS:
|
||||||
|
case OBJ_INST:
|
||||||
TODO;
|
TODO;
|
||||||
|
UNREACHABLE();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ void dumpFunctionCode(PKVM* vm, Function* func, pkByteBuffer* buff) {
|
|||||||
const char* op_name = op_names[opcodes[i]];
|
const char* op_name = op_names[opcodes[i]];
|
||||||
uint32_t op_length = (uint32_t)strlen(op_name);
|
uint32_t op_length = (uint32_t)strlen(op_name);
|
||||||
pkByteBufferAddString(buff, vm, op_name, op_length);
|
pkByteBufferAddString(buff, vm, op_name, op_length);
|
||||||
for (uint32_t i = 0; i < 16 - op_length; i++) { // Padding.
|
for (uint32_t j = 0; j < 16 - op_length; j++) { // Padding.
|
||||||
ADD_CHAR(vm, buff, ' ');
|
ADD_CHAR(vm, buff, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,9 +125,25 @@ void dumpFunctionCode(PKVM* vm, Function* func, pkByteBuffer* buff) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_PUSH_LIST: SHORT_ARG(); break;
|
case OP_PUSH_LIST: SHORT_ARG(); break;
|
||||||
|
case OP_PUSH_INSTANCE:
|
||||||
|
{
|
||||||
|
int ty_index = READ_BYTE();
|
||||||
|
ASSERT_INDEX((uint32_t)ty_index, func->owner->classes.count);
|
||||||
|
uint32_t name_ind = func->owner->classes.data[ty_index]->name;
|
||||||
|
ASSERT_INDEX(name_ind, func->owner->names.count);
|
||||||
|
String* ty_name = func->owner->names.data[name_ind];
|
||||||
|
|
||||||
|
// Prints: %5d [Ty:%s]\n
|
||||||
|
ADD_INTEGER(vm, buff, ty_index, INT_WIDTH);
|
||||||
|
pkByteBufferAddString(buff, vm, STR_AND_LEN(" [Ty:"));
|
||||||
|
pkByteBufferAddString(buff, vm, ty_name->data, ty_name->length);
|
||||||
|
pkByteBufferAddString(buff, vm, STR_AND_LEN("]\n"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
case OP_PUSH_MAP: NO_ARGS(); break;
|
case OP_PUSH_MAP: NO_ARGS(); break;
|
||||||
case OP_LIST_APPEND: NO_ARGS(); break;
|
case OP_LIST_APPEND: NO_ARGS(); break;
|
||||||
case OP_MAP_INSERT: NO_ARGS(); break;
|
case OP_MAP_INSERT: NO_ARGS(); break;
|
||||||
|
case OP_INST_APPEND: NO_ARGS(); break;
|
||||||
|
|
||||||
case OP_PUSH_LOCAL_0:
|
case OP_PUSH_LOCAL_0:
|
||||||
case OP_PUSH_LOCAL_1:
|
case OP_PUSH_LOCAL_1:
|
||||||
@ -148,7 +164,7 @@ void dumpFunctionCode(PKVM* vm, Function* func, pkByteBuffer* buff) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
arg = (int)(op - OP_PUSH_LOCAL_0);
|
arg = (int)(op - OP_PUSH_LOCAL_0);
|
||||||
for (int i = 0; i < INT_WIDTH; i++) ADD_CHAR(vm, buff, ' ');
|
for (int j = 0; j < INT_WIDTH; j++) ADD_CHAR(vm, buff, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg < func->arity) {
|
if (arg < func->arity) {
|
||||||
@ -181,7 +197,7 @@ void dumpFunctionCode(PKVM* vm, Function* func, pkByteBuffer* buff) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
arg = (int)(op - OP_STORE_LOCAL_0);
|
arg = (int)(op - OP_STORE_LOCAL_0);
|
||||||
for (int i = 0; i < INT_WIDTH; i++) ADD_CHAR(vm, buff, ' ');
|
for (int j = 0; j < INT_WIDTH; j++) ADD_CHAR(vm, buff, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg < func->arity) {
|
if (arg < func->arity) {
|
||||||
@ -224,6 +240,23 @@ void dumpFunctionCode(PKVM* vm, Function* func, pkByteBuffer* buff) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OP_PUSH_TYPE:
|
||||||
|
{
|
||||||
|
int ty_index = READ_BYTE();
|
||||||
|
ASSERT_INDEX((uint32_t)ty_index, func->owner->classes.count);
|
||||||
|
uint32_t name_ind = func->owner->classes.data[ty_index]->name;
|
||||||
|
ASSERT_INDEX(name_ind, func->owner->names.count);
|
||||||
|
String* ty_name = func->owner->names.data[name_ind];
|
||||||
|
|
||||||
|
// Prints: %5d [Ty:%s]\n
|
||||||
|
ADD_INTEGER(vm, buff, ty_index, INT_WIDTH);
|
||||||
|
pkByteBufferAddString(buff, vm, STR_AND_LEN(" [Ty:"));
|
||||||
|
pkByteBufferAddString(buff, vm, ty_name->data, ty_name->length);
|
||||||
|
pkByteBufferAddString(buff, vm, STR_AND_LEN("]\n"));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OP_PUSH_BUILTIN_FN:
|
case OP_PUSH_BUILTIN_FN:
|
||||||
{
|
{
|
||||||
int index = READ_BYTE();
|
int index = READ_BYTE();
|
||||||
|
@ -39,6 +39,10 @@ OPCODE(PUSH_LIST, 2, 1)
|
|||||||
// Push a new map to construct from literal.
|
// Push a new map to construct from literal.
|
||||||
OPCODE(PUSH_MAP, 0, 1)
|
OPCODE(PUSH_MAP, 0, 1)
|
||||||
|
|
||||||
|
// Push a new instance to the stack.
|
||||||
|
// param: 1 byte index.
|
||||||
|
OPCODE(PUSH_INSTANCE, 1, 1)
|
||||||
|
|
||||||
// Pop the value on the stack the next stack top would be a list. Append the
|
// Pop the value on the stack the next stack top would be a list. Append the
|
||||||
// value to the list. Used in literal array construction.
|
// value to the list. Used in literal array construction.
|
||||||
OPCODE(LIST_APPEND, 0, -1)
|
OPCODE(LIST_APPEND, 0, -1)
|
||||||
@ -47,6 +51,10 @@ OPCODE(LIST_APPEND, 0, -1)
|
|||||||
// Insert the key value pairs to the map. Used in literal map construction.
|
// Insert the key value pairs to the map. Used in literal map construction.
|
||||||
OPCODE(MAP_INSERT, 0, -2)
|
OPCODE(MAP_INSERT, 0, -2)
|
||||||
|
|
||||||
|
// Pop the value on the stack, the next stack top would be an instance. Append
|
||||||
|
// the value to the instance. Used in instance construction.
|
||||||
|
OPCODE(INST_APPEND, 0, -1)
|
||||||
|
|
||||||
// Push stack local on top of the stack. Locals at 0 to 8 marked explicitly
|
// Push stack local on top of the stack. Locals at 0 to 8 marked explicitly
|
||||||
// since it's performance critical.
|
// since it's performance critical.
|
||||||
// params: PUSH_LOCAL_N -> 1 byte count value.
|
// params: PUSH_LOCAL_N -> 1 byte count value.
|
||||||
@ -89,6 +97,10 @@ OPCODE(STORE_GLOBAL, 1, 0)
|
|||||||
// params: 1 byte index.
|
// params: 1 byte index.
|
||||||
OPCODE(PUSH_FN, 1, 1)
|
OPCODE(PUSH_FN, 1, 1)
|
||||||
|
|
||||||
|
// Push the script's type on the stack.
|
||||||
|
// params: 1 byte index
|
||||||
|
OPCODE(PUSH_TYPE, 1, 1)
|
||||||
|
|
||||||
// Push a built in function.
|
// Push a built in function.
|
||||||
// params: 1 bytes index.
|
// params: 1 bytes index.
|
||||||
OPCODE(PUSH_BUILTIN_FN, 1, 1)
|
OPCODE(PUSH_BUILTIN_FN, 1, 1)
|
||||||
|
208
src/pk_var.c
208
src/pk_var.c
@ -34,7 +34,8 @@ PkVarType pkGetValueType(const PkVar value) {
|
|||||||
case OBJ_SCRIPT: return PK_SCRIPT;
|
case OBJ_SCRIPT: return PK_SCRIPT;
|
||||||
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_USER: TODO; break;
|
case OBJ_CLASS: return PK_CLASS;
|
||||||
|
case OBJ_INST: return PK_INST;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -83,6 +84,7 @@ DEFINE_BUFFER(Byte, uint8_t)
|
|||||||
DEFINE_BUFFER(Var, Var)
|
DEFINE_BUFFER(Var, Var)
|
||||||
DEFINE_BUFFER(String, String*)
|
DEFINE_BUFFER(String, String*)
|
||||||
DEFINE_BUFFER(Function, Function*)
|
DEFINE_BUFFER(Function, Function*)
|
||||||
|
DEFINE_BUFFER(Class, Class*)
|
||||||
|
|
||||||
void pkByteBufferAddString(pkByteBuffer* self, PKVM* vm, const char* str,
|
void pkByteBufferAddString(pkByteBuffer* self, PKVM* vm, const char* str,
|
||||||
uint32_t length) {
|
uint32_t length) {
|
||||||
@ -138,6 +140,7 @@ void markVarBuffer(PKVM* vm, pkVarBuffer* self) {
|
|||||||
|
|
||||||
MARK_OBJ_BUFFER(String)
|
MARK_OBJ_BUFFER(String)
|
||||||
MARK_OBJ_BUFFER(Function)
|
MARK_OBJ_BUFFER(Function)
|
||||||
|
MARK_OBJ_BUFFER(Class)
|
||||||
|
|
||||||
#undef MARK_OBJ_BUFFER
|
#undef MARK_OBJ_BUFFER
|
||||||
|
|
||||||
@ -192,6 +195,9 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
|||||||
markFunctionBuffer(vm, &scr->functions);
|
markFunctionBuffer(vm, &scr->functions);
|
||||||
vm->bytes_allocated += sizeof(Function*) * scr->functions.capacity;
|
vm->bytes_allocated += sizeof(Function*) * scr->functions.capacity;
|
||||||
|
|
||||||
|
markClassBuffer(vm, &scr->classes);
|
||||||
|
vm->bytes_allocated += sizeof(Class*) * scr->classes.count;
|
||||||
|
|
||||||
markStringBuffer(vm, &scr->names);
|
markStringBuffer(vm, &scr->names);
|
||||||
vm->bytes_allocated += sizeof(String*) * scr->names.capacity;
|
vm->bytes_allocated += sizeof(String*) * scr->names.capacity;
|
||||||
|
|
||||||
@ -207,8 +213,10 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
|||||||
|
|
||||||
if (!func->is_native) {
|
if (!func->is_native) {
|
||||||
Fn* fn = func->fn;
|
Fn* fn = func->fn;
|
||||||
|
vm->bytes_allocated += sizeof(Fn);
|
||||||
|
|
||||||
vm->bytes_allocated += sizeof(uint8_t)* fn->opcodes.capacity;
|
vm->bytes_allocated += sizeof(uint8_t)* fn->opcodes.capacity;
|
||||||
vm->bytes_allocated += sizeof(int) * fn->oplines.capacity;
|
vm->bytes_allocated += sizeof(uint32_t) * fn->oplines.capacity;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -237,9 +245,24 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
|||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OBJ_USER:
|
case OBJ_CLASS:
|
||||||
TODO;
|
{
|
||||||
break;
|
Class* type = (Class*)obj;
|
||||||
|
vm->bytes_allocated += sizeof(Class);
|
||||||
|
markObject(vm, &type->owner->_super);
|
||||||
|
markObject(vm, &type->ctor->_super);
|
||||||
|
vm->bytes_allocated += sizeof(uint32_t) * type->field_names.capacity;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OBJ_INST:
|
||||||
|
{
|
||||||
|
Instance* inst = (Instance*)obj;
|
||||||
|
if (!inst->is_native) {
|
||||||
|
Inst* ins = inst->ins;
|
||||||
|
vm->bytes_allocated += sizeof(Inst);
|
||||||
|
vm->bytes_allocated += sizeof(Var*) * ins->fields.capacity;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,6 +352,7 @@ Script* newScript(PKVM* vm, String* path) {
|
|||||||
pkUintBufferInit(&script->global_names);
|
pkUintBufferInit(&script->global_names);
|
||||||
pkVarBufferInit(&script->literals);
|
pkVarBufferInit(&script->literals);
|
||||||
pkFunctionBufferInit(&script->functions);
|
pkFunctionBufferInit(&script->functions);
|
||||||
|
pkClassBufferInit(&script->classes);
|
||||||
pkStringBufferInit(&script->names);
|
pkStringBufferInit(&script->names);
|
||||||
|
|
||||||
vmPushTempRef(vm, &script->_super);
|
vmPushTempRef(vm, &script->_super);
|
||||||
@ -434,6 +458,59 @@ Fiber* newFiber(PKVM* vm, Function* fn) {
|
|||||||
return fiber;
|
return fiber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Class* newClass(PKVM* vm, Script* scr, const char* name, uint32_t length) {
|
||||||
|
Class* type = ALLOCATE(vm, Class);
|
||||||
|
varInitObject(&type->_super, vm, OBJ_CLASS);
|
||||||
|
|
||||||
|
vmPushTempRef(vm, &type->_super); // type.
|
||||||
|
|
||||||
|
pkClassBufferWrite(&scr->classes, vm, type);
|
||||||
|
type->owner = scr;
|
||||||
|
type->name = scriptAddName(scr, vm, name, length);
|
||||||
|
pkUintBufferInit(&type->field_names);
|
||||||
|
|
||||||
|
// Can't use '$' in string format. (TODO)
|
||||||
|
String* ty_name = scr->names.data[type->name];
|
||||||
|
String* dollar = newStringLength(vm, "$", 1);
|
||||||
|
vmPushTempRef(vm, &dollar->_super); // dollar
|
||||||
|
String* ctor_name = stringFormat(vm, "@(Ctor:@)", dollar, ty_name);
|
||||||
|
vmPopTempRef(vm); // dollar
|
||||||
|
|
||||||
|
// Constructor.
|
||||||
|
vmPushTempRef(vm, &ctor_name->_super); // ctor_name
|
||||||
|
type->ctor = newFunction(vm, ctor_name->data, ctor_name->length,
|
||||||
|
scr, false, NULL);
|
||||||
|
vmPopTempRef(vm); // ctor_name
|
||||||
|
|
||||||
|
vmPopTempRef(vm); // type.
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instance* newInstance(PKVM* vm, Class* ty, bool initialize) {
|
||||||
|
|
||||||
|
Instance* inst = ALLOCATE(vm, Instance);
|
||||||
|
varInitObject(&inst->_super, vm, OBJ_INST);
|
||||||
|
|
||||||
|
vmPushTempRef(vm, &inst->_super); // inst.
|
||||||
|
|
||||||
|
ASSERT(ty->name < ty->owner->names.count, OOPS);
|
||||||
|
inst->name = ty->owner->names.data[ty->name]->data;
|
||||||
|
inst->is_native = false;
|
||||||
|
|
||||||
|
Inst* ins = ALLOCATE(vm, Inst);
|
||||||
|
inst->ins = ins;
|
||||||
|
ins->type = ty;
|
||||||
|
pkVarBufferInit(&ins->fields);
|
||||||
|
|
||||||
|
if (initialize && ty->field_names.count != 0) {
|
||||||
|
pkVarBufferFill(&ins->fields, vm, VAR_NULL, ty->field_names.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
vmPopTempRef(vm); // inst.
|
||||||
|
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
|
||||||
List* rangeAsList(PKVM* vm, Range* self) {
|
List* rangeAsList(PKVM* vm, Range* self) {
|
||||||
List* list;
|
List* list;
|
||||||
if (self->from < self->to) {
|
if (self->from < self->to) {
|
||||||
@ -678,8 +755,10 @@ static uint32_t _hashObject(Object* obj) {
|
|||||||
case OBJ_SCRIPT:
|
case OBJ_SCRIPT:
|
||||||
case OBJ_FUNC:
|
case OBJ_FUNC:
|
||||||
case OBJ_FIBER:
|
case OBJ_FIBER:
|
||||||
case OBJ_USER:
|
case OBJ_CLASS:
|
||||||
|
case OBJ_INST:
|
||||||
TODO;
|
TODO;
|
||||||
|
UNREACHABLE();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
L_unhashable:
|
L_unhashable:
|
||||||
@ -898,6 +977,7 @@ void freeObject(PKVM* vm, Object* self) {
|
|||||||
pkUintBufferClear(&scr->global_names, vm);
|
pkUintBufferClear(&scr->global_names, vm);
|
||||||
pkVarBufferClear(&scr->literals, vm);
|
pkVarBufferClear(&scr->literals, vm);
|
||||||
pkFunctionBufferClear(&scr->functions, vm);
|
pkFunctionBufferClear(&scr->functions, vm);
|
||||||
|
pkClassBufferClear(&scr->classes, vm);
|
||||||
pkStringBufferClear(&scr->names, vm);
|
pkStringBufferClear(&scr->names, vm);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -906,6 +986,7 @@ void freeObject(PKVM* vm, Object* self) {
|
|||||||
if (!func->is_native) {
|
if (!func->is_native) {
|
||||||
pkByteBufferClear(&func->fn->opcodes, vm);
|
pkByteBufferClear(&func->fn->opcodes, vm);
|
||||||
pkUintBufferClear(&func->fn->oplines, vm);
|
pkUintBufferClear(&func->fn->oplines, vm);
|
||||||
|
DEALLOCATE(vm, func->fn);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -915,10 +996,27 @@ void freeObject(PKVM* vm, Object* self) {
|
|||||||
DEALLOCATE(vm, fiber->frames);
|
DEALLOCATE(vm, fiber->frames);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OBJ_USER:
|
case OBJ_CLASS: {
|
||||||
TODO; // Remove OBJ_USER.
|
Class* type = (Class*)self;
|
||||||
|
pkUintBufferClear(&type->field_names, vm);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OBJ_INST:
|
||||||
|
{
|
||||||
|
Instance* inst = (Instance*)self;
|
||||||
|
|
||||||
|
if (inst->is_native) {
|
||||||
|
TODO;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Inst* ins = inst->ins;
|
||||||
|
pkVarBufferClear(&ins->fields, vm);
|
||||||
|
DEALLOCATE(vm, ins);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DEALLOCATE(vm, self);
|
DEALLOCATE(vm, self);
|
||||||
}
|
}
|
||||||
@ -943,23 +1041,36 @@ uint32_t scriptAddName(Script* self, PKVM* vm, const char* name,
|
|||||||
return self->names.count - 1;
|
return self->names.count - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t scriptGetFunc(Script* script, const char* name, uint32_t length) {
|
int scriptGetClass(Script* script, const char* name, uint32_t length) {
|
||||||
for (uint32_t i = 0; i < script->functions.count; i++) {
|
for (uint32_t i = 0; i < script->classes.count; i++) {
|
||||||
const char* fn_name = script->functions.data[i]->name;
|
uint32_t name_ind = script->classes.data[i]->name;
|
||||||
uint32_t fn_length = (uint32_t)strlen(fn_name);
|
ASSERT(name_ind < script->names.count, OOPS);
|
||||||
if (fn_length == length && strncmp(fn_name, name, length) == 0) {
|
String* ty_name = script->names.data[name_ind];
|
||||||
return i;
|
if (ty_name->length == length &&
|
||||||
|
strncmp(ty_name->data, name, length) == 0) {
|
||||||
|
return (int)i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t scriptGetGlobals(Script* script, const char* name, uint32_t length) {
|
int scriptGetFunc(Script* script, const char* name, uint32_t length) {
|
||||||
|
for (uint32_t i = 0; i < script->functions.count; i++) {
|
||||||
|
const char* fn_name = script->functions.data[i]->name;
|
||||||
|
uint32_t fn_length = (uint32_t)strlen(fn_name);
|
||||||
|
if (fn_length == length && strncmp(fn_name, name, length) == 0) {
|
||||||
|
return (int)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scriptGetGlobals(Script* script, const char* name, uint32_t length) {
|
||||||
for (uint32_t i = 0; i < script->global_names.count; i++) {
|
for (uint32_t i = 0; i < script->global_names.count; i++) {
|
||||||
uint32_t name_index = script->global_names.data[i];
|
uint32_t name_index = script->global_names.data[i];
|
||||||
String* g_name = script->names.data[name_index];
|
String* g_name = script->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 i;
|
return (int)i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
@ -970,9 +1081,9 @@ uint32_t scriptAddGlobal(PKVM* vm, Script* script,
|
|||||||
Var value) {
|
Var value) {
|
||||||
|
|
||||||
// If already exists update the value.
|
// If already exists update the value.
|
||||||
uint32_t var_ind = scriptGetGlobals(script, name, length);
|
int var_ind = scriptGetGlobals(script, name, length);
|
||||||
if (var_ind != -1) {
|
if (var_ind != -1) {
|
||||||
ASSERT(var_ind < script->globals.count, OOPS);
|
ASSERT(var_ind < (int)script->globals.count, OOPS);
|
||||||
script->globals.data[var_ind] = value;
|
script->globals.data[var_ind] = value;
|
||||||
return var_ind;
|
return var_ind;
|
||||||
}
|
}
|
||||||
@ -985,13 +1096,15 @@ uint32_t scriptAddGlobal(PKVM* vm, Script* script,
|
|||||||
return script->globals.count - 1;
|
return script->globals.count - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility functions //////////////////////////////////////////////////////////
|
/*****************************************************************************/
|
||||||
|
/* UTILITY FUNCTIONS */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
const char* getPkVarTypeName(PkVarType type) {
|
const char* getPkVarTypeName(PkVarType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PK_NULL: return "null";
|
case PK_NULL: return "Null";
|
||||||
case PK_BOOL: return "bool";
|
case PK_BOOL: return "Bool";
|
||||||
case PK_NUMBER: return "number";
|
case PK_NUMBER: return "Number";
|
||||||
case PK_STRING: return "String";
|
case PK_STRING: return "String";
|
||||||
case PK_LIST: return "List";
|
case PK_LIST: return "List";
|
||||||
case PK_MAP: return "Map";
|
case PK_MAP: return "Map";
|
||||||
@ -999,6 +1112,8 @@ const char* getPkVarTypeName(PkVarType type) {
|
|||||||
case PK_SCRIPT: return "Script";
|
case PK_SCRIPT: return "Script";
|
||||||
case PK_FUNCTION: return "Function";
|
case PK_FUNCTION: return "Function";
|
||||||
case PK_FIBER: return "Fiber";
|
case PK_FIBER: return "Fiber";
|
||||||
|
case PK_CLASS: return "Class";
|
||||||
|
case PK_INST: return "Inst";
|
||||||
}
|
}
|
||||||
|
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -1013,15 +1128,16 @@ const char* getObjectTypeName(ObjectType type) {
|
|||||||
case OBJ_SCRIPT: return "Script";
|
case OBJ_SCRIPT: return "Script";
|
||||||
case OBJ_FUNC: return "Func";
|
case OBJ_FUNC: return "Func";
|
||||||
case OBJ_FIBER: return "Fiber";
|
case OBJ_FIBER: return "Fiber";
|
||||||
case OBJ_USER: return "UserObj";
|
case OBJ_CLASS: return "Class";
|
||||||
|
case OBJ_INST: return "Inst";
|
||||||
}
|
}
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* varTypeName(Var v) {
|
const char* varTypeName(Var v) {
|
||||||
if (IS_NULL(v)) return "null";
|
if (IS_NULL(v)) return "Null";
|
||||||
if (IS_BOOL(v)) return "bool";
|
if (IS_BOOL(v)) return "Bool";
|
||||||
if (IS_NUM(v)) return "number";
|
if (IS_NUM(v)) return "Number";
|
||||||
|
|
||||||
ASSERT(IS_OBJ(v), OOPS);
|
ASSERT(IS_OBJ(v), OOPS);
|
||||||
Object* obj = AS_OBJ(v);
|
Object* obj = AS_OBJ(v);
|
||||||
@ -1299,9 +1415,40 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OBJ_USER: {
|
case OBJ_CLASS: {
|
||||||
// TODO:
|
const Class* ty = (const Class*)obj;
|
||||||
pkByteBufferAddString(buff, vm, "[UserObj]", 9);
|
pkByteBufferAddString(buff, vm, "[Class:", 7);
|
||||||
|
String* ty_name = ty->owner->names.data[ty->name];
|
||||||
|
pkByteBufferAddString(buff, vm, ty_name->data, ty_name->length);
|
||||||
|
pkByteBufferWrite(buff, vm, ']');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OBJ_INST:
|
||||||
|
{
|
||||||
|
const Instance* inst = (const Instance*)obj;
|
||||||
|
pkByteBufferWrite(buff, vm, '[');
|
||||||
|
pkByteBufferAddString(buff, vm, inst->name,
|
||||||
|
(uint32_t)strlen(inst->name));
|
||||||
|
|
||||||
|
if (!inst->is_native) {
|
||||||
|
const Class* ty = inst->ins->type;
|
||||||
|
const Inst* ins = inst->ins;
|
||||||
|
ASSERT(ins->fields.count == ty->field_names.count, OOPS);
|
||||||
|
|
||||||
|
pkByteBufferWrite(buff, vm, ':');
|
||||||
|
for (uint32_t i = 0; i < ty->field_names.count; i++) {
|
||||||
|
if (i != 0) pkByteBufferWrite(buff, vm, ',');
|
||||||
|
|
||||||
|
pkByteBufferWrite(buff, vm, ' ');
|
||||||
|
String* f_name = ty->owner->names.data[ty->field_names.data[i]];
|
||||||
|
pkByteBufferAddString(buff, vm, f_name->data, f_name->length);
|
||||||
|
pkByteBufferWrite(buff, vm, '=');
|
||||||
|
_toStringInternal(vm, ins->fields.data[i], buff, outer, repr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pkByteBufferWrite(buff, vm, ']');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1351,7 +1498,8 @@ bool toBool(Var v) {
|
|||||||
case OBJ_SCRIPT:
|
case OBJ_SCRIPT:
|
||||||
case OBJ_FUNC:
|
case OBJ_FUNC:
|
||||||
case OBJ_FIBER:
|
case OBJ_FIBER:
|
||||||
case OBJ_USER:
|
case OBJ_CLASS:
|
||||||
|
case OBJ_INST:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
71
src/pk_var.h
71
src/pk_var.h
@ -187,6 +187,8 @@ typedef struct Range Range;
|
|||||||
typedef struct Script Script;
|
typedef struct Script Script;
|
||||||
typedef struct Function Function;
|
typedef struct Function Function;
|
||||||
typedef struct Fiber Fiber;
|
typedef struct Fiber Fiber;
|
||||||
|
typedef struct Class Class;
|
||||||
|
typedef struct Instance Instance;
|
||||||
|
|
||||||
// Declaration of buffer objects of different types.
|
// Declaration of buffer objects of different types.
|
||||||
DECLARE_BUFFER(Uint, uint32_t)
|
DECLARE_BUFFER(Uint, uint32_t)
|
||||||
@ -194,6 +196,7 @@ DECLARE_BUFFER(Byte, uint8_t)
|
|||||||
DECLARE_BUFFER(Var, Var)
|
DECLARE_BUFFER(Var, Var)
|
||||||
DECLARE_BUFFER(String, String*)
|
DECLARE_BUFFER(String, String*)
|
||||||
DECLARE_BUFFER(Function, Function*)
|
DECLARE_BUFFER(Function, Function*)
|
||||||
|
DECLARE_BUFFER(Class, Class*)
|
||||||
|
|
||||||
// Add all the characters to the buffer, byte buffer can also be used as a
|
// Add all the characters to the buffer, byte buffer can also be used as a
|
||||||
// buffer to write string (like a string stream). Note that this will not
|
// buffer to write string (like a string stream). Note that this will not
|
||||||
@ -209,16 +212,14 @@ typedef enum {
|
|||||||
OBJ_SCRIPT,
|
OBJ_SCRIPT,
|
||||||
OBJ_FUNC,
|
OBJ_FUNC,
|
||||||
OBJ_FIBER,
|
OBJ_FIBER,
|
||||||
// TODO:
|
OBJ_CLASS,
|
||||||
OBJ_USER,
|
OBJ_INST,
|
||||||
} ObjectType;
|
} ObjectType;
|
||||||
|
|
||||||
// Base struct for all heap allocated objects.
|
// Base struct for all heap allocated objects.
|
||||||
struct Object {
|
struct Object {
|
||||||
ObjectType type; //< Type of the object in \ref var_Object_Type.
|
ObjectType type; //< Type of the object in \ref var_Object_Type.
|
||||||
bool is_marked; //< Marked when garbage collection's marking phase.
|
bool is_marked; //< Marked when garbage collection's marking phase.
|
||||||
//Class* is; //< The class the object IS. // No OOP in PK.
|
|
||||||
|
|
||||||
Object* next; //< Next object in the heap allocated link list.
|
Object* next; //< Next object in the heap allocated link list.
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -269,24 +270,11 @@ struct Script {
|
|||||||
String* module; //< Module name of the script.
|
String* module; //< Module name of the script.
|
||||||
String* path; //< Path of the script.
|
String* path; //< Path of the script.
|
||||||
|
|
||||||
/*
|
|
||||||
names: ["v1", "fn1", "v2", "fn2", ...]
|
|
||||||
0 1 2 3
|
|
||||||
|
|
||||||
g_names: [ 1, 3 ] <-- function name
|
|
||||||
0 1 <-- it's index
|
|
||||||
|
|
||||||
globals: [ fn1, fn2 ]
|
|
||||||
0 1
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO: (maybe) join the function buffer and variable buffers.
|
|
||||||
// and make if possible to override functions. (also have to allow builtin).
|
|
||||||
|
|
||||||
pkVarBuffer globals; //< Script level global variables.
|
pkVarBuffer globals; //< Script level global variables.
|
||||||
pkUintBuffer global_names; //< Name map to index in globals.
|
pkUintBuffer global_names; //< Name map to index in globals.
|
||||||
|
|
||||||
pkFunctionBuffer functions; //< Script level functions.
|
pkFunctionBuffer functions; //< Functions of the script.
|
||||||
|
pkClassBuffer classes; //< Classes of the script.
|
||||||
|
|
||||||
pkStringBuffer names; //< Name literals, attribute names, etc.
|
pkStringBuffer names; //< Name literals, attribute names, etc.
|
||||||
pkVarBuffer literals; //< Script literal constant values.
|
pkVarBuffer literals; //< Script literal constant values.
|
||||||
@ -369,6 +357,33 @@ struct Fiber {
|
|||||||
String* error;
|
String* error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Class {
|
||||||
|
Object _super;
|
||||||
|
|
||||||
|
Script* owner; //< The script it belongs to.
|
||||||
|
uint32_t name; //< Index of the type's name in the script's name buffer.
|
||||||
|
|
||||||
|
Function* ctor; //< The constructor function.
|
||||||
|
pkUintBuffer field_names; //< Buffer of field names.
|
||||||
|
// TODO: ordered names buffer for binary search.
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Class* type; //< Class this instance belongs to.
|
||||||
|
pkVarBuffer fields; //< Var buffer of the instance.
|
||||||
|
} Inst;
|
||||||
|
|
||||||
|
struct Instance {
|
||||||
|
Object _super;
|
||||||
|
|
||||||
|
const char* name; //< Name of the type it belongs to.
|
||||||
|
bool is_native; //< True if it's a native type instance.
|
||||||
|
union {
|
||||||
|
void* native; //< C struct pointer. // TODO:
|
||||||
|
Inst* ins; //< Module instance pointer.
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* "CONSTRUCTORS" */
|
/* "CONSTRUCTORS" */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -392,7 +407,7 @@ String* newStringLength(PKVM* vm, const char* text, uint32_t length);
|
|||||||
#else // Macro implementation.
|
#else // Macro implementation.
|
||||||
// Allocate new string using the cstring [text].
|
// Allocate new string using the cstring [text].
|
||||||
#define newString(vm, text) \
|
#define newString(vm, text) \
|
||||||
newStringLength(vm, text, (text == NULL) ? 0 : (uint32_t)strlen(text))
|
newStringLength(vm, text, (!text) ? 0 : (uint32_t)strlen(text))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Allocate new List and return List*.
|
// Allocate new List and return List*.
|
||||||
@ -419,6 +434,14 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner,
|
|||||||
// Allocate new Fiber object around the function [fn] and return Fiber*.
|
// Allocate new Fiber object around the function [fn] and return Fiber*.
|
||||||
Fiber* newFiber(PKVM* vm, Function* fn);
|
Fiber* newFiber(PKVM* vm, Function* fn);
|
||||||
|
|
||||||
|
// Allocate new Class object and return Class* with name [name].
|
||||||
|
Class* newClass(PKVM* vm, Script* scr, const char* name, uint32_t length);
|
||||||
|
|
||||||
|
// Allocate new instance with of the base [type]. Note that if [initialize] is
|
||||||
|
// false, the field value buffer of the instance would be un initialized (ie.
|
||||||
|
// the buffer count = 0). Otherwise they'll be set to VAR_NULL.
|
||||||
|
Instance* newInstance(PKVM* vm, Class* ty, bool initialize);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* METHODS */
|
/* METHODS */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -520,13 +543,17 @@ bool fiberHasError(Fiber* fiber);
|
|||||||
uint32_t scriptAddName(Script* self, PKVM* vm, const char* name,
|
uint32_t scriptAddName(Script* self, PKVM* vm, const char* name,
|
||||||
uint32_t length);
|
uint32_t length);
|
||||||
|
|
||||||
|
// Search for the type name in the script and return it's index in it's
|
||||||
|
// [classes] buffer. If not found returns -1.
|
||||||
|
int scriptGetClass(Script* script, const char* name, uint32_t length);
|
||||||
|
|
||||||
// Search for the function name in the script and return it's index in it's
|
// Search for the function name in the script and return it's index in it's
|
||||||
// [functions] buffer. If not found returns -1.
|
// [functions] buffer. If not found returns -1.
|
||||||
uint32_t scriptGetFunc(Script* script, const char* name, uint32_t length);
|
int scriptGetFunc(Script* script, const char* name, uint32_t length);
|
||||||
|
|
||||||
// Search for the global variable name in the script and return it's index in
|
// Search for the global variable name in the script and return it's index in
|
||||||
// it's [globals] buffer. If not found returns -1.
|
// it's [globals] buffer. If not found returns -1.
|
||||||
uint32_t scriptGetGlobals(Script* script, const char* name, uint32_t length);
|
int scriptGetGlobals(Script* script, const char* name, uint32_t length);
|
||||||
|
|
||||||
// Add a global [value] to the [scrpt] and return its index.
|
// Add a global [value] to the [scrpt] and return its index.
|
||||||
uint32_t scriptAddGlobal(PKVM* vm, Script* script,
|
uint32_t scriptAddGlobal(PKVM* vm, Script* script,
|
||||||
|
68
src/pk_vm.c
68
src/pk_vm.c
@ -755,6 +755,15 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OPCODE(PUSH_INSTANCE):
|
||||||
|
{
|
||||||
|
uint8_t index = READ_BYTE();
|
||||||
|
ASSERT_INDEX(index, script->classes.count);
|
||||||
|
Instance* inst = newInstance(vm, script->classes.data[index], false);
|
||||||
|
PUSH(VAR_OBJ(inst));
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE(LIST_APPEND):
|
OPCODE(LIST_APPEND):
|
||||||
{
|
{
|
||||||
Var elem = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
Var elem = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||||
@ -785,6 +794,21 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OPCODE(INST_APPEND):
|
||||||
|
{
|
||||||
|
Var value = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||||
|
Var inst = PEEK(-2);
|
||||||
|
ASSERT(IS_OBJ_TYPE(inst, OBJ_INST), OOPS);
|
||||||
|
|
||||||
|
Instance* inst_p = (Instance*)AS_OBJ(inst);
|
||||||
|
ASSERT(!inst_p->is_native, OOPS);
|
||||||
|
Inst* ins = inst_p->ins;
|
||||||
|
pkVarBufferWrite(&ins->fields, vm, value);
|
||||||
|
DROP(); // value
|
||||||
|
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE(PUSH_LOCAL_0):
|
OPCODE(PUSH_LOCAL_0):
|
||||||
OPCODE(PUSH_LOCAL_1):
|
OPCODE(PUSH_LOCAL_1):
|
||||||
OPCODE(PUSH_LOCAL_2):
|
OPCODE(PUSH_LOCAL_2):
|
||||||
@ -830,7 +854,7 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
|
|||||||
OPCODE(PUSH_GLOBAL):
|
OPCODE(PUSH_GLOBAL):
|
||||||
{
|
{
|
||||||
uint8_t index = READ_BYTE();
|
uint8_t index = READ_BYTE();
|
||||||
ASSERT(index < script->globals.count, OOPS);
|
ASSERT_INDEX(index, script->globals.count);
|
||||||
PUSH(script->globals.data[index]);
|
PUSH(script->globals.data[index]);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
@ -838,7 +862,7 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
|
|||||||
OPCODE(STORE_GLOBAL):
|
OPCODE(STORE_GLOBAL):
|
||||||
{
|
{
|
||||||
uint8_t index = READ_BYTE();
|
uint8_t index = READ_BYTE();
|
||||||
ASSERT(index < script->globals.count, OOPS);
|
ASSERT_INDEX(index, script->globals.count);
|
||||||
script->globals.data[index] = PEEK(-1);
|
script->globals.data[index] = PEEK(-1);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
@ -846,12 +870,21 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
|
|||||||
OPCODE(PUSH_FN):
|
OPCODE(PUSH_FN):
|
||||||
{
|
{
|
||||||
uint8_t index = READ_BYTE();
|
uint8_t index = READ_BYTE();
|
||||||
ASSERT(index < script->functions.count, OOPS);
|
ASSERT_INDEX(index, script->functions.count);
|
||||||
Function* fn = script->functions.data[index];
|
Function* fn = script->functions.data[index];
|
||||||
PUSH(VAR_OBJ(fn));
|
PUSH(VAR_OBJ(fn));
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OPCODE(PUSH_TYPE):
|
||||||
|
{
|
||||||
|
uint8_t index = READ_BYTE();
|
||||||
|
ASSERT_INDEX(index, script->classes.count);
|
||||||
|
Class* ty = script->classes.data[index];
|
||||||
|
PUSH(VAR_OBJ(ty));
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE(PUSH_BUILTIN_FN):
|
OPCODE(PUSH_BUILTIN_FN):
|
||||||
{
|
{
|
||||||
uint8_t index = READ_BYTE();
|
uint8_t index = READ_BYTE();
|
||||||
@ -890,8 +923,22 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
|
|||||||
Fiber* call_fiber = vm->fiber;
|
Fiber* call_fiber = vm->fiber;
|
||||||
Var* callable = call_fiber->sp - argc - 1;
|
Var* callable = call_fiber->sp - argc - 1;
|
||||||
|
|
||||||
|
const Function* fn = NULL;
|
||||||
|
|
||||||
if (IS_OBJ_TYPE(*callable, OBJ_FUNC)) {
|
if (IS_OBJ_TYPE(*callable, OBJ_FUNC)) {
|
||||||
const Function* fn = (const Function*)AS_OBJ(*callable);
|
fn = (const Function*)AS_OBJ(*callable);
|
||||||
|
|
||||||
|
} else if (IS_OBJ_TYPE(*callable, OBJ_CLASS)) {
|
||||||
|
fn = (const Function*)((Class*)AS_OBJ(*callable))->ctor;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
RUNTIME_ERROR(stringFormat(vm, "$ $(@).", "Expected a function in "
|
||||||
|
"call, instead got",
|
||||||
|
varTypeName(*callable), toString(vm, *callable)));
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reached here it's a valid callable.
|
||||||
|
|
||||||
// -1 argument means multiple number of args.
|
// -1 argument means multiple number of args.
|
||||||
if (fn->arity != -1 && fn->arity != argc) {
|
if (fn->arity != -1 && fn->arity != argc) {
|
||||||
@ -945,11 +992,6 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
RUNTIME_ERROR(stringFormat(vm, "$ $(@).", "Expected a function in "
|
|
||||||
"call, instead got", varTypeName(*callable), toString(vm, *callable)));
|
|
||||||
}
|
|
||||||
|
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1051,7 +1093,8 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
|
|||||||
case OBJ_SCRIPT:
|
case OBJ_SCRIPT:
|
||||||
case OBJ_FUNC:
|
case OBJ_FUNC:
|
||||||
case OBJ_FIBER:
|
case OBJ_FIBER:
|
||||||
case OBJ_USER:
|
case OBJ_CLASS:
|
||||||
|
case OBJ_INST:
|
||||||
TODO; break;
|
TODO; break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -1433,6 +1476,7 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
|
|||||||
OPCODE(IN):
|
OPCODE(IN):
|
||||||
// TODO: Implement bool varContaines(vm, on, value);
|
// TODO: Implement bool varContaines(vm, on, value);
|
||||||
TODO;
|
TODO;
|
||||||
|
UNREACHABLE();
|
||||||
|
|
||||||
OPCODE(REPL_PRINT):
|
OPCODE(REPL_PRINT):
|
||||||
{
|
{
|
||||||
@ -1447,7 +1491,7 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(END):
|
OPCODE(END):
|
||||||
TODO;
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1455,5 +1499,5 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return PK_RESULT_SUCCESS;
|
UNREACHABLE(); //return PK_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
36
tests/lang/class.pk
Normal file
36
tests/lang/class.pk
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
## TODO: Implement ctor with va arg to
|
||||||
|
## initialize, fields.
|
||||||
|
|
||||||
|
class _Vec
|
||||||
|
x = 0
|
||||||
|
y = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def Vec(x, y)
|
||||||
|
ret = _Vec()
|
||||||
|
ret.x = x; ret.y = y
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def vecAdd(v1, v2)
|
||||||
|
return Vec(v1.x + v2.x,
|
||||||
|
v1.y + v2.y)
|
||||||
|
end
|
||||||
|
|
||||||
|
v1 = Vec(1, 2); assert(v1.x == 1 and v1.y == 2)
|
||||||
|
v2 = Vec(3, 4); assert(v2.x == 3 and v2.y == 4)
|
||||||
|
|
||||||
|
v3 = vecAdd(v1, v2)
|
||||||
|
assert(v3.x == 4 and v3.y == 6)
|
||||||
|
|
||||||
|
class Test
|
||||||
|
fn = null
|
||||||
|
val = Vec(12, 32)
|
||||||
|
end
|
||||||
|
|
||||||
|
test = Test()
|
||||||
|
test.fn = to_string
|
||||||
|
res = test.fn(test.val)
|
||||||
|
assert(res == "[_Vec: x=12, y=32]")
|
||||||
|
|
@ -13,6 +13,10 @@ import "basics.pk" ## will import all
|
|||||||
import "controlflow.pk" as if_test
|
import "controlflow.pk" as if_test
|
||||||
from "functions.pk" import fn1, fn2 as f2, fn3
|
from "functions.pk" import fn1, fn2 as f2, fn3
|
||||||
|
|
||||||
|
import "class.pk" as class_
|
||||||
|
assert(class_.Vec(42, 3.14).y == 3.14)
|
||||||
|
(vec = class_._Vec()).x = 'a'; assert(vec.x == 'a')
|
||||||
|
|
||||||
## If it has a module name it'll bind to that name.
|
## If it has a module name it'll bind to that name.
|
||||||
import 'import/module.pk'
|
import 'import/module.pk'
|
||||||
assert(module_name.get_module_name() == 'module_name')
|
assert(module_name.get_module_name() == 'module_name')
|
||||||
|
@ -16,6 +16,7 @@ THIS_PATH = abspath(dirname(__file__))
|
|||||||
TEST_SUITE = {
|
TEST_SUITE = {
|
||||||
"Unit Tests": (
|
"Unit Tests": (
|
||||||
"lang/basics.pk",
|
"lang/basics.pk",
|
||||||
|
"lang/class.pk",
|
||||||
"lang/core.pk",
|
"lang/core.pk",
|
||||||
"lang/controlflow.pk",
|
"lang/controlflow.pk",
|
||||||
"lang/fibers.pk",
|
"lang/fibers.pk",
|
||||||
|
Loading…
Reference in New Issue
Block a user