mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 15:16:41 +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.
|
// 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.
|
||||||
|
@ -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);
|
||||||
|
@ -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 not os.path.isfile(join(root, file)): continue
|
|
||||||
if file.endswith('.c'):
|
if file.endswith('.c'):
|
||||||
source = fix_path(join(root, file))
|
source = fix_path(join(SRC_DIR, file))
|
||||||
sources.append(source)
|
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__':
|
||||||
|
@ -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 { \
|
||||||
|
@ -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.
|
||||||
|
75
src/core.c
75
src/core.c
@ -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;
|
||||||
|
78
src/debug.c
78
src/debug.c
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
19
src/var.c
19
src/var.c
@ -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.
|
||||||
|
43
src/vm.c
43
src/vm.c
@ -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
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
|
## 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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ set files=( ^
|
|||||||
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\fib.pk ^
|
||||||
examples\prime.pk ^
|
examples\prime.pk ^
|
||||||
|
Loading…
Reference in New Issue
Block a user