mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 07:00:58 +08:00
Merge pull request #22 from ThakeeNathees/chain-call-test
chain call implemented
This commit is contained in:
commit
bd41435519
@ -1,8 +1,14 @@
|
||||
|
||||
// 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.
|
||||
[ ] 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).
|
||||
Then remove vm's root script.
|
||||
@ -12,8 +18,8 @@
|
||||
[ ] Var handler implement.
|
||||
[ ] Make it possible to override function names.
|
||||
[ ] Hex, binary literals and floats like ".5".
|
||||
[ ] Function docstring property.
|
||||
[ ] Union tagging alter in var.
|
||||
[ ] Add a make file/and more? (not every one has scons).
|
||||
[ ] (future) add structs and maybe enums.
|
||||
|
||||
// Add more.
|
||||
|
@ -75,10 +75,10 @@ pkStringResult loadScript(PKVM* vm, const char* path) {
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
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"
|
||||
"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) {
|
||||
printf("%s\n%s", notice, help);
|
||||
|
@ -12,7 +12,7 @@ SRC_DIR = '../../src/'
|
||||
JS_API_PATH = './io_api.js'
|
||||
TARGET_DIR = '../static/'
|
||||
TARGET_NAME = 'pocketlang.html'
|
||||
JS_SCRIPT = 'try_now.js'
|
||||
PAGE_SCRIPT = 'try_now.js'
|
||||
|
||||
def main():
|
||||
sources = ' '.join(collect_source_files())
|
||||
@ -27,7 +27,7 @@ def main():
|
||||
print(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.
|
||||
|
||||
|
||||
@ -36,16 +36,11 @@ def fix_path(path):
|
||||
|
||||
def collect_source_files():
|
||||
sources = []
|
||||
|
||||
def add_all(root, sources):
|
||||
for file in os.listdir(root):
|
||||
if not os.path.isfile(join(root, file)): continue
|
||||
if file.endswith('.c'):
|
||||
source = fix_path(join(root, file))
|
||||
sources.append(source)
|
||||
|
||||
add_all(SRC_DIR, sources)
|
||||
add_all(join(SRC_DIR, 'buffers/'), sources)
|
||||
for file in os.listdir(SRC_DIR):
|
||||
if not os.path.isfile(join(SRC_DIR, file)): continue
|
||||
if file.endswith('.c'):
|
||||
source = fix_path(join(SRC_DIR, file))
|
||||
sources.append(source)
|
||||
return sources
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define BUFFERS_TEMPLATE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "pocketlang.h"
|
||||
#include "include/pocketlang.h"
|
||||
|
||||
#define DECLARE_BUFFER(M__NAME, M__NAME_L, M__TYPE) \
|
||||
typedef struct { \
|
||||
|
@ -62,6 +62,7 @@ typedef enum {
|
||||
TK_AMP, // &
|
||||
TK_PIPE, // |
|
||||
TK_CARET, // ^
|
||||
TK_ARROW, // ->
|
||||
|
||||
TK_PLUS, // +
|
||||
TK_MINUS, // -
|
||||
@ -221,6 +222,7 @@ typedef enum {
|
||||
PREC_TERM, // + -
|
||||
PREC_FACTOR, // * / %
|
||||
PREC_UNARY, // - ! ~
|
||||
PREC_CHAIN_CALL, // ->
|
||||
PREC_CALL, // ()
|
||||
PREC_SUBSCRIPT, // []
|
||||
PREC_ATTRIB, // .index
|
||||
@ -623,7 +625,13 @@ static void lexToken(Parser* parser) {
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
case '*':
|
||||
@ -892,6 +900,7 @@ static void exprName(Compiler* compiler, bool can_assign);
|
||||
static void exprOr(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 exprUnaryOp(Compiler* compiler, bool can_assign);
|
||||
|
||||
@ -930,6 +939,7 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence
|
||||
/* TK_AMP */ { NULL, exprBinaryOp, PREC_BITWISE_AND },
|
||||
/* TK_PIPE */ { NULL, exprBinaryOp, PREC_BITWISE_OR },
|
||||
/* TK_CARET */ { NULL, exprBinaryOp, PREC_BITWISE_XOR },
|
||||
/* TK_ARROW */ { NULL, exprChainCall, PREC_CHAIN_CALL },
|
||||
/* TK_PLUS */ { NULL, exprBinaryOp, PREC_TERM },
|
||||
/* TK_MINUS */ { exprUnaryOp, exprBinaryOp, PREC_TERM },
|
||||
/* 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) {
|
||||
Token* value = &compiler->parser.previous;
|
||||
int index = compilerAddConstant(compiler, value->value);
|
||||
emitOpcode(compiler, OP_CONSTANT);
|
||||
emitOpcode(compiler, OP_PUSH_CONSTANT);
|
||||
emitShort(compiler, index);
|
||||
}
|
||||
|
||||
@ -1161,6 +1171,30 @@ void exprAnd(Compiler* compiler, bool can_assign) {
|
||||
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) {
|
||||
TokenType op = compiler->parser.previous.type;
|
||||
skipNewLines(&compiler->parser);
|
||||
@ -1490,7 +1524,7 @@ static void emitOpcode(Compiler* compiler, Opcode opcode) {
|
||||
// make one.
|
||||
static void emitConstant(Compiler* compiler, Var value) {
|
||||
int index = compilerAddConstant(compiler, value);
|
||||
emitOpcode(compiler, OP_CONSTANT);
|
||||
emitOpcode(compiler, OP_PUSH_CONSTANT);
|
||||
emitShort(compiler, index);
|
||||
}
|
||||
|
||||
@ -1546,7 +1580,7 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) {
|
||||
}
|
||||
|
||||
} else {
|
||||
name = "[FunctionLiteral]";
|
||||
name = "$(LiteralFn)";
|
||||
name_length = (int)strlen(name);
|
||||
}
|
||||
|
||||
@ -1610,7 +1644,7 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) {
|
||||
compilerExitBlock(compiler); // Parameter depth.
|
||||
|
||||
#if DEBUG_DUMP_COMPILED_CODE
|
||||
dumpInstructions(compiler->vm, compiler->func->ptr);
|
||||
dumpFunctionCode(compiler->vm, compiler->func->ptr);
|
||||
#endif
|
||||
compiler->func = compiler->func->outer_func;
|
||||
|
||||
@ -2020,7 +2054,7 @@ bool compile(PKVM* vm, Script* script, const char* source) {
|
||||
vm->compiler = NULL;
|
||||
|
||||
#if DEBUG_DUMP_COMPILED_CODE
|
||||
dumpInstructions(vm, script->body);
|
||||
dumpFunctionCode(vm, script->body);
|
||||
#endif
|
||||
|
||||
// Return true if success.
|
||||
|
75
src/core.c
75
src/core.c
@ -5,9 +5,11 @@
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "var.h"
|
||||
#include "vm.h"
|
||||
|
||||
@ -84,6 +86,20 @@ static inline bool validateIndex(PKVM* vm, int32_t index, int32_t size,
|
||||
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 */
|
||||
/*****************************************************************************/
|
||||
@ -91,7 +107,7 @@ static inline bool validateIndex(PKVM* vm, int32_t index, int32_t size,
|
||||
// Argument getter (1 based).
|
||||
#define ARG(n) vm->fiber->ret[n]
|
||||
|
||||
// Convinent macro
|
||||
// Convinent macros.
|
||||
#define ARG1 ARG(1)
|
||||
#define ARG2 ARG(2)
|
||||
#define ARG3 ARG(3)
|
||||
@ -216,6 +232,49 @@ void corePrint(PKVM* vm) {
|
||||
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 */
|
||||
/*****************************************************************************/
|
||||
@ -303,6 +362,11 @@ void initializeCore(PKVM* vm) {
|
||||
INITALIZE_BUILTIN_FN("to_string", coreToString, 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.
|
||||
Script* std; // A temporary pointer to the current std script.
|
||||
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);
|
||||
if (IS_UNDEF(value)) {
|
||||
|
||||
String* key_str = toString(vm, key, true);
|
||||
|
||||
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);
|
||||
|
||||
return VAR_NULL;
|
||||
}
|
||||
return value;
|
||||
|
78
src/debug.c
78
src/debug.c
@ -16,7 +16,6 @@ static const char* op_name[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
static void _dumpValue(PKVM* vm, Var value, bool recursive) {
|
||||
if (IS_NULL(value)) {
|
||||
printf("null");
|
||||
@ -53,8 +52,22 @@ static void _dumpValue(PKVM* vm, Var value, bool recursive) {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
case OBJ_RANGE:
|
||||
{
|
||||
@ -64,10 +77,11 @@ static void _dumpValue(PKVM* vm, Var value, bool recursive) {
|
||||
}
|
||||
|
||||
case OBJ_SCRIPT:
|
||||
printf("[Script:%p]", obj);
|
||||
printf("[Script:%s]", ((Script*)obj)->name->data);
|
||||
return;
|
||||
|
||||
case OBJ_FUNC:
|
||||
printf("[Fn:%p]", obj);
|
||||
printf("[Fn:%s]", ((Function*)obj)->name);
|
||||
return;
|
||||
|
||||
case OBJ_FIBER:
|
||||
@ -84,8 +98,7 @@ void dumpValue(PKVM* vm, Var value) {
|
||||
_dumpValue(vm, value, false);
|
||||
}
|
||||
|
||||
void dumpInstructions(PKVM* vm, Function* func) {
|
||||
|
||||
void dumpFunctionCode(PKVM* vm, Function* func) {
|
||||
|
||||
uint32_t i = 0;
|
||||
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++];
|
||||
switch (op) {
|
||||
case OP_CONSTANT:
|
||||
case OP_PUSH_CONSTANT:
|
||||
{
|
||||
int index = READ_SHORT();
|
||||
printf("%5d ", index);
|
||||
@ -131,6 +144,7 @@ void dumpInstructions(PKVM* vm, Function* func) {
|
||||
case OP_PUSH_SELF:
|
||||
case OP_PUSH_TRUE:
|
||||
case OP_PUSH_FALSE:
|
||||
case OP_SWAP:
|
||||
NO_ARGS();
|
||||
break;
|
||||
|
||||
@ -174,9 +188,23 @@ void dumpInstructions(PKVM* vm, Function* func) {
|
||||
|
||||
case OP_PUSH_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;
|
||||
}
|
||||
|
||||
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:
|
||||
{
|
||||
@ -184,10 +212,15 @@ void dumpInstructions(PKVM* vm, Function* func) {
|
||||
printf("%5d [Fn:%s]\n", index, getBuiltinFunctionName(vm, index));
|
||||
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:
|
||||
printf("%5d (argc)\n", READ_SHORT());
|
||||
@ -237,8 +270,6 @@ void dumpInstructions(PKVM* vm, Function* func) {
|
||||
case OP_BIT_XOR:
|
||||
case OP_BIT_LSHIFT:
|
||||
case OP_BIT_RSHIFT:
|
||||
case OP_AND:
|
||||
case OP_OR:
|
||||
case OP_EQEQ:
|
||||
case OP_NOTEQ:
|
||||
case OP_LT:
|
||||
@ -258,19 +289,18 @@ void dumpInstructions(PKVM* vm, Function* func) {
|
||||
}
|
||||
}
|
||||
|
||||
void reportStackTrace(PKVM* vm) {
|
||||
if (vm->config.error_fn == NULL) return;
|
||||
|
||||
void dumpStackFrame(PKVM* vm) {
|
||||
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);
|
||||
|
||||
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);
|
||||
printf("Frame: %d.\n", frame_ind);
|
||||
for (; sp >= frame->rbp; sp--) {
|
||||
printf(" ");
|
||||
dumpValue(vm, *sp);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,9 +12,9 @@
|
||||
void dumpValue(PKVM* vm, Var value);
|
||||
|
||||
// Dump opcodes of the given function.
|
||||
void dumpInstructions(PKVM* vm, Function* func);
|
||||
void dumpFunctionCode(PKVM* vm, Function* func);
|
||||
|
||||
// Print stack track.
|
||||
void reportStackTrace(PKVM* vm);
|
||||
// Dump the current (top most) stack call frame.
|
||||
void dumpStackFrame(PKVM* vm);
|
||||
|
||||
#endif // DEBUG_H
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
// Load the constant at index [arg] from the script's literals.
|
||||
// params: 2 byte (uint16_t) index value.
|
||||
OPCODE(CONSTANT, 2, 1)
|
||||
OPCODE(PUSH_CONSTANT, 2, 1)
|
||||
|
||||
// Push null on the stack.
|
||||
OPCODE(PUSH_NULL, 0, 1)
|
||||
@ -29,6 +29,9 @@ OPCODE(PUSH_TRUE, 0, 1)
|
||||
// Push false on the stack.
|
||||
OPCODE(PUSH_FALSE, 0, 1)
|
||||
|
||||
// Swap the top 2 stack values.
|
||||
OPCODE(SWAP, 0, 0)
|
||||
|
||||
// Push a new list to construct from literal.
|
||||
// param: 2 bytes list size (defalt is 0).
|
||||
OPCODE(PUSH_LIST, 2, 1)
|
||||
@ -182,8 +185,6 @@ OPCODE(BIT_XOR, 0, -1)
|
||||
OPCODE(BIT_LSHIFT, 0, -1)
|
||||
OPCODE(BIT_RSHIFT, 0, -1)
|
||||
|
||||
OPCODE(AND, 0, -1)
|
||||
OPCODE(OR, 0, -1)
|
||||
OPCODE(EQEQ, 0, -1)
|
||||
OPCODE(NOTEQ, 0, -1)
|
||||
OPCODE(LT, 0, -1)
|
||||
|
19
src/var.c
19
src/var.c
@ -79,22 +79,23 @@ void grayValue(Var self, PKVM* vm) {
|
||||
}
|
||||
|
||||
void grayVarBuffer(VarBuffer* self, PKVM* vm) {
|
||||
if (self == NULL) return;
|
||||
for (uint32_t i = 0; i < self->count; i++) {
|
||||
grayValue(self->data[i], vm);
|
||||
}
|
||||
}
|
||||
|
||||
void grayStringBuffer(StringBuffer* self, PKVM* vm) {
|
||||
for (uint32_t i = 0; i < self->count; i++) {
|
||||
grayObject(&self->data[i]->_super, vm);
|
||||
#define GRAY_OBJ_BUFFER(m_name) \
|
||||
void gray##m_name##Buffer(m_name##Buffer* self, PKVM* 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) {
|
||||
for (uint32_t i = 0; i < self->count; i++) {
|
||||
grayObject(&self->data[i]->_super, vm);
|
||||
}
|
||||
}
|
||||
GRAY_OBJ_BUFFER(String)
|
||||
GRAY_OBJ_BUFFER(Function)
|
||||
|
||||
|
||||
static void blackenObject(Object* obj, PKVM* vm) {
|
||||
// TODO: trace here.
|
||||
|
43
src/vm.c
43
src/vm.c
@ -6,7 +6,7 @@
|
||||
#include "vm.h"
|
||||
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
//#include "debug.h" //< Wrap around debug macro.
|
||||
#include "utils.h"
|
||||
|
||||
#define HAS_ERROR() (vm->fiber->error != NULL)
|
||||
@ -375,10 +375,19 @@ void pkSetRuntimeError(PKVM* vm, const char* message) {
|
||||
|
||||
void vmReportError(PKVM* vm) {
|
||||
ASSERT(HAS_ERROR(), "runtimeError() should be called after an error.");
|
||||
|
||||
// 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.
|
||||
@ -530,7 +539,7 @@ PKInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
Opcode instruction;
|
||||
SWITCH(instruction) {
|
||||
|
||||
OPCODE(CONSTANT):
|
||||
OPCODE(PUSH_CONSTANT):
|
||||
{
|
||||
uint16_t index = READ_SHORT();
|
||||
ASSERT_INDEX(index, script->literals.count);
|
||||
@ -550,6 +559,16 @@ PKInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
PUSH(VAR_FALSE);
|
||||
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):
|
||||
{
|
||||
List* list = newList(vm, (uint32_t)READ_SHORT());
|
||||
@ -754,7 +773,6 @@ PKInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
|
||||
OPCODE(JUMP_IF):
|
||||
{
|
||||
Var cond = POP();
|
||||
@ -929,21 +947,6 @@ PKInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
OPCODE(BIT_XOR):
|
||||
OPCODE(BIT_LSHIFT):
|
||||
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) :
|
||||
{
|
||||
|
27
test/lang/chain_call.pk
Normal file
27
test/lang/chain_call.pk
Normal 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')
|
||||
|
||||
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
|
||||
## Testing import statement
|
||||
import os
|
||||
import os, path
|
||||
import os as o, path as p
|
||||
from os import clock
|
||||
from os import clock as c
|
||||
import lang
|
||||
import lang, path
|
||||
import lang as o, path as p
|
||||
from lang import clock
|
||||
from lang import clock as c
|
||||
from path import abspath, curdir
|
||||
from path import abspath as ap, curdir as cd
|
||||
|
@ -5,8 +5,10 @@ val = 0
|
||||
|
||||
a = false; b = true;
|
||||
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
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
@echo off
|
||||
|
||||
set files=( ^
|
||||
lang\basics.pk ^
|
||||
lang\import.pk ^
|
||||
lang\if.pk ^
|
||||
lang\logical.pk ^
|
||||
^
|
||||
examples\fib.pk ^
|
||||
examples\prime.pk ^
|
||||
set files=( ^
|
||||
lang\basics.pk ^
|
||||
lang\import.pk ^
|
||||
lang\if.pk ^
|
||||
lang\logical.pk ^
|
||||
lang\chain_call.pk ^
|
||||
^
|
||||
examples\fib.pk ^
|
||||
examples\prime.pk ^
|
||||
)
|
||||
|
||||
set errorlevel=0
|
||||
|
Loading…
Reference in New Issue
Block a user