Merge pull request #22 from ThakeeNathees/chain-call-test

chain call implemented
This commit is contained in:
Thakee Nathees 2021-05-16 15:07:52 +05:30
commit bd41435519
15 changed files with 267 additions and 100 deletions

View File

@ -1,8 +1,14 @@
// To implement. // To implement.
[ ] Single header for embedding.
[ ] Add a make file/and more? (not every one has scons).
[ ] Resolve function name (called before defined).
[ ] Relative file import. [ ] Relative file import.
[ ] Remove resolve path for the root module. [ ] Remove resolve path for the root module.
[ ] Global variable names (also update dumpFunctionCode after).
[ ] Implement fiber from script body and vm run fibers (not scripts). [ ] Implement fiber from script body and vm run fibers (not scripts).
Then remove vm's root script. Then remove vm's root script.
@ -12,8 +18,8 @@
[ ] Var handler implement. [ ] Var handler implement.
[ ] Make it possible to override function names. [ ] Make it possible to override function names.
[ ] Hex, binary literals and floats like ".5". [ ] Hex, binary literals and floats like ".5".
[ ] Function docstring property.
[ ] Union tagging alter in var. [ ] Union tagging alter in var.
[ ] Add a make file/and more? (not every one has scons).
[ ] (future) add structs and maybe enums. [ ] (future) add structs and maybe enums.
// Add more. // Add more.

View File

@ -75,10 +75,10 @@ pkStringResult loadScript(PKVM* vm, const char* path) {
int main(int argc, char** argv) { int main(int argc, char** argv) {
const char* notice = const char* notice =
"MiniScript " PK_VERSION_STRING " (https://github.com/ThakeeNathees/miniscript/)\n" "PocketLang " PK_VERSION_STRING " (https://github.com/ThakeeNathees/pocketlang/)\n"
"Copyright(c) 2020 - 2021 ThakeeNathees.\n" "Copyright(c) 2020 - 2021 ThakeeNathees.\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";
const char* help = "Usage: miniscript <source_path>\n"; const char* help = "Usage: pocketlang <source_path>\n";
if (argc < 2) { if (argc < 2) {
printf("%s\n%s", notice, help); printf("%s\n%s", notice, help);

View File

@ -12,7 +12,7 @@ SRC_DIR = '../../src/'
JS_API_PATH = './io_api.js' JS_API_PATH = './io_api.js'
TARGET_DIR = '../static/' TARGET_DIR = '../static/'
TARGET_NAME = 'pocketlang.html' TARGET_NAME = 'pocketlang.html'
JS_SCRIPT = 'try_now.js' PAGE_SCRIPT = 'try_now.js'
def main(): def main():
sources = ' '.join(collect_source_files()) sources = ' '.join(collect_source_files())
@ -27,7 +27,7 @@ def main():
print(cmd) print(cmd)
os.system(cmd) os.system(cmd)
shutil.copyfile(JS_SCRIPT, join(TARGET_DIR,JS_SCRIPT)) shutil.copyfile(PAGE_SCRIPT, join(TARGET_DIR,PAGE_SCRIPT))
os.remove(output) ## Not using the generated html file. os.remove(output) ## Not using the generated html file.
@ -36,16 +36,11 @@ def fix_path(path):
def collect_source_files(): def collect_source_files():
sources = [] sources = []
for file in os.listdir(SRC_DIR):
def add_all(root, sources): if not os.path.isfile(join(SRC_DIR, file)): continue
for file in os.listdir(root): if file.endswith('.c'):
if not os.path.isfile(join(root, file)): continue source = fix_path(join(SRC_DIR, file))
if file.endswith('.c'): sources.append(source)
source = fix_path(join(root, file))
sources.append(source)
add_all(SRC_DIR, sources)
add_all(join(SRC_DIR, 'buffers/'), sources)
return sources return sources
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -7,7 +7,7 @@
#define BUFFERS_TEMPLATE_H #define BUFFERS_TEMPLATE_H
#include "common.h" #include "common.h"
#include "pocketlang.h" #include "include/pocketlang.h"
#define DECLARE_BUFFER(M__NAME, M__NAME_L, M__TYPE) \ #define DECLARE_BUFFER(M__NAME, M__NAME_L, M__TYPE) \
typedef struct { \ typedef struct { \

View File

@ -62,6 +62,7 @@ typedef enum {
TK_AMP, // & TK_AMP, // &
TK_PIPE, // | TK_PIPE, // |
TK_CARET, // ^ TK_CARET, // ^
TK_ARROW, // ->
TK_PLUS, // + TK_PLUS, // +
TK_MINUS, // - TK_MINUS, // -
@ -221,6 +222,7 @@ typedef enum {
PREC_TERM, // + - PREC_TERM, // + -
PREC_FACTOR, // * / % PREC_FACTOR, // * / %
PREC_UNARY, // - ! ~ PREC_UNARY, // - ! ~
PREC_CHAIN_CALL, // ->
PREC_CALL, // () PREC_CALL, // ()
PREC_SUBSCRIPT, // [] PREC_SUBSCRIPT, // []
PREC_ATTRIB, // .index PREC_ATTRIB, // .index
@ -623,7 +625,13 @@ static void lexToken(Parser* parser) {
return; return;
case '-': case '-':
setNextTwoCharToken(parser, '=', TK_MINUS, TK_MINUSEQ); if (matchChar(parser, '=')) {
setNextToken(parser, TK_MINUSEQ); // '-='
} else if (matchChar(parser, '>')) {
setNextToken(parser, TK_ARROW); // '->'
} else {
setNextToken(parser, TK_MINUS); // '-'
}
return; return;
case '*': case '*':
@ -892,6 +900,7 @@ static void exprName(Compiler* compiler, bool can_assign);
static void exprOr(Compiler* compiler, bool can_assign); static void exprOr(Compiler* compiler, bool can_assign);
static void exprAnd(Compiler* compiler, bool can_assign); static void exprAnd(Compiler* compiler, bool can_assign);
static void exprChainCall(Compiler* compiler, bool can_assign);
static void exprBinaryOp(Compiler* compiler, bool can_assign); static void exprBinaryOp(Compiler* compiler, bool can_assign);
static void exprUnaryOp(Compiler* compiler, bool can_assign); static void exprUnaryOp(Compiler* compiler, bool can_assign);
@ -930,6 +939,7 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence
/* TK_AMP */ { NULL, exprBinaryOp, PREC_BITWISE_AND }, /* TK_AMP */ { NULL, exprBinaryOp, PREC_BITWISE_AND },
/* TK_PIPE */ { NULL, exprBinaryOp, PREC_BITWISE_OR }, /* TK_PIPE */ { NULL, exprBinaryOp, PREC_BITWISE_OR },
/* TK_CARET */ { NULL, exprBinaryOp, PREC_BITWISE_XOR }, /* TK_CARET */ { NULL, exprBinaryOp, PREC_BITWISE_XOR },
/* TK_ARROW */ { NULL, exprChainCall, PREC_CHAIN_CALL },
/* TK_PLUS */ { NULL, exprBinaryOp, PREC_TERM }, /* TK_PLUS */ { NULL, exprBinaryOp, PREC_TERM },
/* TK_MINUS */ { exprUnaryOp, exprBinaryOp, PREC_TERM }, /* TK_MINUS */ { exprUnaryOp, exprBinaryOp, PREC_TERM },
/* TK_STAR */ { NULL, exprBinaryOp, PREC_FACTOR }, /* TK_STAR */ { NULL, exprBinaryOp, PREC_FACTOR },
@ -1016,7 +1026,7 @@ static void emitPushVariable(Compiler* compiler, int index, bool global) {
static void exprLiteral(Compiler* compiler, bool can_assign) { static void exprLiteral(Compiler* compiler, bool can_assign) {
Token* value = &compiler->parser.previous; Token* value = &compiler->parser.previous;
int index = compilerAddConstant(compiler, value->value); int index = compilerAddConstant(compiler, value->value);
emitOpcode(compiler, OP_CONSTANT); emitOpcode(compiler, OP_PUSH_CONSTANT);
emitShort(compiler, index); emitShort(compiler, index);
} }
@ -1161,6 +1171,30 @@ void exprAnd(Compiler* compiler, bool can_assign) {
patchJump(compiler, end_offset); patchJump(compiler, end_offset);
} }
static void exprChainCall(Compiler* compiler, bool can_assign) {
skipNewLines(&compiler->parser);
parsePrecedence(compiler, (Precedence)(PREC_CHAIN_CALL + 1));
emitOpcode(compiler, OP_SWAP); // Swap the data with the function.
int argc = 1; // The initial data.
if (match(&compiler->parser, TK_LBRACE)) {
if (!match(&compiler->parser, TK_RBRACE)) {
do {
skipNewLines(&compiler->parser);
compileExpression(compiler);
skipNewLines(&compiler->parser);
argc++;
} while (match(&compiler->parser, TK_COMMA));
consume(&compiler->parser, TK_RBRACE, "Expected '}' after chain call"
"parameter list.");
}
}
emitOpcode(compiler, OP_CALL);
emitShort(compiler, argc);
}
static void exprBinaryOp(Compiler* compiler, bool can_assign) { static void exprBinaryOp(Compiler* compiler, bool can_assign) {
TokenType op = compiler->parser.previous.type; TokenType op = compiler->parser.previous.type;
skipNewLines(&compiler->parser); skipNewLines(&compiler->parser);
@ -1490,7 +1524,7 @@ static void emitOpcode(Compiler* compiler, Opcode opcode) {
// make one. // make one.
static void emitConstant(Compiler* compiler, Var value) { static void emitConstant(Compiler* compiler, Var value) {
int index = compilerAddConstant(compiler, value); int index = compilerAddConstant(compiler, value);
emitOpcode(compiler, OP_CONSTANT); emitOpcode(compiler, OP_PUSH_CONSTANT);
emitShort(compiler, index); emitShort(compiler, index);
} }
@ -1546,7 +1580,7 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) {
} }
} else { } else {
name = "[FunctionLiteral]"; name = "$(LiteralFn)";
name_length = (int)strlen(name); name_length = (int)strlen(name);
} }
@ -1610,7 +1644,7 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) {
compilerExitBlock(compiler); // Parameter depth. compilerExitBlock(compiler); // Parameter depth.
#if DEBUG_DUMP_COMPILED_CODE #if DEBUG_DUMP_COMPILED_CODE
dumpInstructions(compiler->vm, compiler->func->ptr); dumpFunctionCode(compiler->vm, compiler->func->ptr);
#endif #endif
compiler->func = compiler->func->outer_func; compiler->func = compiler->func->outer_func;
@ -2020,7 +2054,7 @@ bool compile(PKVM* vm, Script* script, const char* source) {
vm->compiler = NULL; vm->compiler = NULL;
#if DEBUG_DUMP_COMPILED_CODE #if DEBUG_DUMP_COMPILED_CODE
dumpInstructions(vm, script->body); dumpFunctionCode(vm, script->body);
#endif #endif
// Return true if success. // Return true if success.

View File

@ -5,9 +5,11 @@
#include "core.h" #include "core.h"
#include <ctype.h>
#include <math.h> #include <math.h>
#include <time.h> #include <time.h>
#include "utils.h"
#include "var.h" #include "var.h"
#include "vm.h" #include "vm.h"
@ -84,6 +86,20 @@ static inline bool validateIndex(PKVM* vm, int32_t index, int32_t size,
return true; return true;
} }
// Check if [var] is string for argument at [arg_ind]. If not set error and
// return false.
static bool validateArgString(PKVM* vm, Var var, String** value, int arg_ind) {
if (!IS_OBJ(var) || AS_OBJ(var)->type != OBJ_STRING) {
String* str_arg = toString(vm, VAR_NUM((double)arg_ind), false);
vmPushTempRef(vm, &str_arg->_super);
vm->fiber->error = stringFormat(vm, "Expected a string at argument @.",
str_arg, false);
vmPopTempRef(vm);
}
*value = (String*)AS_OBJ(var);
return true;
}
/*****************************************************************************/ /*****************************************************************************/
/* BUILTIN FUNCTIONS API */ /* BUILTIN FUNCTIONS API */
/*****************************************************************************/ /*****************************************************************************/
@ -91,7 +107,7 @@ static inline bool validateIndex(PKVM* vm, int32_t index, int32_t size,
// Argument getter (1 based). // Argument getter (1 based).
#define ARG(n) vm->fiber->ret[n] #define ARG(n) vm->fiber->ret[n]
// Convinent macro // Convinent macros.
#define ARG1 ARG(1) #define ARG1 ARG(1)
#define ARG2 ARG(2) #define ARG2 ARG(2)
#define ARG3 ARG(3) #define ARG3 ARG(3)
@ -216,6 +232,49 @@ void corePrint(PKVM* vm) {
vm->config.write_fn(vm, "\n"); vm->config.write_fn(vm, "\n");
} }
// string functions
// ----------------
void coreStrLower(PKVM* vm) {
String* str;
if (!validateArgString(vm, ARG1, &str, 1)) return;
String* result = newStringLength(vm, str->data, str->length);
char* data = result->data;
for (; *data; ++data) *data = tolower(*data);
// Since the string is modified re-hash it.
result->hash = utilHashString(result->data);
RET(VAR_OBJ(&result->_super));
}
void coreStrUpper(PKVM* vm) {
String* str;
if (!validateArgString(vm, ARG1, &str, 1)) return;
String* result = newStringLength(vm, str->data, str->length);
char* data = result->data;
for (; *data; ++data) *data = toupper(*data);
// Since the string is modified re-hash it.
result->hash = utilHashString(result->data);
RET(VAR_OBJ(&result->_super));
}
void coreStrStrip(PKVM* vm) {
String* str;
if (!validateArgString(vm, ARG1, &str, 1)) return;
const char* start = str->data;
while (*start && isspace(*start)) start++;
if (*start == '\0') RET(VAR_OBJ(&newStringLength(vm, NULL, 0)->_super));
const char* end = str->data + str->length - 1;
while (isspace(*end)) end--;
RET(VAR_OBJ(&newStringLength(vm, start, end - start + 1)->_super));
}
/*****************************************************************************/ /*****************************************************************************/
/* CORE LIBRARY METHODS */ /* CORE LIBRARY METHODS */
/*****************************************************************************/ /*****************************************************************************/
@ -303,6 +362,11 @@ void initializeCore(PKVM* vm) {
INITALIZE_BUILTIN_FN("to_string", coreToString, 1); INITALIZE_BUILTIN_FN("to_string", coreToString, 1);
INITALIZE_BUILTIN_FN("print", corePrint, -1); INITALIZE_BUILTIN_FN("print", corePrint, -1);
// string functions.
INITALIZE_BUILTIN_FN("str_lower", coreStrLower, 1);
INITALIZE_BUILTIN_FN("str_upper", coreStrUpper, 1);
INITALIZE_BUILTIN_FN("str_strip", coreStrStrip, 1);
// Make STD scripts. // Make STD scripts.
Script* std; // A temporary pointer to the current std script. Script* std; // A temporary pointer to the current std script.
Function* fn; // A temporary pointer to the allocated function function. Function* fn; // A temporary pointer to the allocated function function.
@ -671,12 +735,15 @@ Var varGetSubscript(PKVM* vm, Var on, Var key) {
{ {
Var value = mapGet((Map*)obj, key); Var value = mapGet((Map*)obj, key);
if (IS_UNDEF(value)) { if (IS_UNDEF(value)) {
String* key_str = toString(vm, key, true); String* key_str = toString(vm, key, true);
vmPushTempRef(vm, &key_str->_super); vmPushTempRef(vm, &key_str->_super);
vm->fiber->error = stringFormat(vm, "Key (@) not exists", key_str); if (IS_OBJ(key) && !isObjectHashable(AS_OBJ(key)->type)) {
vm->fiber->error = stringFormat(vm, "Invalid key '@'.", key_str);
} else {
vm->fiber->error = stringFormat(vm, "Key '@' not exists", key_str);
}
vmPopTempRef(vm); vmPopTempRef(vm);
return VAR_NULL; return VAR_NULL;
} }
return value; return value;

View File

@ -16,7 +16,6 @@ static const char* op_name[] = {
NULL, NULL,
}; };
static void _dumpValue(PKVM* vm, Var value, bool recursive) { static void _dumpValue(PKVM* vm, Var value, bool recursive) {
if (IS_NULL(value)) { if (IS_NULL(value)) {
printf("null"); printf("null");
@ -53,8 +52,22 @@ static void _dumpValue(PKVM* vm, Var value, bool recursive) {
} }
case OBJ_MAP: case OBJ_MAP:
TODO; {
Map* map = (Map*)obj;
if (recursive) {
printf("{...}");
} else {
printf("{");
for (uint32_t i = 0; i < map->count; i++) {
if (i != 0) printf(", ");
_dumpValue(vm, map->entries[i].key, true);
printf(":");
_dumpValue(vm, map->entries[i].value, true);
}
printf("}");
}
return; return;
}
case OBJ_RANGE: case OBJ_RANGE:
{ {
@ -64,10 +77,11 @@ static void _dumpValue(PKVM* vm, Var value, bool recursive) {
} }
case OBJ_SCRIPT: case OBJ_SCRIPT:
printf("[Script:%p]", obj); printf("[Script:%s]", ((Script*)obj)->name->data);
return; return;
case OBJ_FUNC: case OBJ_FUNC:
printf("[Fn:%p]", obj); printf("[Fn:%s]", ((Function*)obj)->name);
return; return;
case OBJ_FIBER: case OBJ_FIBER:
@ -84,8 +98,7 @@ void dumpValue(PKVM* vm, Var value) {
_dumpValue(vm, value, false); _dumpValue(vm, value, false);
} }
void dumpInstructions(PKVM* vm, Function* func) { void dumpFunctionCode(PKVM* vm, Function* func) {
uint32_t i = 0; uint32_t i = 0;
uint8_t* opcodes = func->fn->opcodes.data; uint8_t* opcodes = func->fn->opcodes.data;
@ -116,7 +129,7 @@ void dumpInstructions(PKVM* vm, Function* func) {
Opcode op = (Opcode)func->fn->opcodes.data[i++]; Opcode op = (Opcode)func->fn->opcodes.data[i++];
switch (op) { switch (op) {
case OP_CONSTANT: case OP_PUSH_CONSTANT:
{ {
int index = READ_SHORT(); int index = READ_SHORT();
printf("%5d ", index); printf("%5d ", index);
@ -131,6 +144,7 @@ void dumpInstructions(PKVM* vm, Function* func) {
case OP_PUSH_SELF: case OP_PUSH_SELF:
case OP_PUSH_TRUE: case OP_PUSH_TRUE:
case OP_PUSH_FALSE: case OP_PUSH_FALSE:
case OP_SWAP:
NO_ARGS(); NO_ARGS();
break; break;
@ -174,9 +188,23 @@ void dumpInstructions(PKVM* vm, Function* func) {
case OP_PUSH_GLOBAL: case OP_PUSH_GLOBAL:
case OP_STORE_GLOBAL: case OP_STORE_GLOBAL:
case OP_PUSH_FN: {
SHORT_ARG(); int index = READ_SHORT();
// TODO: name hasn't implemented yet.
//int name_index = func->owner->global_names.data[index];
//String* name = func->owner->names.data[name_index];
printf("%5d '%s'\n", index, "todo:name"/*name->data*/);
break; break;
}
case OP_PUSH_FN:
{
int fn_index = READ_SHORT();
int name_index = func->owner->function_names.data[fn_index];
String* name = func->owner->names.data[name_index];
printf("%5d [Fn:%s]\n", fn_index, name->data);
break;
}
case OP_PUSH_BUILTIN_FN: case OP_PUSH_BUILTIN_FN:
{ {
@ -185,9 +213,14 @@ void dumpInstructions(PKVM* vm, Function* func) {
break; break;
} }
case OP_POP: NO_ARGS(); break; case OP_POP: NO_ARGS(); break;
case OP_IMPORT: NO_ARGS(); break; case OP_IMPORT:
{
int index = READ_SHORT();
String* name = func->owner->names.data[index];
printf("%5d '%s'\n", index, name->data);
break;
}
case OP_CALL: case OP_CALL:
printf("%5d (argc)\n", READ_SHORT()); printf("%5d (argc)\n", READ_SHORT());
@ -237,8 +270,6 @@ void dumpInstructions(PKVM* vm, Function* func) {
case OP_BIT_XOR: case OP_BIT_XOR:
case OP_BIT_LSHIFT: case OP_BIT_LSHIFT:
case OP_BIT_RSHIFT: case OP_BIT_RSHIFT:
case OP_AND:
case OP_OR:
case OP_EQEQ: case OP_EQEQ:
case OP_NOTEQ: case OP_NOTEQ:
case OP_LT: case OP_LT:
@ -258,19 +289,18 @@ void dumpInstructions(PKVM* vm, Function* func) {
} }
} }
void reportStackTrace(PKVM* vm) { void dumpStackFrame(PKVM* vm) {
if (vm->config.error_fn == NULL) return;
Fiber* fiber = vm->fiber; Fiber* fiber = vm->fiber;
int frame_ind = fiber->frame_count - 1;
ASSERT(frame_ind >= 0, OOPS);
CallFrame* frame = &fiber->frames[frame_ind];
Var* sp = fiber->sp - 1;
vm->config.error_fn(vm, PK_ERROR_RUNTIME, NULL, -1, fiber->error->data); printf("Frame: %d.\n", frame_ind);
for (; sp >= frame->rbp; sp--) {
for (int i = fiber->frame_count - 1; i >= 0; i--) { printf(" ");
CallFrame* frame = &fiber->frames[i]; dumpValue(vm, *sp);
Function* fn = frame->fn; printf("\n");
ASSERT(!fn->is_native, OOPS);
int line = fn->fn->oplines.data[frame->ip - fn->fn->opcodes.data - 1];
vm->config.error_fn(vm, PK_ERROR_STACKTRACE, fn->owner->name->data, line, fn->name);
} }
} }

View File

@ -12,9 +12,9 @@
void dumpValue(PKVM* vm, Var value); void dumpValue(PKVM* vm, Var value);
// Dump opcodes of the given function. // Dump opcodes of the given function.
void dumpInstructions(PKVM* vm, Function* func); void dumpFunctionCode(PKVM* vm, Function* func);
// Print stack track. // Dump the current (top most) stack call frame.
void reportStackTrace(PKVM* vm); void dumpStackFrame(PKVM* vm);
#endif // DEBUG_H #endif // DEBUG_H

View File

@ -15,7 +15,7 @@
// Load the constant at index [arg] from the script's literals. // Load the constant at index [arg] from the script's literals.
// params: 2 byte (uint16_t) index value. // params: 2 byte (uint16_t) index value.
OPCODE(CONSTANT, 2, 1) OPCODE(PUSH_CONSTANT, 2, 1)
// Push null on the stack. // Push null on the stack.
OPCODE(PUSH_NULL, 0, 1) OPCODE(PUSH_NULL, 0, 1)
@ -29,6 +29,9 @@ OPCODE(PUSH_TRUE, 0, 1)
// Push false on the stack. // Push false on the stack.
OPCODE(PUSH_FALSE, 0, 1) OPCODE(PUSH_FALSE, 0, 1)
// Swap the top 2 stack values.
OPCODE(SWAP, 0, 0)
// Push a new list to construct from literal. // Push a new list to construct from literal.
// param: 2 bytes list size (defalt is 0). // param: 2 bytes list size (defalt is 0).
OPCODE(PUSH_LIST, 2, 1) OPCODE(PUSH_LIST, 2, 1)
@ -182,8 +185,6 @@ OPCODE(BIT_XOR, 0, -1)
OPCODE(BIT_LSHIFT, 0, -1) OPCODE(BIT_LSHIFT, 0, -1)
OPCODE(BIT_RSHIFT, 0, -1) OPCODE(BIT_RSHIFT, 0, -1)
OPCODE(AND, 0, -1)
OPCODE(OR, 0, -1)
OPCODE(EQEQ, 0, -1) OPCODE(EQEQ, 0, -1)
OPCODE(NOTEQ, 0, -1) OPCODE(NOTEQ, 0, -1)
OPCODE(LT, 0, -1) OPCODE(LT, 0, -1)

View File

@ -79,22 +79,23 @@ void grayValue(Var self, PKVM* vm) {
} }
void grayVarBuffer(VarBuffer* self, PKVM* vm) { void grayVarBuffer(VarBuffer* self, PKVM* vm) {
if (self == NULL) return;
for (uint32_t i = 0; i < self->count; i++) { for (uint32_t i = 0; i < self->count; i++) {
grayValue(self->data[i], vm); grayValue(self->data[i], vm);
} }
} }
void grayStringBuffer(StringBuffer* self, PKVM* vm) { #define GRAY_OBJ_BUFFER(m_name) \
for (uint32_t i = 0; i < self->count; i++) { void gray##m_name##Buffer(m_name##Buffer* self, PKVM* vm) { \
grayObject(&self->data[i]->_super, vm); if (self == NULL) return; \
for (uint32_t i = 0; i < self->count; i++) { \
grayObject(&self->data[i]->_super, vm); \
} \
} }
}
void grayFunctionBuffer(FunctionBuffer* self, PKVM* vm) { GRAY_OBJ_BUFFER(String)
for (uint32_t i = 0; i < self->count; i++) { GRAY_OBJ_BUFFER(Function)
grayObject(&self->data[i]->_super, vm);
}
}
static void blackenObject(Object* obj, PKVM* vm) { static void blackenObject(Object* obj, PKVM* vm) {
// TODO: trace here. // TODO: trace here.

View File

@ -6,7 +6,7 @@
#include "vm.h" #include "vm.h"
#include "core.h" #include "core.h"
#include "debug.h" //#include "debug.h" //< Wrap around debug macro.
#include "utils.h" #include "utils.h"
#define HAS_ERROR() (vm->fiber->error != NULL) #define HAS_ERROR() (vm->fiber->error != NULL)
@ -375,10 +375,19 @@ void pkSetRuntimeError(PKVM* vm, const char* message) {
void vmReportError(PKVM* vm) { void vmReportError(PKVM* vm) {
ASSERT(HAS_ERROR(), "runtimeError() should be called after an error."); ASSERT(HAS_ERROR(), "runtimeError() should be called after an error.");
// TODO: pass the error to the caller of the fiber. // TODO: pass the error to the caller of the fiber.
reportStackTrace(vm); // Print the Error message and stack trace.
if (vm->config.error_fn == NULL) return;
Fiber* fiber = vm->fiber;
vm->config.error_fn(vm, PK_ERROR_RUNTIME, NULL, -1, fiber->error->data);
for (int i = fiber->frame_count - 1; i >= 0; i--) {
CallFrame* frame = &fiber->frames[i];
Function* fn = frame->fn;
ASSERT(!fn->is_native, OOPS);
int line = fn->fn->oplines.data[frame->ip - fn->fn->opcodes.data - 1];
vm->config.error_fn(vm, PK_ERROR_STACKTRACE, fn->owner->name->data, line, fn->name);
}
} }
// FIXME: temp. // FIXME: temp.
@ -530,7 +539,7 @@ PKInterpretResult vmRunScript(PKVM* vm, Script* _script) {
Opcode instruction; Opcode instruction;
SWITCH(instruction) { SWITCH(instruction) {
OPCODE(CONSTANT): OPCODE(PUSH_CONSTANT):
{ {
uint16_t index = READ_SHORT(); uint16_t index = READ_SHORT();
ASSERT_INDEX(index, script->literals.count); ASSERT_INDEX(index, script->literals.count);
@ -550,6 +559,16 @@ PKInterpretResult vmRunScript(PKVM* vm, Script* _script) {
PUSH(VAR_FALSE); PUSH(VAR_FALSE);
DISPATCH(); DISPATCH();
OPCODE(SWAP):
{
Var top1 = *(vm->fiber->sp - 1);
Var top2 = *(vm->fiber->sp - 2);
*(vm->fiber->sp - 1) = top2;
*(vm->fiber->sp - 2) = top1;
DISPATCH();
}
OPCODE(PUSH_LIST): OPCODE(PUSH_LIST):
{ {
List* list = newList(vm, (uint32_t)READ_SHORT()); List* list = newList(vm, (uint32_t)READ_SHORT());
@ -754,7 +773,6 @@ PKInterpretResult vmRunScript(PKVM* vm, Script* _script) {
DISPATCH(); DISPATCH();
} }
OPCODE(JUMP_IF): OPCODE(JUMP_IF):
{ {
Var cond = POP(); Var cond = POP();
@ -929,21 +947,6 @@ PKInterpretResult vmRunScript(PKVM* vm, Script* _script) {
OPCODE(BIT_XOR): OPCODE(BIT_XOR):
OPCODE(BIT_LSHIFT): OPCODE(BIT_LSHIFT):
OPCODE(BIT_RSHIFT): OPCODE(BIT_RSHIFT):
OPCODE(AND):
TODO;
OPCODE(OR):
{
TODO;
// Python like or operator.
//Var v1 = POP(), v2 = POP();
//if (toBool(v1)) {
// PUSH(v1);
//} else {
// PUSH(v2);
//}
DISPATCH();
}
OPCODE(EQEQ) : OPCODE(EQEQ) :
{ {

27
test/lang/chain_call.pk Normal file
View File

@ -0,0 +1,27 @@
## Chain call tests.
# concatenative programming
def fn1(data)
return '[fn1:' + data + ']'
end
def fn2(data, suffix)
return '[fn2:' + data + '|' + suffix + ']'
end
def fn3(data)
return '[fn3:' + data + ']'
end
result = 'data' -> fn1 -> fn2{'suff'} -> fn3
## `result -> print` same as `print(result)`
assert(result == '[fn3:[fn2:[fn1:data]|suff]]')
result = ' tEST+InG ' -> str_strip -> str_lower
assert(result == 'test+ing')

View File

@ -1,9 +1,9 @@
## Testing import statement ## Testing import statement
import os import lang
import os, path import lang, path
import os as o, path as p import lang as o, path as p
from os import clock from lang import clock
from os import clock as c from lang import clock as c
from path import abspath, curdir from path import abspath, curdir
from path import abspath as ap, curdir as cd from path import abspath as ap, curdir as cd

View File

@ -5,8 +5,10 @@ val = 0
a = false; b = true; a = false; b = true;
if a and b then assert(false) end if a and b then assert(false) end
if a or b then va
else assert(false, '') end if a or b then val = 42
else assert(false) end
assert(val == 42)
get_true = func return true end get_true = func return true end

View File

@ -1,13 +1,14 @@
@echo off @echo off
set files=( ^ set files=( ^
lang\basics.pk ^ lang\basics.pk ^
lang\import.pk ^ lang\import.pk ^
lang\if.pk ^ lang\if.pk ^
lang\logical.pk ^ lang\logical.pk ^
^ lang\chain_call.pk ^
examples\fib.pk ^ ^
examples\prime.pk ^ examples\fib.pk ^
examples\prime.pk ^
) )
set errorlevel=0 set errorlevel=0