mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Plumbing for index and dot notations is working
This commit is contained in:
@@ -267,7 +267,7 @@ static int writeLiteralToCompiler(Compiler* compiler, Literal literal) {
|
||||
return index;
|
||||
}
|
||||
|
||||
static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAddressesPtr, void* continueAddressesPtr, int jumpOffsets) { //NOTE: jumpOfsets are included, because function arg and return indexes are embedded in the code body i.e. need to include thier sizes in the jump
|
||||
static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAddressesPtr, void* continueAddressesPtr, int jumpOffsets) { //NOTE: jumpOfsets are included, because function arg and return indexes are embedded in the code body i.e. need to include thier sizes in the jump
|
||||
//grow if the bytecode space is too small
|
||||
if (compiler->count + 32 > compiler->capacity) {
|
||||
int oldCapacity = compiler->capacity;
|
||||
@@ -295,11 +295,31 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)node->unary.opcode; //1 byte
|
||||
break;
|
||||
|
||||
case NODE_BINARY:
|
||||
//all infixes come here
|
||||
case NODE_BINARY: {
|
||||
//pass to the child nodes, then embed the binary command (math, etc.)
|
||||
writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
Opcode override = writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
|
||||
//special case for when indexing
|
||||
if (override != OP_EOF && node->binary.opcode >= OP_VAR_ASSIGN && node->binary.opcode <= OP_VAR_MODULO_ASSIGN) {
|
||||
writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)override + 2; //1 byte WARNING: enum arithmetic
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
|
||||
return OP_EOF;
|
||||
}
|
||||
|
||||
//return from the index-binary
|
||||
Opcode ret = writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
|
||||
//loopy logic - if opcode == index or dot
|
||||
if (node->binary.opcode == OP_INDEX || node->binary.opcode == OP_DOT) {
|
||||
return node->binary.opcode;
|
||||
}
|
||||
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
|
||||
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_GROUPING:
|
||||
@@ -339,6 +359,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
|
||||
|
||||
case NODE_PAIR:
|
||||
fprintf(stderr, ERROR "[internal] NODE_PAIR encountered in writeCompilerWithJumps()\n" RESET);
|
||||
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
|
||||
break;
|
||||
|
||||
case NODE_VAR_DECL: {
|
||||
@@ -736,11 +757,66 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)OP_EXPORT; //1 byte
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_INDEX: {
|
||||
//pass to the child nodes, then embed the opcode
|
||||
|
||||
//first
|
||||
if (!node->index.first) {
|
||||
writeLiteralToCompiler(compiler, TO_NULL_LITERAL);
|
||||
}
|
||||
else {
|
||||
writeCompilerWithJumps(compiler, node->index.first, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
}
|
||||
|
||||
//second
|
||||
if (!node->index.second) {
|
||||
writeLiteralToCompiler(compiler, TO_NULL_LITERAL);
|
||||
}
|
||||
else {
|
||||
writeCompilerWithJumps(compiler, node->index.second, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
}
|
||||
|
||||
//third
|
||||
if (!node->index.third) {
|
||||
writeLiteralToCompiler(compiler, TO_NULL_LITERAL);
|
||||
}
|
||||
else {
|
||||
writeCompilerWithJumps(compiler, node->index.third, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
}
|
||||
|
||||
// compiler->bytecode[compiler->count++] = (unsigned char)OP_INDEX; //1 byte
|
||||
|
||||
return OP_INDEX_ASSIGN; //override binary's instruction IF it is assign
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_DOT: {
|
||||
//pass to the child nodes, then embed the opcode
|
||||
if (!node->index.first) {
|
||||
writeLiteralToCompiler(compiler, TO_NULL_LITERAL);
|
||||
}
|
||||
else {
|
||||
writeCompilerWithJumps(compiler, node->index.first, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
}
|
||||
|
||||
// compiler->bytecode[compiler->count++] = (unsigned char)OP_DOT; //1 byte
|
||||
|
||||
return OP_DOT_ASSIGN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return OP_EOF;
|
||||
}
|
||||
|
||||
void writeCompiler(Compiler* compiler, Node* node) {
|
||||
writeCompilerWithJumps(compiler, node, NULL, NULL, 0);
|
||||
Opcode op = writeCompilerWithJumps(compiler, node, NULL, NULL, 0);
|
||||
|
||||
//compensate for indexing & dot notation being screwy
|
||||
if (op != OP_EOF) {
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)op; //1 byte
|
||||
}
|
||||
}
|
||||
|
||||
void freeCompiler(Compiler* compiler) {
|
||||
|
||||
@@ -1345,6 +1345,430 @@ static bool execExport(Interpreter* interpreter) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool execIndex(Interpreter* interpreter) {
|
||||
//assume -> compound, first, second, third are all on the stack
|
||||
|
||||
Literal third = popLiteralArray(&interpreter->stack);
|
||||
Literal second = popLiteralArray(&interpreter->stack);
|
||||
Literal first = popLiteralArray(&interpreter->stack);
|
||||
Literal compound = popLiteralArray(&interpreter->stack);
|
||||
|
||||
if (!IS_IDENTIFIER(compound)) {
|
||||
interpreter->errorOutput("Unknown literal found in indexing notation\n");
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parseIdentifierToValue(interpreter, &compound)) {
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IS_ARRAY(compound) && !IS_DICTIONARY(compound) && !IS_STRING(compound)) {
|
||||
interpreter->errorOutput("Unknown compound found in indexing notation\n");
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
return false;
|
||||
}
|
||||
|
||||
//get the index function
|
||||
Literal func = TO_NULL_LITERAL;
|
||||
char* keyStr = "_index";
|
||||
Literal key = TO_IDENTIFIER_LITERAL(copyString(keyStr, strlen(keyStr)), strlen(keyStr));
|
||||
|
||||
if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) {
|
||||
interpreter->errorOutput("couldn't get the _index function\n");
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(func);
|
||||
freeLiteral(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
//build the argument list
|
||||
LiteralArray arguments;
|
||||
initLiteralArray(&arguments);
|
||||
|
||||
pushLiteralArray(&arguments, compound);
|
||||
pushLiteralArray(&arguments, first);
|
||||
pushLiteralArray(&arguments, second);
|
||||
pushLiteralArray(&arguments, third);
|
||||
pushLiteralArray(&arguments, TO_NULL_LITERAL); //it expects an assignment command
|
||||
pushLiteralArray(&arguments, TO_NULL_LITERAL); //it expects an assignment "opcode"
|
||||
|
||||
//call the function
|
||||
NativeFn fn = (NativeFn)AS_FUNCTION(func).bytecode;
|
||||
fn(interpreter, &arguments);
|
||||
|
||||
//clean up
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(func);
|
||||
freeLiteralArray(&arguments);
|
||||
freeLiteral(key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool execDot(Interpreter* interpreter) {
|
||||
//assume -> compound, first are all on the stack
|
||||
|
||||
Literal first = popLiteralArray(&interpreter->stack);
|
||||
Literal compound = popLiteralArray(&interpreter->stack);
|
||||
|
||||
if (!IS_IDENTIFIER(compound)) {
|
||||
interpreter->errorOutput("Unknown literal found in dot notation\n");
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parseIdentifierToValue(interpreter, &compound)) {
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IS_ARRAY(compound) && !IS_DICTIONARY(compound) && !IS_STRING(compound)) {
|
||||
interpreter->errorOutput("Unknown compound found in dot notation\n");
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
return false;
|
||||
}
|
||||
|
||||
//get the index function
|
||||
Literal func = TO_NULL_LITERAL;
|
||||
char* keyStr = "_dot";
|
||||
Literal key = TO_IDENTIFIER_LITERAL(copyString(keyStr, strlen(keyStr)), strlen(keyStr));
|
||||
|
||||
if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) {
|
||||
interpreter->errorOutput("couldn't get the _dot function\n");
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(func);
|
||||
freeLiteral(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
//build the argument list
|
||||
LiteralArray arguments;
|
||||
initLiteralArray(&arguments);
|
||||
|
||||
pushLiteralArray(&arguments, compound);
|
||||
pushLiteralArray(&arguments, first);
|
||||
pushLiteralArray(&arguments, TO_NULL_LITERAL); //it expects an assignment command
|
||||
pushLiteralArray(&arguments, TO_NULL_LITERAL); //it expects an assignment "opcode"
|
||||
|
||||
//call the function
|
||||
NativeFn fn = (NativeFn)AS_FUNCTION(func).bytecode;
|
||||
fn(interpreter, &arguments);
|
||||
|
||||
//clean up
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(func);
|
||||
freeLiteralArray(&arguments);
|
||||
freeLiteral(key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool execIndexAssign(Interpreter* interpreter) {
|
||||
//assume -> compound, first, second, third, assign are all on the stack
|
||||
|
||||
Literal assign = popLiteralArray(&interpreter->stack);
|
||||
Literal third = popLiteralArray(&interpreter->stack);
|
||||
Literal second = popLiteralArray(&interpreter->stack);
|
||||
Literal first = popLiteralArray(&interpreter->stack);
|
||||
Literal compound = popLiteralArray(&interpreter->stack);
|
||||
|
||||
if (!IS_IDENTIFIER(compound)) {
|
||||
interpreter->errorOutput("Unknown literal found in index assigning notation\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
return false;
|
||||
}
|
||||
|
||||
Literal idn = copyLiteral(compound);
|
||||
|
||||
if (!parseIdentifierToValue(interpreter, &compound)) {
|
||||
freeLiteral(assign);
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IS_ARRAY(compound) && !IS_DICTIONARY(compound) && !IS_STRING(compound)) {
|
||||
interpreter->errorOutput("Unknown compound found in index assigning notation\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
return false;
|
||||
}
|
||||
|
||||
//get the index function
|
||||
Literal func = TO_NULL_LITERAL;
|
||||
char* keyStr = "_index";
|
||||
Literal key = TO_IDENTIFIER_LITERAL(copyString(keyStr, strlen(keyStr)), strlen(keyStr));
|
||||
|
||||
if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) {
|
||||
interpreter->errorOutput("couldn't get the _index function\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteral(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
//build the opcode
|
||||
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
||||
char* opStr = "";
|
||||
switch(opcode) {
|
||||
case OP_VAR_ASSIGN:
|
||||
opStr = "=";
|
||||
break;
|
||||
case OP_VAR_ADDITION_ASSIGN:
|
||||
opStr = "+=";
|
||||
break;
|
||||
case OP_VAR_SUBTRACTION_ASSIGN:
|
||||
opStr = "-=";
|
||||
break;
|
||||
case OP_VAR_MULTIPLICATION_ASSIGN:
|
||||
opStr = "*=";
|
||||
break;
|
||||
case OP_VAR_DIVISION_ASSIGN:
|
||||
opStr = "/=";
|
||||
break;
|
||||
case OP_VAR_MODULO_ASSIGN:
|
||||
opStr = "%=";
|
||||
break;
|
||||
|
||||
default:
|
||||
interpreter->errorOutput("bad opcode in index assigning notation\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteral(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
Literal op = TO_STRING_LITERAL(copyString(opStr, strlen(opStr)), strlen(opStr));
|
||||
|
||||
//build the argument list
|
||||
LiteralArray arguments;
|
||||
initLiteralArray(&arguments);
|
||||
|
||||
pushLiteralArray(&arguments, compound);
|
||||
pushLiteralArray(&arguments, first);
|
||||
pushLiteralArray(&arguments, second);
|
||||
pushLiteralArray(&arguments, third);
|
||||
pushLiteralArray(&arguments, assign); //it expects an assignment command
|
||||
pushLiteralArray(&arguments, op); //it expects an assignment "opcode"
|
||||
|
||||
//call the function
|
||||
NativeFn fn = (NativeFn)AS_FUNCTION(func).bytecode;
|
||||
fn(interpreter, &arguments);
|
||||
|
||||
//save the result (assume top of the interpreter stack is the new compound value)
|
||||
Literal result = popLiteralArray(&interpreter->stack);
|
||||
if (!setScopeVariable(interpreter->scope, idn, result, true)) {//TODO: check this const-ness
|
||||
interpreter->errorOutput("Incorrect type assigned to compound member: ");
|
||||
printLiteralCustom(result, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
|
||||
//clean up
|
||||
freeLiteral(op);
|
||||
freeLiteral(assign);
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteralArray(&arguments);
|
||||
freeLiteral(key);
|
||||
freeLiteral(result);
|
||||
return false;
|
||||
}
|
||||
|
||||
//clean up
|
||||
freeLiteral(op);
|
||||
freeLiteral(assign);
|
||||
freeLiteral(third);
|
||||
freeLiteral(second);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteralArray(&arguments);
|
||||
freeLiteral(key);
|
||||
freeLiteral(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool execDotAssign(Interpreter* interpreter) {
|
||||
//assume -> compound, first, assign are all on the stack
|
||||
|
||||
Literal assign = popLiteralArray(&interpreter->stack);
|
||||
Literal first = popLiteralArray(&interpreter->stack);
|
||||
Literal compound = popLiteralArray(&interpreter->stack);
|
||||
|
||||
if (!IS_IDENTIFIER(compound)) {
|
||||
interpreter->errorOutput("Unknown literal found in dot assigning notation\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
return false;
|
||||
}
|
||||
|
||||
Literal idn = copyLiteral(compound);
|
||||
|
||||
if (!parseIdentifierToValue(interpreter, &compound)) {
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IS_ARRAY(compound) && !IS_DICTIONARY(compound) && !IS_STRING(compound)) {
|
||||
interpreter->errorOutput("Unknown compound found in dot assigning notation\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
return false;
|
||||
}
|
||||
|
||||
//get the index function
|
||||
Literal func = TO_NULL_LITERAL;
|
||||
char* keyStr = "_dot";
|
||||
Literal key = TO_IDENTIFIER_LITERAL(copyString(keyStr, strlen(keyStr)), strlen(keyStr));
|
||||
|
||||
if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) {
|
||||
interpreter->errorOutput("couldn't get the _dot function\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteral(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
//build the opcode
|
||||
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
||||
char* opStr = "";
|
||||
switch(opcode) {
|
||||
case OP_VAR_ASSIGN:
|
||||
opStr = "=";
|
||||
break;
|
||||
case OP_VAR_ADDITION_ASSIGN:
|
||||
opStr = "+=";
|
||||
break;
|
||||
case OP_VAR_SUBTRACTION_ASSIGN:
|
||||
opStr = "-=";
|
||||
break;
|
||||
case OP_VAR_MULTIPLICATION_ASSIGN:
|
||||
opStr = "*=";
|
||||
break;
|
||||
case OP_VAR_DIVISION_ASSIGN:
|
||||
opStr = "/=";
|
||||
break;
|
||||
case OP_VAR_MODULO_ASSIGN:
|
||||
opStr = "%=";
|
||||
break;
|
||||
|
||||
default:
|
||||
interpreter->errorOutput("bad opcode in dot assigning notation\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteral(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
Literal op = TO_STRING_LITERAL(copyString(opStr, strlen(opStr)), strlen(opStr));
|
||||
|
||||
//build the argument list
|
||||
LiteralArray arguments;
|
||||
initLiteralArray(&arguments);
|
||||
|
||||
pushLiteralArray(&arguments, compound);
|
||||
pushLiteralArray(&arguments, first);
|
||||
pushLiteralArray(&arguments, assign); //it expects an assignment command
|
||||
pushLiteralArray(&arguments, op); //it expects an assignment "opcode"
|
||||
|
||||
//call the function
|
||||
NativeFn fn = (NativeFn)AS_FUNCTION(func).bytecode;
|
||||
fn(interpreter, &arguments);
|
||||
|
||||
//save the result (assume top of the interpreter stack is the new compound value)
|
||||
Literal result = popLiteralArray(&interpreter->stack);
|
||||
if (!setScopeVariable(interpreter->scope, idn, result, true)) {//TODO: check this const-ness
|
||||
interpreter->errorOutput("Incorrect type assigned to compound member: ");
|
||||
printLiteralCustom(result, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
|
||||
//clean up
|
||||
freeLiteral(op);
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteralArray(&arguments);
|
||||
freeLiteral(key);
|
||||
freeLiteral(result);
|
||||
return false;
|
||||
}
|
||||
|
||||
//clean up
|
||||
freeLiteral(op);
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteralArray(&arguments);
|
||||
freeLiteral(key);
|
||||
freeLiteral(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//the heart of toy
|
||||
static void execInterpreter(Interpreter* interpreter) {
|
||||
//set the starting point for the interpreter
|
||||
@@ -1552,6 +1976,30 @@ static void execInterpreter(Interpreter* interpreter) {
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_INDEX:
|
||||
if (!execIndex(interpreter)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_DOT:
|
||||
if (!execDot(interpreter)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_INDEX_ASSIGN:
|
||||
if (!execIndexAssign(interpreter)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_DOT_ASSIGN:
|
||||
if (!execDotAssign(interpreter)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_POP_STACK:
|
||||
while (interpreter->stack.count > 0) {
|
||||
freeLiteral(popLiteralArray(&interpreter->stack));
|
||||
@@ -1915,6 +2363,8 @@ void resetInterpreter(Interpreter* interpreter) {
|
||||
interpreter->scope = pushScope(NULL);
|
||||
|
||||
//globally available functions
|
||||
injectNativeFn(interpreter, "_index", _index);
|
||||
injectNativeFn(interpreter, "_dot", _dot);
|
||||
injectNativeFn(interpreter, "_set", _set);
|
||||
injectNativeFn(interpreter, "_get", _get);
|
||||
injectNativeFn(interpreter, "_push", _push);
|
||||
|
||||
@@ -30,12 +30,13 @@ typedef struct Interpreter {
|
||||
bool panic;
|
||||
} Interpreter;
|
||||
|
||||
//for native function API
|
||||
//native function API
|
||||
typedef int (*NativeFn)(Interpreter* interpreter, LiteralArray* arguments);
|
||||
bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func);
|
||||
bool parseIdentifierToValue(Interpreter* interpreter, Literal* literalPtr);
|
||||
//TODO: injectNativeHook
|
||||
|
||||
//utilities for the host program
|
||||
bool parseIdentifierToValue(Interpreter* interpreter, Literal* literalPtr);
|
||||
void setInterpreterPrint(Interpreter* interpreter, PrintFn printOutput);
|
||||
void setInterpreterAssert(Interpreter* interpreter, PrintFn assertOutput);
|
||||
void setInterpreterError(Interpreter* interpreter, PrintFn errorOutput);
|
||||
|
||||
@@ -2,6 +2,52 @@
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
//_index(compound, first, second, third, assignValue, op)
|
||||
Literal op = popLiteralArray(arguments);
|
||||
Literal assign = popLiteralArray(arguments);
|
||||
Literal third = popLiteralArray(arguments);
|
||||
Literal second = popLiteralArray(arguments);
|
||||
Literal first = popLiteralArray(arguments);
|
||||
Literal compound = popLiteralArray(arguments);
|
||||
|
||||
printLiteralCustom(compound, interpreter->printOutput);
|
||||
printLiteralCustom(first, interpreter->printOutput);
|
||||
printLiteralCustom(second, interpreter->printOutput);
|
||||
printLiteralCustom(third, interpreter->printOutput);
|
||||
printLiteralCustom(op, interpreter->printOutput);
|
||||
printLiteralCustom(assign, interpreter->printOutput);
|
||||
|
||||
freeLiteral(compound);
|
||||
freeLiteral(first);
|
||||
freeLiteral(second);
|
||||
freeLiteral(third);
|
||||
freeLiteral(op);
|
||||
freeLiteral(assign);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _dot(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
//_dot(compound, first, assignValue, opcode)
|
||||
Literal op = popLiteralArray(arguments);
|
||||
Literal assign = popLiteralArray(arguments);
|
||||
Literal first = popLiteralArray(arguments);
|
||||
Literal compound = popLiteralArray(arguments);
|
||||
|
||||
printLiteralCustom(compound, interpreter->printOutput);
|
||||
printLiteralCustom(first, interpreter->printOutput);
|
||||
printLiteralCustom(op, interpreter->printOutput);
|
||||
printLiteralCustom(assign, interpreter->printOutput);
|
||||
|
||||
freeLiteral(compound);
|
||||
freeLiteral(first);
|
||||
freeLiteral(op);
|
||||
freeLiteral(assign);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _set(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
//if wrong number of arguments, fail
|
||||
if (arguments->count != 3) {
|
||||
@@ -413,4 +459,4 @@ int _clear(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
|
||||
freeLiteral(obj);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
int _index(Interpreter* interpreter, LiteralArray* arguments);
|
||||
int _dot(Interpreter* interpreter, LiteralArray* arguments);
|
||||
int _set(Interpreter* interpreter, LiteralArray* arguments);
|
||||
int _get(Interpreter* interpreter, LiteralArray* arguments);
|
||||
int _push(Interpreter* interpreter, LiteralArray* arguments);
|
||||
|
||||
@@ -99,8 +99,6 @@ void freeLiteral(Literal literal);
|
||||
#define IS_TRUTHY(x) _isTruthy(x)
|
||||
|
||||
#define MAX_STRING_LENGTH 4096
|
||||
// #define STRLEN(lit) ((lit).as.string.length)
|
||||
// #define STRLEN_I(lit) ((lit).as.identifier.length)
|
||||
#define HASH_I(lit) ((lit).as.identifier.hash)
|
||||
#define TYPE_PUSH_SUBTYPE(lit, subtype) _typePushSubtype(lit, subtype)
|
||||
|
||||
|
||||
@@ -12,6 +12,16 @@ void initLiteralArray(LiteralArray* array) {
|
||||
array->literals = NULL;
|
||||
}
|
||||
|
||||
void freeLiteralArray(LiteralArray* array) {
|
||||
//clean up memory
|
||||
for(int i = 0; i < array->count; i++) {
|
||||
freeLiteral(array->literals[i]);
|
||||
}
|
||||
|
||||
FREE_ARRAY(Literal, array->literals, array->capacity);
|
||||
initLiteralArray(array);
|
||||
}
|
||||
|
||||
int pushLiteralArray(LiteralArray* array, Literal literal) {
|
||||
if (array->capacity < array->count + 1) {
|
||||
int oldCapacity = array->capacity;
|
||||
@@ -39,16 +49,6 @@ Literal popLiteralArray(LiteralArray* array) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void freeLiteralArray(LiteralArray* array) {
|
||||
//clean up memory
|
||||
for(int i = 0; i < array->count; i++) {
|
||||
freeLiteral(array->literals[i]);
|
||||
}
|
||||
|
||||
FREE_ARRAY(Literal, array->literals, array->capacity);
|
||||
initLiteralArray(array);
|
||||
}
|
||||
|
||||
//find a literal in the array that matches the "literal" argument
|
||||
int findLiteralIndex(LiteralArray* array, Literal literal) {
|
||||
for (int i = 0; i < array->count; i++) {
|
||||
|
||||
@@ -9,8 +9,9 @@ typedef struct LiteralArray {
|
||||
} LiteralArray;
|
||||
|
||||
void initLiteralArray(LiteralArray* array);
|
||||
void freeLiteralArray(LiteralArray* array);
|
||||
int pushLiteralArray(LiteralArray* array, Literal literal);
|
||||
Literal popLiteralArray(LiteralArray* array);
|
||||
void freeLiteralArray(LiteralArray* array);
|
||||
//TODO: set & get
|
||||
|
||||
int findLiteralIndex(LiteralArray* array, Literal literal);
|
||||
|
||||
@@ -13,8 +13,8 @@ typedef struct _entry {
|
||||
typedef struct LiteralDictionary {
|
||||
_entry* entries;
|
||||
int capacity;
|
||||
int contains; //count + tombstones
|
||||
int count;
|
||||
int contains; //count + tombstones, for internal use
|
||||
} LiteralDictionary;
|
||||
|
||||
void initLiteralDictionary(LiteralDictionary* dictionary);
|
||||
|
||||
@@ -99,6 +99,13 @@ void freeNodeCustom(Node* node, bool freeSelf) {
|
||||
freeLiteral(node->import.identifier);
|
||||
freeLiteral(node->import.alias);
|
||||
break;
|
||||
|
||||
case NODE_INDEX:
|
||||
case NODE_DOT:
|
||||
freeNode(node->index.first);
|
||||
freeNode(node->index.second);
|
||||
freeNode(node->index.third);
|
||||
break;
|
||||
}
|
||||
|
||||
if (freeSelf) {
|
||||
@@ -261,4 +268,26 @@ void emitNodeImport(Node** nodeHandle, NodeType mode, Literal identifier, Litera
|
||||
tmp->import.alias = copyLiteral(alias);
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void emitNodeIndex(Node** nodeHandle, Node* first, Node* second, Node* third) {
|
||||
Node* tmp = ALLOCATE(Node, 1);
|
||||
|
||||
tmp->type = NODE_INDEX;
|
||||
tmp->index.first = first;
|
||||
tmp->index.second = second;
|
||||
tmp->index.third = third;
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
void emitNodeDot(Node** nodeHandle, Node* first) {
|
||||
Node* tmp = ALLOCATE(Node, 1);
|
||||
|
||||
tmp->type = NODE_DOT;
|
||||
tmp->index.first = first;
|
||||
tmp->index.second = NULL;
|
||||
tmp->index.third = NULL;
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ typedef enum NodeType {
|
||||
NODE_INCREMENT_POSTFIX,
|
||||
NODE_IMPORT,
|
||||
NODE_EXPORT,
|
||||
NODE_INDEX,
|
||||
NODE_DOT,
|
||||
} NodeType;
|
||||
|
||||
typedef struct NodeLiteral {
|
||||
@@ -124,6 +126,13 @@ typedef struct NodeImport {
|
||||
Literal alias;
|
||||
} NodeImport;
|
||||
|
||||
typedef struct NodeIndex {
|
||||
NodeType type;
|
||||
Node* first;
|
||||
Node* second;
|
||||
Node* third;
|
||||
} NodeIndex;
|
||||
|
||||
union _node {
|
||||
NodeType type;
|
||||
NodeLiteral atomic;
|
||||
@@ -140,6 +149,7 @@ union _node {
|
||||
NodePath path;
|
||||
NodeIncrement increment;
|
||||
NodeImport import;
|
||||
NodeIndex index;
|
||||
};
|
||||
|
||||
void freeNode(Node* node);
|
||||
@@ -157,4 +167,6 @@ void emitNodeFnCollection(Node** nodeHandle);
|
||||
void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postClause, Node* condition, Node* thenPath, Node* elsePath);
|
||||
void emitNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
||||
void emitNodePostfixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
||||
void emitNodeImport(Node** nodeHandle, NodeType mode, Literal identifier, Literal alias);
|
||||
void emitNodeImport(Node** nodeHandle, NodeType mode, Literal identifier, Literal alias);
|
||||
void emitNodeIndex(Node** nodeHandle, Node* first, Node* second, Node* third);
|
||||
void emitNodeDot(Node** nodeHandle, Node* first);
|
||||
@@ -48,6 +48,13 @@ typedef enum Opcode {
|
||||
OP_IMPORT,
|
||||
OP_EXPORT,
|
||||
|
||||
//for indexing
|
||||
OP_INDEX,
|
||||
OP_DOT,
|
||||
|
||||
OP_INDEX_ASSIGN,
|
||||
OP_DOT_ASSIGN,
|
||||
|
||||
//comparion of values
|
||||
OP_COMPARE_EQUAL,
|
||||
OP_COMPARE_NOT_EQUAL,
|
||||
|
||||
@@ -717,6 +717,60 @@ static Opcode fnCall(Parser* parser, Node** nodeHandle) {
|
||||
return OP_EOF;
|
||||
}
|
||||
|
||||
static Opcode indexAccess(Parser* parser, Node** nodeHandle) {
|
||||
advance(parser);
|
||||
|
||||
//val[first : second : third]
|
||||
|
||||
Node* first = NULL;
|
||||
Node* second = NULL;
|
||||
Node* third = NULL;
|
||||
|
||||
//eat the first
|
||||
if (!match(parser, TOKEN_COLON)) {
|
||||
parsePrecedence(parser, &first, PREC_TERNARY);
|
||||
}
|
||||
|
||||
if (match(parser, TOKEN_BRACKET_RIGHT)) {
|
||||
emitNodeIndex(nodeHandle, first, second, third);
|
||||
return OP_INDEX;
|
||||
}
|
||||
|
||||
consume(parser, TOKEN_COLON, "Expected ':' in index notation");
|
||||
|
||||
//eat the second
|
||||
if (!match(parser, TOKEN_COLON)) {
|
||||
parsePrecedence(parser, &second, PREC_TERNARY);
|
||||
}
|
||||
|
||||
if (match(parser, TOKEN_BRACKET_RIGHT)) {
|
||||
emitNodeIndex(nodeHandle, first, second, third);
|
||||
return OP_INDEX;
|
||||
}
|
||||
|
||||
consume(parser, TOKEN_COLON, "Expected ':' in index notation");
|
||||
|
||||
//eat the third
|
||||
parsePrecedence(parser, &third, PREC_TERNARY);
|
||||
emitNodeIndex(nodeHandle, first, second, third);
|
||||
|
||||
consume(parser, TOKEN_BRACKET_RIGHT, "Expected ']' in index notation");
|
||||
|
||||
return OP_INDEX;
|
||||
}
|
||||
|
||||
static Opcode dot(Parser* parser, Node** nodeHandle) {
|
||||
advance(parser); //for the dot
|
||||
advance(parser); //for the identifier
|
||||
|
||||
Node* first = NULL;
|
||||
|
||||
identifier(parser, &first); //specific case
|
||||
emitNodeDot(nodeHandle, first);
|
||||
|
||||
return OP_DOT;
|
||||
}
|
||||
|
||||
ParseRule parseRules[] = { //must match the token types
|
||||
//types
|
||||
{atomic, NULL, PREC_PRIMARY},// TOKEN_NULL,
|
||||
@@ -779,7 +833,7 @@ ParseRule parseRules[] = { //must match the token types
|
||||
//logical operators
|
||||
{grouping, fnCall, PREC_CALL},// TOKEN_PAREN_LEFT,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_PAREN_RIGHT,
|
||||
{compound, NULL, PREC_CALL},// TOKEN_BRACKET_LEFT,
|
||||
{compound, indexAccess, PREC_CALL},// TOKEN_BRACKET_LEFT,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_BRACKET_RIGHT,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_BRACE_LEFT,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_BRACE_RIGHT,
|
||||
@@ -797,7 +851,7 @@ ParseRule parseRules[] = { //must match the token types
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_COLON,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_SEMICOLON,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_COMMA,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_DOT,
|
||||
{NULL, dot, PREC_CALL},// TOKEN_DOT,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_PIPE,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_REST,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user