mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 15:16:41 +08:00
increment operators implemented
This commit is contained in:
parent
c69a5686bb
commit
f090089e4b
@ -78,7 +78,7 @@ typedef struct {
|
|||||||
} MSConfiguration;
|
} MSConfiguration;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RESULT_SUCCESS,
|
RESULT_SUCCESS = 0,
|
||||||
RESULT_COMPILE_ERROR,
|
RESULT_COMPILE_ERROR,
|
||||||
RESULT_RUNTIME_ERROR,
|
RESULT_RUNTIME_ERROR,
|
||||||
} MSInterpretResult;
|
} MSInterpretResult;
|
||||||
|
141
src/compiler.c
141
src/compiler.c
@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "types/name_table.h"
|
#include "types/name_table.h"
|
||||||
#include "types/gen/byte_buffer.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.
|
// Read and ignore chars till it reach new line or EOF.
|
||||||
static void skipLineComment(Parser* parser) {
|
static void skipLineComment(Parser* parser) {
|
||||||
char c = eatChar(parser);
|
char c;
|
||||||
|
while ((c = peekChar(parser)) != '\0') {
|
||||||
while (c != '\n' && c != '\0') {
|
eatChar(parser);
|
||||||
c = eatChar(parser);
|
if (c == '\n') return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,6 +683,30 @@ static bool match(Parser* self, TokenType expected) {
|
|||||||
return true;
|
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.
|
// Match one or more lines and return true if there any.
|
||||||
static bool matchLine(Parser* parser) {
|
static bool matchLine(Parser* parser) {
|
||||||
if (peek(parser) != TK_LINE) return false;
|
if (peek(parser) != TK_LINE) return false;
|
||||||
@ -688,17 +715,20 @@ static bool matchLine(Parser* parser) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match semi collon or multiple new lines.
|
// Match semi collon, multiple new lines or peek 'end' keyword.
|
||||||
static void consumeEndStatement(Parser* parser) {
|
static bool matchEndStatement(Parser* parser) {
|
||||||
bool consumed = false;
|
if (match(parser, TK_SEMICOLLON)) {
|
||||||
|
skipNewLines(parser);
|
||||||
// Semi collon must be on the same line.
|
return true;
|
||||||
if (peek(parser) == TK_SEMICOLLON) {
|
|
||||||
match(parser, TK_SEMICOLLON);
|
|
||||||
consumed = 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 ';'.");
|
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
|
// Returns a optional compound assignment.
|
||||||
// and continue parsing for more error logs.
|
static bool matchAssignment(Parser* parser) {
|
||||||
static void consume(Parser* self, TokenType expected, const char* err_msg) {
|
if (match(parser, TK_EQ)) return true;
|
||||||
//ASSERT(expected != TK_LINE, "Can't match TK_LINE.");
|
if (match(parser, TK_PLUSEQ)) return true;
|
||||||
//matchLine(self);
|
if (match(parser, TK_MINUSEQ)) return true;
|
||||||
|
if (match(parser, TK_STAREQ)) return true;
|
||||||
lexToken(self);
|
if (match(parser, TK_DIVEQ)) return true;
|
||||||
if (self->previous.type != expected) {
|
return false;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
@ -932,7 +954,7 @@ static GrammarRule* getRule(TokenType type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Emit variable store.
|
// Emit variable store.
|
||||||
static void _emitStoreVariable(Compiler* compiler, int index, bool global) {
|
static void emitStoreVariable(Compiler* compiler, int index, bool global) {
|
||||||
if (global) {
|
if (global) {
|
||||||
emitOpcode(compiler, OP_STORE_GLOBAL);
|
emitOpcode(compiler, OP_STORE_GLOBAL);
|
||||||
emitShort(compiler, index);
|
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) {
|
if (global) {
|
||||||
emitOpcode(compiler, OP_PUSH_GLOBAL);
|
emitOpcode(compiler, OP_PUSH_GLOBAL);
|
||||||
emitShort(compiler, index);
|
emitShort(compiler, index);
|
||||||
@ -977,45 +999,56 @@ static void exprFunc(Compiler* compiler, bool can_assign) {
|
|||||||
|
|
||||||
// Local/global variables, script/native/builtin functions name.
|
// Local/global variables, script/native/builtin functions name.
|
||||||
static void exprName(Compiler* compiler, bool can_assign) {
|
static void exprName(Compiler* compiler, bool can_assign) {
|
||||||
const char* name_start = compiler->parser.previous.start;
|
|
||||||
int name_len = compiler->parser.previous.length;
|
Parser* parser = &compiler->parser;
|
||||||
int name_line = compiler->parser.previous.line;
|
|
||||||
|
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);
|
NameSearchResult result = compilerSearchName(compiler, name_start, name_len);
|
||||||
|
|
||||||
if (result.type == NAME_NOT_DEFINED) {
|
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,
|
int index = compilerAddVariable(compiler, name_start, name_len,
|
||||||
name_line);
|
name_line);
|
||||||
compileExpression(compiler);
|
compileExpression(compiler);
|
||||||
_emitStoreVariable(compiler, index, compiler->scope_depth == DEPTH_GLOBAL);
|
emitStoreVariable(compiler, index, compiler->scope_depth == DEPTH_GLOBAL);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
parseError(&compiler->parser, "Name \"%.*s\" is not defined.", name_len,
|
parseError(parser, "Name \"%.*s\" is not defined.", name_len, name_start);
|
||||||
name_start);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: can_assign and += -= etc.
|
// TODO: can_assign and += -= etc.
|
||||||
|
|
||||||
switch (result.type) {
|
switch (result.type) {
|
||||||
case NAME_LOCAL_VAR:
|
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:
|
case NAME_GLOBAL_VAR:
|
||||||
if (can_assign && match(&compiler->parser, TK_EQ)) {
|
|
||||||
|
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);
|
compileExpression(compiler);
|
||||||
_emitStoreVariable(compiler, result.index, true);
|
|
||||||
|
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 {
|
} else {
|
||||||
emitOpcode(compiler, OP_PUSH_GLOBAL);
|
emitPushVariable(compiler, result.index, result.type == NAME_GLOBAL_VAR);
|
||||||
emitShort(compiler, result.index);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1345,7 +1378,7 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) {
|
|||||||
vmPushTempRef(compiler->vm, &func->_super);
|
vmPushTempRef(compiler->vm, &func->_super);
|
||||||
functionBufferWrite(&compiler->script->functions, compiler->vm, func);
|
functionBufferWrite(&compiler->script->functions, compiler->vm, func);
|
||||||
vmPopTempRef(compiler->vm);
|
vmPopTempRef(compiler->vm);
|
||||||
int fn_index = compiler->script->functions.count - 1;
|
int fn_index = (int)compiler->script->functions.count - 1;
|
||||||
|
|
||||||
Func curr_func;
|
Func curr_func;
|
||||||
curr_func.outer_func = compiler->func;
|
curr_func.outer_func = compiler->func;
|
||||||
@ -1574,7 +1607,7 @@ static void compileStatement(Compiler* compiler) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match(parser, TK_SEMICOLLON)|| match(parser, TK_LINE)) {
|
if (matchEndStatement(parser)) {
|
||||||
emitOpcode(compiler, OP_PUSH_NULL);
|
emitOpcode(compiler, OP_PUSH_NULL);
|
||||||
emitOpcode(compiler, OP_RETURN);
|
emitOpcode(compiler, OP_RETURN);
|
||||||
} else {
|
} else {
|
||||||
|
45
src/core.c
45
src/core.c
@ -6,6 +6,8 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -50,7 +52,7 @@ int findBuiltinFunction(const char* name, int length) {
|
|||||||
// Validators /////////////////////////////////////////////////////////////////
|
// Validators /////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Check if a numeric value bool/number and set [value].
|
// 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)) {
|
if (IS_BOOL(var)) {
|
||||||
*value = AS_BOOL(var);
|
*value = AS_BOOL(var);
|
||||||
return true;
|
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) {
|
void initializeCore(MSVM* vm) {
|
||||||
|
|
||||||
int i = 0; //< Iterate through builtins.
|
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++], "print", -1, corePrint);
|
||||||
initializeBuiltinFN(vm, &builtins[i++], "import", 1, coreImport);
|
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.
|
// Sentinal to mark the end of the array.
|
||||||
initializeBuiltinFN(vm, &builtins[i], NULL, 0, NULL);
|
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) {
|
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;
|
return VAR_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +256,27 @@ Var varDivide(MSVM* vm, Var v1, Var v2) {
|
|||||||
return VAR_NULL;
|
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) {
|
bool varIterate(MSVM* vm, Var seq, Var* iterator, Var* value) {
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -24,6 +24,9 @@ Var varSubtract(MSVM* vm, Var v1, Var v2);
|
|||||||
Var varMultiply(MSVM* vm, Var v1, Var v2);
|
Var varMultiply(MSVM* vm, Var v1, Var v2);
|
||||||
Var varDivide(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 //////////////////////////////////////////////////////////////////
|
// Functions //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Parameter [iterator] should be VAR_NULL before starting the iteration.
|
// Parameter [iterator] should be VAR_NULL before starting the iteration.
|
||||||
|
28
src/var.c
28
src/var.c
@ -3,6 +3,8 @@
|
|||||||
* Licensed under: MIT License
|
* Licensed under: MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "var.h"
|
#include "var.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
@ -187,3 +189,29 @@ String* toString(MSVM* vm, Var v, bool recursive) {
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return NULL;
|
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;
|
||||||
|
}
|
||||||
|
@ -303,4 +303,7 @@ bool isVauesSame(Var v1, Var v2);
|
|||||||
// It's an internal use (or may be I could make a wrapper around).
|
// It's an internal use (or may be I could make a wrapper around).
|
||||||
String* toString(MSVM* vm, Var v, bool _recursive);
|
String* toString(MSVM* vm, Var v, bool _recursive);
|
||||||
|
|
||||||
|
// Returns the truthy value of the var.
|
||||||
|
bool toBool(Var v);
|
||||||
|
|
||||||
#endif // VAR_H
|
#endif // VAR_H
|
||||||
|
43
src/vm.c
43
src/vm.c
@ -14,7 +14,7 @@
|
|||||||
#define INITIAL_CALL_FRAMES 4
|
#define INITIAL_CALL_FRAMES 4
|
||||||
|
|
||||||
// Minimum size of the stack.
|
// 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) {
|
void* vmRealloc(MSVM* self, void* memory, size_t old_size, size_t new_size) {
|
||||||
|
|
||||||
@ -57,6 +57,8 @@ void vmPopTempRef(MSVM* self) {
|
|||||||
* RUNTIME *
|
* RUNTIME *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#include <stdio.h>
|
||||||
// TODO: A function for quick debug. REMOVE.
|
// TODO: A function for quick debug. REMOVE.
|
||||||
void _printStackTop(MSVM* vm) {
|
void _printStackTop(MSVM* vm) {
|
||||||
if (vm->sp != vm->stack) {
|
if (vm->sp != vm->stack) {
|
||||||
@ -64,6 +66,7 @@ void _printStackTop(MSVM* vm) {
|
|||||||
printf("%s\n", toString(vm, v, false)->data);
|
printf("%s\n", toString(vm, v, false)->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void ensureStackSize(MSVM* vm, int size) {
|
static void ensureStackSize(MSVM* vm, int size) {
|
||||||
if (vm->stack_size > size) return;
|
if (vm->stack_size > size) return;
|
||||||
@ -377,8 +380,24 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
|
|
||||||
|
|
||||||
OPCODE(JUMP_IF):
|
OPCODE(JUMP_IF):
|
||||||
|
{
|
||||||
|
Var cond = POP();
|
||||||
|
int offset = READ_SHORT();
|
||||||
|
if (toBool(cond)) {
|
||||||
|
ip += offset;
|
||||||
|
}
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE(JUMP_IF_NOT):
|
OPCODE(JUMP_IF_NOT):
|
||||||
TODO;
|
{
|
||||||
|
Var cond = POP();
|
||||||
|
int offset = READ_SHORT();
|
||||||
|
if (!toBool(cond)) {
|
||||||
|
ip += offset;
|
||||||
|
}
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE(RETURN):
|
OPCODE(RETURN):
|
||||||
{
|
{
|
||||||
@ -419,6 +438,12 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(NOT):
|
OPCODE(NOT):
|
||||||
|
{
|
||||||
|
Var val = POP();
|
||||||
|
PUSH(VAR_BOOL(!toBool(val)));
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE(BIT_NOT):
|
OPCODE(BIT_NOT):
|
||||||
TODO;
|
TODO;
|
||||||
|
|
||||||
@ -452,9 +477,23 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
OPCODE(OR):
|
OPCODE(OR):
|
||||||
OPCODE(EQEQ):
|
OPCODE(EQEQ):
|
||||||
OPCODE(NOTEQ):
|
OPCODE(NOTEQ):
|
||||||
|
TODO;
|
||||||
|
|
||||||
OPCODE(LT):
|
OPCODE(LT):
|
||||||
|
{
|
||||||
|
PUSH(VAR_BOOL(varLesser(POP(), POP())));
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE(LTEQ):
|
OPCODE(LTEQ):
|
||||||
|
TODO;
|
||||||
|
|
||||||
OPCODE(GT):
|
OPCODE(GT):
|
||||||
|
{
|
||||||
|
PUSH(VAR_BOOL(varGreater(POP(), POP())));
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE(GTEQ):
|
OPCODE(GTEQ):
|
||||||
TODO;
|
TODO;
|
||||||
|
|
||||||
|
29
test/main.c
29
test/main.c
@ -63,6 +63,19 @@ MSLoadScriptResult loadScript(MSVM* vm, const char* path) {
|
|||||||
|
|
||||||
int main(int argc, char** argv) {
|
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 <source_path>\n";
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("%s\n%s", notice, help);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* source_path = argv[1];
|
||||||
|
|
||||||
MSConfiguration config;
|
MSConfiguration config;
|
||||||
config.error_fn = errorPrint;
|
config.error_fn = errorPrint;
|
||||||
config.write_fn = writeFunction;
|
config.write_fn = writeFunction;
|
||||||
@ -70,19 +83,7 @@ int main(int argc, char** argv) {
|
|||||||
config.load_script_done_fn = loadScriptDone;
|
config.load_script_done_fn = loadScriptDone;
|
||||||
|
|
||||||
MSVM* vm = msNewVM(&config);
|
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");
|
return result;
|
||||||
//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;
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user