From f090089e4be8ac16cbe1c455347b1d4e335b531c Mon Sep 17 00:00:00 2001 From: Thakee Nathees Date: Mon, 15 Feb 2021 18:19:19 +0530 Subject: [PATCH 1/2] increment operators implemented --- include/miniscript.h | 2 +- src/compiler.c | 145 ++++++++++++++++++++++++++----------------- src/core.c | 45 +++++++++++++- src/core.h | 3 + src/var.c | 28 +++++++++ src/var.h | 3 + src/vm.c | 43 ++++++++++++- test/main.c | 29 ++++----- 8 files changed, 223 insertions(+), 75 deletions(-) diff --git a/include/miniscript.h b/include/miniscript.h index 5f7e59f..40d5fd5 100644 --- a/include/miniscript.h +++ b/include/miniscript.h @@ -78,7 +78,7 @@ typedef struct { } MSConfiguration; typedef enum { - RESULT_SUCCESS, + RESULT_SUCCESS = 0, RESULT_COMPILE_ERROR, RESULT_RUNTIME_ERROR, } MSInterpretResult; diff --git a/src/compiler.c b/src/compiler.c index a33af6f..d5fbc9c 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -5,6 +5,9 @@ #include "compiler.h" +#include +#include + #include "core.h" #include "types/name_table.h" #include "types/gen/byte_buffer.h" @@ -481,10 +484,10 @@ static void eatNumber(Parser* parser) { // Read and ignore chars till it reach new line or EOF. static void skipLineComment(Parser* parser) { - char c = eatChar(parser); - - while (c != '\n' && c != '\0') { - c = eatChar(parser); + char c; + while ((c = peekChar(parser)) != '\0') { + eatChar(parser); + if (c == '\n') return; } } @@ -680,6 +683,30 @@ static bool match(Parser* self, TokenType expected) { return true; } +// Consume the the current token and if it's not [expected] emits error log +// and continue parsing for more error logs. +static void consume(Parser* self, TokenType expected, const char* err_msg) { + //ASSERT(expected != TK_LINE, "Can't match TK_LINE."); + //matchLine(self); + + lexToken(self); + if (self->previous.type != expected) { + parseError(self, "%s", err_msg); + + // If the next token is expected discard the current to minimize + // cascaded errors and continue parsing. + if (peek(self) == expected) { + lexToken(self); + + } else { + // Skip the current line, to prevent multiple caseaded errors on the + // same line. + skipLineComment(self); + } + } +} + + // Match one or more lines and return true if there any. static bool matchLine(Parser* parser) { if (peek(parser) != TK_LINE) return false; @@ -688,17 +715,20 @@ static bool matchLine(Parser* parser) { return true; } -// Match semi collon or multiple new lines. -static void consumeEndStatement(Parser* parser) { - bool consumed = false; - - // Semi collon must be on the same line. - if (peek(parser) == TK_SEMICOLLON) { - match(parser, TK_SEMICOLLON); - consumed = true; +// Match semi collon, multiple new lines or peek 'end' keyword. +static bool matchEndStatement(Parser* parser) { + if (match(parser, TK_SEMICOLLON)) { + skipNewLines(parser); + return true; } - if (matchLine(parser)) consumed = true; - if (!consumed && peek(parser) != TK_EOF) { + + if (matchLine(parser) || peek(parser) == TK_END || peek(parser) == TK_EOF) + return true; +} + +// Consume semi collon, multiple new lines or peek 'end' keyword. +static void consumeEndStatement(Parser* parser) { + if (!matchEndStatement(parser)) { parseError(parser, "Expected statement end with newline or ';'."); } } @@ -719,22 +749,14 @@ static void consumeStartBlock(Parser* parser) { } } -// Consume the the current token and if it's not [expected] emits error log -// and continue parsing for more error logs. -static void consume(Parser* self, TokenType expected, const char* err_msg) { - //ASSERT(expected != TK_LINE, "Can't match TK_LINE."); - //matchLine(self); - - lexToken(self); - if (self->previous.type != expected) { - parseError(self, "%s", err_msg); - - // If the next token is expected discard the current to minimize - // cascaded errors and continue parsing. - if (peek(self) == expected) { - lexToken(self); - } - } +// Returns a optional compound assignment. +static bool matchAssignment(Parser* parser) { + if (match(parser, TK_EQ)) return true; + if (match(parser, TK_PLUSEQ)) return true; + if (match(parser, TK_MINUSEQ)) return true; + if (match(parser, TK_STAREQ)) return true; + if (match(parser, TK_DIVEQ)) return true; + return false; } /***************************************************************************** @@ -932,7 +954,7 @@ static GrammarRule* getRule(TokenType type) { } // Emit variable store. -static void _emitStoreVariable(Compiler* compiler, int index, bool global) { +static void emitStoreVariable(Compiler* compiler, int index, bool global) { if (global) { emitOpcode(compiler, OP_STORE_GLOBAL); emitShort(compiler, index); @@ -947,7 +969,7 @@ static void _emitStoreVariable(Compiler* compiler, int index, bool global) { } } -static void _emitPushVariable(Compiler* compiler, int index, bool global) { +static void emitPushVariable(Compiler* compiler, int index, bool global) { if (global) { emitOpcode(compiler, OP_PUSH_GLOBAL); emitShort(compiler, index); @@ -977,45 +999,56 @@ static void exprFunc(Compiler* compiler, bool can_assign) { // Local/global variables, script/native/builtin functions name. static void exprName(Compiler* compiler, bool can_assign) { - const char* name_start = compiler->parser.previous.start; - int name_len = compiler->parser.previous.length; - int name_line = compiler->parser.previous.line; + + Parser* parser = &compiler->parser; + + const char* name_start = parser->previous.start; + int name_len = parser->previous.length; + int name_line = parser->previous.line; NameSearchResult result = compilerSearchName(compiler, name_start, name_len); if (result.type == NAME_NOT_DEFINED) { - if (can_assign && match(&compiler->parser, TK_EQ)) { + if (can_assign && match(parser, TK_EQ)) { int index = compilerAddVariable(compiler, name_start, name_len, name_line); compileExpression(compiler); - _emitStoreVariable(compiler, index, compiler->scope_depth == DEPTH_GLOBAL); + emitStoreVariable(compiler, index, compiler->scope_depth == DEPTH_GLOBAL); return; } else { - parseError(&compiler->parser, "Name \"%.*s\" is not defined.", name_len, - name_start); + parseError(parser, "Name \"%.*s\" is not defined.", name_len, name_start); } } // TODO: can_assign and += -= etc. - switch (result.type) { case NAME_LOCAL_VAR: - if (can_assign && match(&compiler->parser, TK_EQ)) { - compileExpression(compiler); - _emitStoreVariable(compiler, result.index, false); - } else { - _emitPushVariable(compiler, result.index, false); - } - return; - case NAME_GLOBAL_VAR: - if (can_assign && match(&compiler->parser, TK_EQ)) { - compileExpression(compiler); - _emitStoreVariable(compiler, result.index, true); - + + if (can_assign && matchAssignment(parser)) { + TokenType assignment = parser->previous.type; + if (assignment != TK_EQ) { + emitPushVariable(compiler, result.index, result.type == NAME_GLOBAL_VAR); + compileExpression(compiler); + + switch (assignment) { + case TK_PLUSEQ: emitOpcode(compiler, OP_ADD); break; + case TK_MINUSEQ: emitOpcode(compiler, OP_SUBTRACT); break; + case TK_STAREQ: emitOpcode(compiler, OP_MULTIPLY); break; + case TK_DIVEQ: emitOpcode(compiler, OP_DIVIDE); break; + default: + UNREACHABLE(); + break; + + } + } else { + compileExpression(compiler); + } + + emitStoreVariable(compiler, result.index, result.type == NAME_GLOBAL_VAR); + } else { - emitOpcode(compiler, OP_PUSH_GLOBAL); - emitShort(compiler, result.index); + emitPushVariable(compiler, result.index, result.type == NAME_GLOBAL_VAR); } return; @@ -1345,7 +1378,7 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) { vmPushTempRef(compiler->vm, &func->_super); functionBufferWrite(&compiler->script->functions, compiler->vm, func); vmPopTempRef(compiler->vm); - int fn_index = compiler->script->functions.count - 1; + int fn_index = (int)compiler->script->functions.count - 1; Func curr_func; curr_func.outer_func = compiler->func; @@ -1574,7 +1607,7 @@ static void compileStatement(Compiler* compiler) { return; } - if (match(parser, TK_SEMICOLLON)|| match(parser, TK_LINE)) { + if (matchEndStatement(parser)) { emitOpcode(compiler, OP_PUSH_NULL); emitOpcode(compiler, OP_RETURN); } else { diff --git a/src/core.c b/src/core.c index c0d2fcc..8013689 100644 --- a/src/core.c +++ b/src/core.c @@ -6,6 +6,8 @@ #include "core.h" #include +#include + #include "vm.h" typedef struct { @@ -50,7 +52,7 @@ int findBuiltinFunction(const char* name, int length) { // Validators ///////////////////////////////////////////////////////////////// // Check if a numeric value bool/number and set [value]. -static bool isNumeric(Var var, double* value) { +static inline bool isNumeric(Var var, double* value) { if (IS_BOOL(var)) { *value = AS_BOOL(var); return true; @@ -170,6 +172,13 @@ void coreImport(MSVM* vm) { } } +// TODO: Temp function to benchmark. +void coreClock(MSVM* vm) { + RET(VAR_NUM((double)clock() / CLOCKS_PER_SEC)); +} + + + void initializeCore(MSVM* vm) { int i = 0; //< Iterate through builtins. @@ -191,6 +200,9 @@ void initializeCore(MSVM* vm) { initializeBuiltinFN(vm, &builtins[i++], "print", -1, corePrint); initializeBuiltinFN(vm, &builtins[i++], "import", 1, coreImport); + // FIXME: move this. temp for benchmarking. + initializeBuiltinFN(vm, &builtins[i++], "clock", 0, coreClock); + // Sentinal to mark the end of the array. initializeBuiltinFN(vm, &builtins[i], NULL, 0, NULL); @@ -213,7 +225,15 @@ Var varAdd(MSVM* vm, Var v1, Var v2) { } Var varSubtract(MSVM* vm, Var v1, Var v2) { - TODO; + double d1, d2; + if (isNumeric(v1, &d1)) { + if (validateNumeric(vm, v2, &d2, "Right operand")) { + return VAR_NUM(d1 - d2); + } + return VAR_NULL; + } + + TODO; //string addition/ array addition etc. return VAR_NULL; } @@ -236,6 +256,27 @@ Var varDivide(MSVM* vm, Var v1, Var v2) { return VAR_NULL; } +bool varGreater(Var v1, Var v2) { + + double d1, d2; + if (isNumeric(v1, &d1) && isNumeric(v2, &d2)) { + return d1 > d2; + } + + TODO; + return false; +} + +bool varLesser(Var v1, Var v2) { + double d1, d2; + if (isNumeric(v1, &d1) && isNumeric(v2, &d2)) { + return d1 < d2; + } + + TODO; + return false; +} + bool varIterate(MSVM* vm, Var seq, Var* iterator, Var* value) { #ifdef DEBUG diff --git a/src/core.h b/src/core.h index c347e24..5e15264 100644 --- a/src/core.h +++ b/src/core.h @@ -24,6 +24,9 @@ Var varSubtract(MSVM* vm, Var v1, Var v2); Var varMultiply(MSVM* vm, Var v1, Var v2); Var varDivide(MSVM* vm, Var v1, Var v2); +bool varGreater(Var v1, Var v2); +bool varLesser(Var v1, Var v2); + // Functions ////////////////////////////////////////////////////////////////// // Parameter [iterator] should be VAR_NULL before starting the iteration. diff --git a/src/var.c b/src/var.c index 8a4ee12..2df5e43 100644 --- a/src/var.c +++ b/src/var.c @@ -3,6 +3,8 @@ * Licensed under: MIT License */ +#include + #include "var.h" #include "vm.h" @@ -187,3 +189,29 @@ String* toString(MSVM* vm, Var v, bool recursive) { UNREACHABLE(); return NULL; } + +bool toBool(Var v) { + if (IS_BOOL(v)) return AS_BOOL(v); + if (IS_NULL(v)) return false; + if (IS_NUM(v)) { + return AS_NUM(v) != 0; + } + + ASSERT(IS_OBJ(v), OOPS); + Object* o = AS_OBJ(v); + switch (o->type) { + case OBJ_STRING: return ((String*)o)->length != 0; + + case OBJ_LIST: return ((List*)o)->elements.count != 0; + case OBJ_MAP: TODO; + case OBJ_RANGE: TODO; // Nout sure. + case OBJ_SCRIPT: // [[FALLTHROUGH]] + case OBJ_FUNC: + case OBJ_USER: + return true; + default: + UNREACHABLE(); + } + + return true; +} diff --git a/src/var.h b/src/var.h index c8b5b8e..eeb2820 100644 --- a/src/var.h +++ b/src/var.h @@ -303,4 +303,7 @@ bool isVauesSame(Var v1, Var v2); // It's an internal use (or may be I could make a wrapper around). String* toString(MSVM* vm, Var v, bool _recursive); +// Returns the truthy value of the var. +bool toBool(Var v); + #endif // VAR_H diff --git a/src/vm.c b/src/vm.c index ae51636..0507c9f 100644 --- a/src/vm.c +++ b/src/vm.c @@ -14,7 +14,7 @@ #define INITIAL_CALL_FRAMES 4 // Minimum size of the stack. -#define MIN_STACK_SIZE 16 +#define MIN_STACK_SIZE 128 void* vmRealloc(MSVM* self, void* memory, size_t old_size, size_t new_size) { @@ -57,6 +57,8 @@ void vmPopTempRef(MSVM* self) { * RUNTIME * *****************************************************************************/ +#ifdef DEBUG +#include // TODO: A function for quick debug. REMOVE. void _printStackTop(MSVM* vm) { if (vm->sp != vm->stack) { @@ -64,6 +66,7 @@ void _printStackTop(MSVM* vm) { printf("%s\n", toString(vm, v, false)->data); } } +#endif static void ensureStackSize(MSVM* vm, int size) { if (vm->stack_size > size) return; @@ -377,8 +380,24 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) { OPCODE(JUMP_IF): + { + Var cond = POP(); + int offset = READ_SHORT(); + if (toBool(cond)) { + ip += offset; + } + DISPATCH(); + } + OPCODE(JUMP_IF_NOT): - TODO; + { + Var cond = POP(); + int offset = READ_SHORT(); + if (!toBool(cond)) { + ip += offset; + } + DISPATCH(); + } OPCODE(RETURN): { @@ -419,6 +438,12 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) { } OPCODE(NOT): + { + Var val = POP(); + PUSH(VAR_BOOL(!toBool(val))); + DISPATCH(); + } + OPCODE(BIT_NOT): TODO; @@ -452,9 +477,23 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) { OPCODE(OR): OPCODE(EQEQ): OPCODE(NOTEQ): + TODO; + OPCODE(LT): + { + PUSH(VAR_BOOL(varLesser(POP(), POP()))); + DISPATCH(); + } + OPCODE(LTEQ): + TODO; + OPCODE(GT): + { + PUSH(VAR_BOOL(varGreater(POP(), POP()))); + DISPATCH(); + } + OPCODE(GTEQ): TODO; diff --git a/test/main.c b/test/main.c index d1c5ee3..b748d59 100644 --- a/test/main.c +++ b/test/main.c @@ -63,6 +63,19 @@ MSLoadScriptResult loadScript(MSVM* vm, const char* path) { int main(int argc, char** argv) { + const char* notice = + "MiniScript " MS_VERSION_STRING " (https://github.com/ThakeeNathees/miniscript/)\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 \n"; + + if (argc < 2) { + printf("%s\n%s", notice, help); + return 0; + } + + const char* source_path = argv[1]; + MSConfiguration config; config.error_fn = errorPrint; config.write_fn = writeFunction; @@ -70,19 +83,7 @@ int main(int argc, char** argv) { config.load_script_done_fn = loadScriptDone; MSVM* vm = msNewVM(&config); - MSInterpretResult result = msInterpret(vm, "build/test.ms"); + MSInterpretResult result = msInterpret(vm, source_path); - //Script* script = compileSource(vm, "../some/path/file.ms"); - //vmRunScript(vm, script); - // - //ByteBuffer* bytes = &script->body->fn->opcodes; - //for (int i = 0; i < bytes->count; i++) { - // const char* op = "(???)"; - // if (bytes->data[i] <= (int)OP_END) { - // op = opnames[bytes->data[i]]; - // } - // printf("%s %i\n", op, bytes->data[i]); - //} - - return 0; + return result; } From 6c88b99065b496b0fc5f883d62ef3bd7ed369071 Mon Sep 17 00:00:00 2001 From: Thakee Nathees Date: Tue, 16 Feb 2021 00:21:00 +0530 Subject: [PATCH 2/2] elif jump implemented --- src/compiler.c | 154 ++++++++++++++++++++------- src/core.c | 233 ++++++++++++++++++++++++++++++++++++----- src/core.h | 10 +- src/opcodes.h | 9 ++ src/types/name_table.c | 7 +- src/types/name_table.h | 4 +- src/var.c | 53 +++++++--- src/var.h | 9 +- src/vm.c | 70 ++++++++++++- src/vm.h | 14 +++ test/main.c | 10 -- 11 files changed, 475 insertions(+), 98 deletions(-) diff --git a/src/compiler.c b/src/compiler.c index d5fbc9c..03ca2d8 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -697,16 +697,10 @@ static void consume(Parser* self, TokenType expected, const char* err_msg) { // cascaded errors and continue parsing. if (peek(self) == expected) { lexToken(self); - - } else { - // Skip the current line, to prevent multiple caseaded errors on the - // same line. - skipLineComment(self); } } } - // Match one or more lines and return true if there any. static bool matchLine(Parser* parser) { if (peek(parser) != TK_LINE) return false; @@ -724,6 +718,7 @@ static bool matchEndStatement(Parser* parser) { if (matchLine(parser) || peek(parser) == TK_END || peek(parser) == TK_EOF) return true; + return false; } // Consume semi collon, multiple new lines or peek 'end' keyword. @@ -888,7 +883,7 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence /* TK_ERROR */ NO_RULE, /* TK_EOF */ NO_RULE, /* TK_LINE */ NO_RULE, - /* TK_DOT */ { exprAttrib, NULL, PREC_ATTRIB }, + /* TK_DOT */ { NULL, exprAttrib, PREC_ATTRIB }, /* TK_DOTDOT */ { NULL, exprBinaryOp, PREC_RANGE }, /* TK_COMMA */ NO_RULE, /* TK_COLLON */ NO_RULE, @@ -1159,9 +1154,10 @@ static void exprCall(Compiler* compiler, bool can_assign) { } static void exprAttrib(Compiler* compiler, bool can_assign) { - consume(&compiler->parser, TK_NAME, "Expected an attribute name after '.'."); - const char* name = compiler->parser.previous.start; - int length = compiler->parser.previous.length; + Parser* parser = &compiler->parser; + consume(parser, TK_NAME, "Expected an attribute name after '.'."); + const char* name = parser->previous.start; + int length = parser->previous.length; // Store the name in script's names. String* string = newString(compiler->vm, name, length); @@ -1171,9 +1167,27 @@ static void exprAttrib(Compiler* compiler, bool can_assign) { int index = (int)compiler->script->names.count - 1; - // TODO: +=, -=, ... - if (can_assign && match(&compiler->parser, TK_EQ)) { - compileExpression(compiler); + if (can_assign && matchAssignment(parser)) { + + TokenType assignment = parser->previous.type; + if (assignment != TK_EQ) { + emitOpcode(compiler, OP_GET_ATTRIB_AOP); + emitShort(compiler, index); + compileExpression(compiler); + + switch (assignment) { + case TK_PLUSEQ: emitOpcode(compiler, OP_ADD); break; + case TK_MINUSEQ: emitOpcode(compiler, OP_SUBTRACT); break; + case TK_STAREQ: emitOpcode(compiler, OP_MULTIPLY); break; + case TK_DIVEQ: emitOpcode(compiler, OP_DIVIDE); break; + default: + UNREACHABLE(); + break; + } + } else { + compileExpression(compiler); + } + emitOpcode(compiler, OP_SET_ATTRIB); emitShort(compiler, index); @@ -1183,7 +1197,37 @@ static void exprAttrib(Compiler* compiler, bool can_assign) { } } -static void exprSubscript(Compiler* compiler, bool can_assign) { TODO; } +static void exprSubscript(Compiler* compiler, bool can_assign) { + Parser* parser = &compiler->parser; + compileExpression(compiler); + consume(parser, TK_RBRACKET, "Expected ']' after subscription ends."); + + if (can_assign && matchAssignment(parser)) { + + TokenType assignment = parser->previous.type; + if (assignment != TK_EQ) { + emitOpcode(compiler, OP_GET_SUBSCRIPT_AOP); + compileExpression(compiler); + + switch (assignment) { + case TK_PLUSEQ: emitOpcode(compiler, OP_ADD); break; + case TK_MINUSEQ: emitOpcode(compiler, OP_SUBTRACT); break; + case TK_STAREQ: emitOpcode(compiler, OP_MULTIPLY); break; + case TK_DIVEQ: emitOpcode(compiler, OP_DIVIDE); break; + default: + UNREACHABLE(); + break; + } + } else { + compileExpression(compiler); + } + + emitOpcode(compiler, OP_SET_SUBSCRIPT); + + } else { + emitOpcode(compiler, OP_GET_SUBSCRIPT); + } +} static void exprValue(Compiler* compiler, bool can_assign) { TokenType op = compiler->parser.previous.type; @@ -1342,8 +1386,16 @@ static void emitLoopJump(Compiler* compiler) { * COMPILING (PARSE TOPLEVEL) * ****************************************************************************/ +typedef enum { + BLOCK_FUNC, + BLOCK_LOOP, + BLOCK_IF, + BLOCK_ELIF, + BLOCK_ELSE, +} BlockType; + static void compileStatement(Compiler* compiler); -static void compileBlockBody(Compiler* compiler, bool if_body); +static void compileBlockBody(Compiler* compiler, BlockType type); // Compile a function and return it's index in the script's function buffer. static int compileFunction(Compiler* compiler, FuncType fn_type) { @@ -1351,33 +1403,27 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) { Parser* parser = &compiler->parser; const char* name; + int name_length; if (fn_type != FN_LITERAL) { consume(parser, TK_NAME, "Expected a function name."); - const char* name_start = parser->previous.start; - int name_length = parser->previous.length; - NameSearchResult result = compilerSearchName(compiler, name_start, + name = parser->previous.start; + name_length = parser->previous.length; + NameSearchResult result = compilerSearchName(compiler, name, name_length); if (result.type != NAME_NOT_DEFINED) { parseError(&compiler->parser, "Name %.*s already exists.", name_length, - name_start); + name); // Not returning here as to complete for skip cascaded errors. } - int index = nameTableAdd(&compiler->script->function_names, compiler->vm, - name_start, name_length); - name = nameTableGet(&compiler->script->function_names, index); - } else { name = "[FunctionLiteral]"; + name_length = (int)strlen(name); } - Function* func = newFunction(compiler->vm, name, + Function* func = newFunction(compiler->vm, name, name_length, compiler->script, fn_type == FN_NATIVE); - - vmPushTempRef(compiler->vm, &func->_super); - functionBufferWrite(&compiler->script->functions, compiler->vm, func); - vmPopTempRef(compiler->vm); int fn_index = (int)compiler->script->functions.count - 1; Func curr_func; @@ -1425,7 +1471,7 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) { func->arity = argc; if (fn_type != FN_NATIVE) { - compileBlockBody(compiler, false); + compileBlockBody(compiler, BLOCK_FUNC); } consume(parser, TK_END, "Expected 'end' after function definition end."); @@ -1441,11 +1487,16 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) { } // Finish a block body. -static void compileBlockBody(Compiler* compiler, bool if_body) { +static void compileBlockBody(Compiler* compiler, BlockType type) { - consumeStartBlock(&compiler->parser); compilerEnterBlock(compiler); - skipNewLines(&compiler->parser); + + if (type != BLOCK_ELIF) { + consumeStartBlock(&compiler->parser); + skipNewLines(&compiler->parser); + } + + bool if_body = (type == BLOCK_IF) || (type == BLOCK_ELIF); TokenType next = peek(&compiler->parser); while (!(next == TK_END || next == TK_EOF || ( @@ -1473,22 +1524,45 @@ static void compileIfStatement(Compiler* compiler) { emitOpcode(compiler, OP_JUMP_IF_NOT); int ifpatch = emitShort(compiler, 0xffff); //< Will be patched. - compileBlockBody(compiler, true); + compileBlockBody(compiler, BLOCK_IF); + + // Elif statement's don't consume 'end' after they end since it's treated as + // else and if they require 2 'end' statements. But we're omitting the 'end' + // for the 'else' since it'll consumed by the 'if'. + bool elif = false; + + if (peek(&compiler->parser) == TK_ELIF) { + elif = true; + // Override the elif to if so that it'll be parsed as a new if statement + // and that's why we're not consuming it here. + compiler->parser.current.type = TK_IF; + + // Jump pass else. + emitOpcode(compiler, OP_JUMP); + int exit_jump = emitShort(compiler, 0xffff); //< Will be patched. - if (match(&compiler->parser, TK_ELIF)) { patchJump(compiler, ifpatch); - compileBlockBody(compiler, true); + compileBlockBody(compiler, BLOCK_ELIF); + patchJump(compiler, exit_jump); } else if (match(&compiler->parser, TK_ELSE)) { + + // Jump pass else. + emitOpcode(compiler, OP_JUMP); + int exit_jump = emitShort(compiler, 0xffff); //< Will be patched. + patchJump(compiler, ifpatch); - compileBlockBody(compiler, false); + compileBlockBody(compiler, BLOCK_ELSE); + patchJump(compiler, exit_jump); } else { patchJump(compiler, ifpatch); } - skipNewLines(&compiler->parser); - consume(&compiler->parser, TK_END, "Expected 'end' after statement end."); + if (!elif) { + skipNewLines(&compiler->parser); + consume(&compiler->parser, TK_END, "Expected 'end' after statement end."); + } } static void compileWhileStatement(Compiler* compiler) { @@ -1502,7 +1576,7 @@ static void compileWhileStatement(Compiler* compiler) { emitOpcode(compiler, OP_JUMP_IF_NOT); int whilepatch = emitByte(compiler, 0xffff); //< Will be patched. - compileBlockBody(compiler, false); + compileBlockBody(compiler, BLOCK_LOOP); emitLoopJump(compiler); patchJump(compiler, whilepatch); @@ -1556,7 +1630,7 @@ static void compileForStatement(Compiler* compiler) { emitOpcode(compiler, OP_ITER); int forpatch = emitShort(compiler, 0xffff); - compileBlockBody(compiler, false); + compileBlockBody(compiler, BLOCK_LOOP); emitLoopJump(compiler); patchJump(compiler, forpatch); diff --git a/src/core.c b/src/core.c index 8013689..fc29083 100644 --- a/src/core.c +++ b/src/core.c @@ -49,7 +49,9 @@ int findBuiltinFunction(const char* name, int length) { return -1; } -// Validators ///////////////////////////////////////////////////////////////// +/*****************************************************************************/ +/* VALIDATORS */ +/*****************************************************************************/ // Check if a numeric value bool/number and set [value]. static inline bool isNumeric(Var var, double* value) { @@ -65,7 +67,7 @@ static inline bool isNumeric(Var var, double* value) { } // Check if [var] is bool/number. If not set error and return false. -static bool validateNumeric(MSVM* vm, Var var, double* value, +static inline bool validateNumeric(MSVM* vm, Var var, double* value, const char* name) { if (isNumeric(var, value)) return true; msSetRuntimeError(vm, "%s must be a numeric value.", name); @@ -73,7 +75,7 @@ static bool validateNumeric(MSVM* vm, Var var, double* value, } // Check if [var] is integer. If not set error and return false. -static bool validateIngeger(MSVM* vm, Var var, int32_t* value, +static inline bool validateIngeger(MSVM* vm, Var var, int32_t* value, const char* name) { double number; if (isNumeric(var, &number)) { @@ -88,7 +90,7 @@ static bool validateIngeger(MSVM* vm, Var var, int32_t* value, return false; } -static bool validateIndex(MSVM* vm, int32_t index, int32_t size, +static inline bool validateIndex(MSVM* vm, int32_t index, int32_t size, const char* container) { if (index < 0 || size <= index) { msSetRuntimeError(vm, "%s index out of range.", container); @@ -97,7 +99,9 @@ static bool validateIndex(MSVM* vm, int32_t index, int32_t size, return true; } -// Builtin Functions ////////////////////////////////////////////////////////// +/*****************************************************************************/ +/* BUILTIN FUNCTIONS */ +/*****************************************************************************/ // Argument getter (1 based). #define ARG(n) vm->rbp[n] @@ -106,7 +110,11 @@ static bool validateIndex(MSVM* vm, int32_t index, int32_t size, #define ARGC ((int)(vm->sp - vm->rbp) - 1) // Set return value. -#define RET(value) vm->rbp[0] = value +#define RET(value) \ + do { \ + vm->rbp[0] = value; \ + return; \ + } while (false) Function* getBuiltinFunction(int index) { ASSERT(index < BUILTIN_COUNT, "Index out of bound."); @@ -165,20 +173,44 @@ void corePrint(MSVM* vm) { void coreImport(MSVM* vm) { Var arg1 = vm->rbp[1]; - if (IS_OBJ(arg1) && AS_OBJ(arg1)->type == OBJ_STRING) { - TODO; - } else { + if (!IS_OBJ(arg1) || !AS_OBJ(arg1)->type == OBJ_STRING) { msSetRuntimeError(vm, "Expected a String argument."); } + + String* path = (String*)AS_OBJ(arg1); + if (path->length > 4 && strncmp(path->data, "std:", 4) == 0) { + Script* scr = vmGetStdScript(vm, path->data + 4); + ASSERT(scr != NULL, OOPS); + RET(VAR_OBJ(scr)); + } + + TODO; } -// TODO: Temp function to benchmark. -void coreClock(MSVM* vm) { +/*****************************************************************************/ +/* STD METHODS */ +/*****************************************************************************/ + +// std:list Methods. +void stdListSort(MSVM* vm) { + Var list = ARG(1); + if (!IS_OBJ(list) || AS_OBJ(list)->type != OBJ_LIST) { + msSetRuntimeError(vm, "Expected a list at argument 1."); + } + + // TODO: sort. + + RET(list); +} + +// std:os Methods. +void stdOsClock(MSVM* vm) { RET(VAR_NUM((double)clock() / CLOCKS_PER_SEC)); } - - +/*****************************************************************************/ +/* CORE INITIALIZATION */ +/*****************************************************************************/ void initializeCore(MSVM* vm) { int i = 0; //< Iterate through builtins. @@ -200,15 +232,43 @@ void initializeCore(MSVM* vm) { initializeBuiltinFN(vm, &builtins[i++], "print", -1, corePrint); initializeBuiltinFN(vm, &builtins[i++], "import", 1, coreImport); - // FIXME: move this. temp for benchmarking. - initializeBuiltinFN(vm, &builtins[i++], "clock", 0, coreClock); - // Sentinal to mark the end of the array. initializeBuiltinFN(vm, &builtins[i], NULL, 0, NULL); + // Make STD scripts. + Script* std; // A temporary pointer to the current std script. + Function* fn; // A temporary pointer to the allocated function function. + +#define STD_NEW_SCRIPT(_name) \ + do { \ + std = newScript(vm); \ + std->name = _name; \ + std->name_length = (int)strlen(_name); \ + vmPushTempRef(vm, &std->_super); \ + vmAddStdScript(vm, std); \ + vmPopTempRef(vm); \ + } while (false) + +#define STD_ADD_FUNCTION(_name, fptr, _arity) \ + do { \ + fn = newFunction(vm, _name, (int)strlen(_name), std, true); \ + fn->native = fptr; \ + fn->arity = _arity; \ + } while (false) + + // std:list script. + STD_NEW_SCRIPT("std:list"); + STD_ADD_FUNCTION("sort", stdListSort, 1); + + + // std:os script. + STD_NEW_SCRIPT("std:os"); + STD_ADD_FUNCTION("clock", stdOsClock, 0); // TODO: rename coreClock. } -// Operators ////////////////////////////////////////////////////////////////// +/*****************************************************************************/ +/* OPERATORS */ +/*****************************************************************************/ Var varAdd(MSVM* vm, Var v1, Var v2) { @@ -233,7 +293,9 @@ Var varSubtract(MSVM* vm, Var v1, Var v2) { return VAR_NULL; } - TODO; //string addition/ array addition etc. + msSetRuntimeError(vm, "Unsupported operand types for operator '-' " + "%s and %s", varTypeName(v1), varTypeName(v2)); + return VAR_NULL; } @@ -247,17 +309,26 @@ Var varMultiply(MSVM* vm, Var v1, Var v2) { return VAR_NULL; } - TODO; + msSetRuntimeError(vm, "Unsupported operand types for operator '*' " + "%s and %s", varTypeName(v1), varTypeName(v2)); return VAR_NULL; } Var varDivide(MSVM* vm, Var v1, Var v2) { - TODO; + double d1, d2; + if (isNumeric(v1, &d1)) { + if (validateNumeric(vm, v2, &d2, "Right operand")) { + return VAR_NUM(d1 / d2); + } + return VAR_NULL; + } + + msSetRuntimeError(vm, "Unsupported operand types for operator '/' " + "%s and %s", varTypeName(v1), varTypeName(v2)); return VAR_NULL; } -bool varGreater(Var v1, Var v2) { - +bool varGreater(MSVM* vm, Var v1, Var v2) { double d1, d2; if (isNumeric(v1, &d1) && isNumeric(v2, &d2)) { return d1 > d2; @@ -267,7 +338,7 @@ bool varGreater(Var v1, Var v2) { return false; } -bool varLesser(Var v1, Var v2) { +bool varLesser(MSVM* vm, Var v1, Var v2) { double d1, d2; if (isNumeric(v1, &d1) && isNumeric(v2, &d2)) { return d1 < d2; @@ -277,6 +348,120 @@ bool varLesser(Var v1, Var v2) { return false; } +Var varGetAttrib(MSVM* vm, Var on, String* attrib) { + if (!IS_OBJ(on)) { + msSetRuntimeError(vm, "%s type is not subscriptable.", varTypeName(on)); + return VAR_NULL; + } + + Object* obj = (Object*)AS_OBJ(on); + switch (obj->type) { + case OBJ_STRING: + case OBJ_LIST: + case OBJ_MAP: + case OBJ_RANGE: + TODO; + + case OBJ_SCRIPT: { + Script* scr = (Script*)obj; + + // Search in functions. + int index = nameTableFind(&scr->function_names, attrib->data, + attrib->length); + if (index != -1) { + // TODO: Assert index (not a runtime error). + return VAR_OBJ(scr->functions.data[index]); + } + + TODO; // Search in global variables. + } + + case OBJ_FUNC: + case OBJ_USER: + TODO; + + default: + UNREACHABLE(); + } + + UNREACHABLE(); + return VAR_NULL; +} + +void varSetAttrib(MSVM* vm, Var on, String* name, Var value) { + TODO; +} + +Var varGetSubscript(MSVM* vm, Var on, Var key) { + if (!IS_OBJ(on)) { + msSetRuntimeError(vm, "%s type is not subscriptable.", varTypeName(on)); + return VAR_NULL; + } + + Object* obj = AS_OBJ(on); + switch (obj->type) { + case OBJ_STRING: TODO; + + case OBJ_LIST: + { + int32_t index; + VarBuffer* elems = &((List*)obj)->elements; + if (!validateIngeger(vm, key, &index, "List index")) { + return VAR_NULL; + } + if (!validateIndex(vm, index, (int)elems->count, "List")) { + return VAR_NULL; + } + return elems->data[index]; + } + + case OBJ_MAP: + case OBJ_RANGE: + case OBJ_SCRIPT: + case OBJ_FUNC: + case OBJ_USER: + TODO; + default: + UNREACHABLE(); + } + + UNREACHABLE(); + return VAR_NULL; +} + +void varsetSubscript(MSVM* vm, Var on, Var key, Var value) { + if (!IS_OBJ(on)) { + msSetRuntimeError(vm, "%s type is not subscriptable.", varTypeName(on)); + return; + } + + Object* obj = AS_OBJ(on); + switch (obj->type) { + case OBJ_STRING: TODO; + + case OBJ_LIST: + { + int32_t index; + VarBuffer* elems = &((List*)obj)->elements; + if (!validateIngeger(vm, key, &index, "List index")) return; + if (!validateIndex(vm, index, (int)elems->count, "List")) return; + elems->data[index] = value; + return; + } + + case OBJ_MAP: + case OBJ_RANGE: + case OBJ_SCRIPT: + case OBJ_FUNC: + case OBJ_USER: + TODO; + default: + UNREACHABLE(); + } + + UNREACHABLE(); +} + bool varIterate(MSVM* vm, Var seq, Var* iterator, Var* value) { #ifdef DEBUG @@ -355,6 +540,6 @@ bool varIterate(MSVM* vm, Var seq, Var* iterator, Var* value) { UNREACHABLE(); } - TODO; + UNREACHABLE(); return false; } \ No newline at end of file diff --git a/src/core.h b/src/core.h index 5e15264..a2503b8 100644 --- a/src/core.h +++ b/src/core.h @@ -24,8 +24,14 @@ Var varSubtract(MSVM* vm, Var v1, Var v2); Var varMultiply(MSVM* vm, Var v1, Var v2); Var varDivide(MSVM* vm, Var v1, Var v2); -bool varGreater(Var v1, Var v2); -bool varLesser(Var v1, Var v2); +bool varGreater(MSVM* vm, Var v1, Var v2); +bool varLesser(MSVM* vm, Var v1, Var v2); + +Var varGetAttrib(MSVM* vm, Var on, String* attrib); +void varSetAttrib(MSVM* vm, Var on, String* name, Var value); + +Var varGetSubscript(MSVM* vm, Var on, Var key); +void varsetSubscript(MSVM* vm, Var on, Var key, Var value); // Functions ////////////////////////////////////////////////////////////////// diff --git a/src/opcodes.h b/src/opcodes.h index face369..84067be 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -134,6 +134,11 @@ OPCODE(RETURN, 0, -1) // param: 2 byte attrib name index. OPCODE(GET_ATTRIB, 2, 0) +// Get attribute to perform assignment operation before store it, so don't +// pop the var. +// param: 2 byte attrib name index. +OPCODE(GET_ATTRIB_AOP, 2, 1) + // Pop var and value update the attribute push result. // param: 2 byte attrib name index. OPCODE(SET_ATTRIB, 2, -1) @@ -141,6 +146,10 @@ OPCODE(SET_ATTRIB, 2, -1) // Pop var, key, get value and push the result. OPCODE(GET_SUBSCRIPT, 0, -1) +// Get subscript to perform assignment operation before store it, so it won't +// pop the var and the key. +OPCODE(GET_SUBSCRIPT_AOP, 0, 1) + // Pop var, key, value set and push value back. OPCODE(SET_SUBSCRIPT, 0, -2) diff --git a/src/types/name_table.c b/src/types/name_table.c index d616062..6d65132 100644 --- a/src/types/name_table.c +++ b/src/types/name_table.c @@ -15,14 +15,17 @@ void nameTableClear(NameTable* self, MSVM* vm) { stringBufferClear(self, vm); } -int nameTableAdd(NameTable* self, MSVM* vm, const char* name, size_t length) { +int nameTableAdd(NameTable* self, MSVM* vm, const char* name, size_t length, + String** ptr) { String* string = newString(vm, name, (uint32_t)length); vmPushTempRef(vm, &string->_super); stringBufferWrite(self, vm, string); vmPopTempRef(vm); - return (int)(self->count - 1); + int index = (int)(self->count - 1); + if (ptr != NULL) *ptr = self->data[index]; + return index; } const char* nameTableGet(NameTable* self, int index) { diff --git a/src/types/name_table.h b/src/types/name_table.h index cf3d71d..ee0e10f 100644 --- a/src/types/name_table.h +++ b/src/types/name_table.h @@ -19,7 +19,9 @@ void nameTableInit(NameTable* self); void nameTableClear(NameTable* self, MSVM* vm); // Add a name to the name table and return the index of the name in the table. -int nameTableAdd(NameTable* self, MSVM* vm, const char* name, size_t length); +// Parameter [ptr] will updated with the string entry if it's not NULL. +int nameTableAdd(NameTable* self, MSVM* vm, const char* name, size_t length, + String** ptr); // Return name at index. const char* nameTableGet(NameTable* self, int index); diff --git a/src/var.c b/src/var.c index 2df5e43..41403bc 100644 --- a/src/var.c +++ b/src/var.c @@ -83,41 +83,47 @@ Script* newScript(MSVM* vm) { Script* script = ALLOCATE(vm, Script); varInitObject(&script->_super, vm, OBJ_SCRIPT); + script->name = NULL; + script->name_length = 0; + script->path = NULL; + varBufferInit(&script->globals); nameTableInit(&script->global_names); - varBufferInit(&script->literals); - - vmPushTempRef(vm, &script->_super); - script->body = newFunction(vm, "@(ScriptLevel)", script, false); - vmPopTempRef(vm); - functionBufferInit(&script->functions); nameTableInit(&script->function_names); - stringBufferInit(&script->names); + vmPushTempRef(vm, &script->_super); + const char* fn_name = "@(ScriptLevel)"; + script->body = newFunction(vm, fn_name, (int)strlen(fn_name), script, false); + vmPopTempRef(vm); + return script; } -Function* newFunction(MSVM* vm, const char* name, Script* owner, +Function* newFunction(MSVM* vm, const char* name, int length, Script* owner, bool is_native) { Function* func = ALLOCATE(vm, Function); varInitObject(&func->_super, vm, OBJ_FUNC); - func->name = name; + // Add the name in the script's function buffer. + String* name_ptr; + vmPushTempRef(vm, &func->_super); + functionBufferWrite(&owner->functions, vm, func); + nameTableAdd(&owner->function_names, vm, name, length, &name_ptr); + vmPopTempRef(vm); + + func->name = name_ptr->data; func->owner = owner; func->arity = -2; // -1 means variadic args. - func->is_native = is_native; if (is_native) { func->native = NULL; } else { - vmPushTempRef(vm, &func->_super); Fn* fn = ALLOCATE(vm, Fn); - vmPopTempRef(vm); byteBufferInit(&fn->opcodes); intBufferInit(&fn->oplines); @@ -129,6 +135,27 @@ Function* newFunction(MSVM* vm, const char* name, Script* owner, // Utility functions ////////////////////////////////////////////////////////// +const char* varTypeName(Var v) { + if (IS_NULL(v)) return "null"; + if (IS_BOOL(v)) return "bool"; + if (IS_NUM(v)) return "number"; + + ASSERT(IS_OBJ(v), OOPS); + Object* obj = AS_OBJ(v); + switch (obj->type) { + case OBJ_STRING: return "String"; + case OBJ_LIST: return "List"; + case OBJ_MAP: return "Map"; + case OBJ_RANGE: return "Range"; + case OBJ_SCRIPT: return "Script"; + case OBJ_FUNC: return "Func"; + case OBJ_USER: return "UserObj"; + TODO; + default: + UNREACHABLE(); + } +} + bool isVauesSame(Var v1, Var v2) { #if VAR_NAN_TAGGING // Bit representation of each values are unique so just compare the bits. @@ -176,7 +203,7 @@ String* toString(MSVM* vm, Var v, bool recursive) { const char* name = ((Function*)obj)->name; int length = (int)strlen(name); // TODO: Assert length. char buff[TO_STRING_BUFF_SIZE]; - memcpy(buff, "[func:", 6); + memcpy(buff, "[Func:", 6); memcpy(buff + 6, name, length); buff[6 + length] = ']'; return newString(vm, buff, 6 + length + 1); diff --git a/src/var.h b/src/var.h index eeb2820..da97fcd 100644 --- a/src/var.h +++ b/src/var.h @@ -233,7 +233,9 @@ struct Range { struct Script { Object _super; - String* path; //< Absolute path of the script. + const char* name; //< Std script's name. Null for user script. + int name_length; //< Length of the name. + String* path; //< Absolute path of the script. Null for std scripts. ID imports[MAX_IMPORT_SCRIPTS]; //< Imported script IDs. int import_count; //< Number of import in imports. @@ -291,11 +293,14 @@ Script* newScript(MSVM* vm); // Allocate new Function object and return Function*. Parameter [name] should // be the name in the Script's nametable. -Function* newFunction(MSVM* vm, const char* name, Script* owner, +Function* newFunction(MSVM* vm, const char* name, int length, Script* owner, bool is_native); // Utility functions ////////////////////////////////////////////////////////// +// Returns the type name of the var [v]. +const char* varTypeName(Var v); + // Returns true if both variables are the same. bool isVauesSame(Var v1, Var v2); diff --git a/src/vm.c b/src/vm.c index 0507c9f..33b12f1 100644 --- a/src/vm.c +++ b/src/vm.c @@ -53,6 +53,22 @@ void vmPopTempRef(MSVM* self) { self->temp_reference_count--; } +void vmAddStdScript(MSVM* self, Script* script) { + ASSERT(self->std_count < MAX_SCRIPT_CACHE, OOPS); + self->std_scripts[self->std_count++] = script; +} + +Script* vmGetStdScript(MSVM* self, const char* name) { + for (int i = 0; i < self->std_count; i++) { + Script* scr = self->std_scripts[i]; + // +4 to skip "std:". + if (strcmp(name, scr->name + 4) == 0) { + return scr; + } + } + return NULL; +} + /****************************************************************************** * RUNTIME * *****************************************************************************/ @@ -422,11 +438,55 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) { } OPCODE(GET_ATTRIB): + { + Var on = POP(); + String* name = script->names.data[READ_SHORT()]; + PUSH(varGetAttrib(vm, on, name)); + DISPATCH(); + } + + OPCODE(GET_ATTRIB_AOP): + { + Var on = *(vm->sp - 1); + String* name = script->names.data[READ_SHORT()]; + PUSH(varGetAttrib(vm, on, name)); + DISPATCH(); + } + OPCODE(SET_ATTRIB): - OPCODE(GET_SUBSCRIPT): - OPCODE(SET_SUBSCRIPT): TODO; + OPCODE(GET_SUBSCRIPT): + { + Var key = POP(); + Var on = POP(); + PUSH(varGetSubscript(vm, on, key)); + CHECK_ERROR(); + DISPATCH(); + } + + OPCODE(GET_SUBSCRIPT_AOP): + { + Var key = *(vm->sp - 1); + Var on = *(vm->sp - 2); + PUSH(varGetSubscript(vm, on, key)); + CHECK_ERROR(); + DISPATCH(); + } + + OPCODE(SET_SUBSCRIPT): + { + Var value = POP(); + Var key = POP(); + Var on = POP(); + + varsetSubscript(vm, on, key, value); + CHECK_ERROR(); + PUSH(value); + + DISPATCH(); + } + OPCODE(NEGATIVE): { Var num = POP(); @@ -481,7 +541,8 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) { OPCODE(LT): { - PUSH(VAR_BOOL(varLesser(POP(), POP()))); + PUSH(VAR_BOOL(varLesser(vm, POP(), POP()))); + CHECK_ERROR(); DISPATCH(); } @@ -490,7 +551,8 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) { OPCODE(GT): { - PUSH(VAR_BOOL(varGreater(POP(), POP()))); + PUSH(VAR_BOOL(varGreater(vm, POP(), POP()))); + CHECK_ERROR(); DISPATCH(); } diff --git a/src/vm.h b/src/vm.h index dd70380..7513e1e 100644 --- a/src/vm.h +++ b/src/vm.h @@ -49,6 +49,12 @@ struct MSVM { // Current compiler reference to mark it's heap allocated objects. Compiler* compiler; + // Std scripts array. + Script* std_scripts[MAX_SCRIPT_CACHE]; + + // Std scripts count. + int std_count; + // Execution variables //////////////////////////////////////////////////// // Compiled script cache. @@ -105,6 +111,14 @@ void vmPushTempRef(MSVM* self, Object* obj); // Pop the top most object from temporary reference stack. void vmPopTempRef(MSVM* self); +// Add a std script to vm when initializing core. +void vmAddStdScript(MSVM* self, Script* script); + +// Returns the std script with the name [name]. Note that the name shouldn't +// be start with "std:" but the actual name of the script. If not found +// returns NULL. +Script* vmGetStdScript(MSVM* self, const char* name); + // Runs the script and return result. MSInterpretResult vmRunScript(MSVM* vm, Script* script); diff --git a/test/main.c b/test/main.c index b748d59..d99035c 100644 --- a/test/main.c +++ b/test/main.c @@ -5,20 +5,10 @@ #include -//#define CLOGGER_IMPLEMENT -//#include "clogger.h" - #include "miniscript.h" #include -static const char* opnames[] = { - #define OPCODE(name, params, stack) #name, - #include "../src/opcodes.h" - #undef OPCODE - NULL, -}; - void errorPrint(MSVM* vm, MSErrorType type, const char* file, int line, const char* message) { fprintf(stderr, "Error: %s\n\tat %s:%i\n", message, file, line);