mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Plumbing for index and dot notations is working
This commit is contained in:
@@ -34,7 +34,9 @@ DONE: Import/export keywords
|
|||||||
DONE: A way to check the type of a variable (typeOf keyword)
|
DONE: A way to check the type of a variable (typeOf keyword)
|
||||||
|
|
||||||
|
|
||||||
TODO: slice and dot notation around the builtin _index function
|
TODO: slice and dot notation around the builtin _index and _dot functions
|
||||||
|
|
||||||
|
|
||||||
TODO: ternary operator
|
TODO: ternary operator
|
||||||
TODO: Nullish types?
|
TODO: Nullish types?
|
||||||
TODO: hooks on the external libraries, triggered on import
|
TODO: hooks on the external libraries, triggered on import
|
||||||
@@ -42,7 +44,8 @@ TODO: standard library
|
|||||||
TODO: external script runner library
|
TODO: external script runner library
|
||||||
TODO: document how it all works - book?
|
TODO: document how it all works - book?
|
||||||
TODO: maximum recursion/function depth
|
TODO: maximum recursion/function depth
|
||||||
|
TODO: better API
|
||||||
|
TODO: packaging for release?
|
||||||
|
|
||||||
NOPE: a = b = c = 1;
|
NOPE: a = b = c = 1;
|
||||||
NOPE: functions return a set number of values
|
NOPE: functions return a set number of values
|
||||||
@@ -267,7 +267,7 @@ static int writeLiteralToCompiler(Compiler* compiler, Literal literal) {
|
|||||||
return index;
|
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
|
//grow if the bytecode space is too small
|
||||||
if (compiler->count + 32 > compiler->capacity) {
|
if (compiler->count + 32 > compiler->capacity) {
|
||||||
int oldCapacity = 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
|
compiler->bytecode[compiler->count++] = (unsigned char)node->unary.opcode; //1 byte
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_BINARY:
|
//all infixes come here
|
||||||
|
case NODE_BINARY: {
|
||||||
//pass to the child nodes, then embed the binary command (math, etc.)
|
//pass to the child nodes, then embed the binary command (math, etc.)
|
||||||
writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
Opcode override = writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||||
writeCompilerWithJumps(compiler, node->binary.right, 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
|
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_GROUPING:
|
case NODE_GROUPING:
|
||||||
@@ -339,6 +359,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
|
|||||||
|
|
||||||
case NODE_PAIR:
|
case NODE_PAIR:
|
||||||
fprintf(stderr, ERROR "[internal] NODE_PAIR encountered in writeCompilerWithJumps()\n" RESET);
|
fprintf(stderr, ERROR "[internal] NODE_PAIR encountered in writeCompilerWithJumps()\n" RESET);
|
||||||
|
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_VAR_DECL: {
|
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
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_EXPORT; //1 byte
|
||||||
}
|
}
|
||||||
break;
|
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) {
|
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) {
|
void freeCompiler(Compiler* compiler) {
|
||||||
|
|||||||
@@ -1345,6 +1345,430 @@ static bool execExport(Interpreter* interpreter) {
|
|||||||
return true;
|
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
|
//the heart of toy
|
||||||
static void execInterpreter(Interpreter* interpreter) {
|
static void execInterpreter(Interpreter* interpreter) {
|
||||||
//set the starting point for the interpreter
|
//set the starting point for the interpreter
|
||||||
@@ -1552,6 +1976,30 @@ static void execInterpreter(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case OP_POP_STACK:
|
||||||
while (interpreter->stack.count > 0) {
|
while (interpreter->stack.count > 0) {
|
||||||
freeLiteral(popLiteralArray(&interpreter->stack));
|
freeLiteral(popLiteralArray(&interpreter->stack));
|
||||||
@@ -1915,6 +2363,8 @@ void resetInterpreter(Interpreter* interpreter) {
|
|||||||
interpreter->scope = pushScope(NULL);
|
interpreter->scope = pushScope(NULL);
|
||||||
|
|
||||||
//globally available functions
|
//globally available functions
|
||||||
|
injectNativeFn(interpreter, "_index", _index);
|
||||||
|
injectNativeFn(interpreter, "_dot", _dot);
|
||||||
injectNativeFn(interpreter, "_set", _set);
|
injectNativeFn(interpreter, "_set", _set);
|
||||||
injectNativeFn(interpreter, "_get", _get);
|
injectNativeFn(interpreter, "_get", _get);
|
||||||
injectNativeFn(interpreter, "_push", _push);
|
injectNativeFn(interpreter, "_push", _push);
|
||||||
|
|||||||
@@ -30,12 +30,13 @@ typedef struct Interpreter {
|
|||||||
bool panic;
|
bool panic;
|
||||||
} Interpreter;
|
} Interpreter;
|
||||||
|
|
||||||
//for native function API
|
//native function API
|
||||||
typedef int (*NativeFn)(Interpreter* interpreter, LiteralArray* arguments);
|
typedef int (*NativeFn)(Interpreter* interpreter, LiteralArray* arguments);
|
||||||
bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func);
|
bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func);
|
||||||
bool parseIdentifierToValue(Interpreter* interpreter, Literal* literalPtr);
|
//TODO: injectNativeHook
|
||||||
|
|
||||||
//utilities for the host program
|
//utilities for the host program
|
||||||
|
bool parseIdentifierToValue(Interpreter* interpreter, Literal* literalPtr);
|
||||||
void setInterpreterPrint(Interpreter* interpreter, PrintFn printOutput);
|
void setInterpreterPrint(Interpreter* interpreter, PrintFn printOutput);
|
||||||
void setInterpreterAssert(Interpreter* interpreter, PrintFn assertOutput);
|
void setInterpreterAssert(Interpreter* interpreter, PrintFn assertOutput);
|
||||||
void setInterpreterError(Interpreter* interpreter, PrintFn errorOutput);
|
void setInterpreterError(Interpreter* interpreter, PrintFn errorOutput);
|
||||||
|
|||||||
@@ -2,6 +2,52 @@
|
|||||||
|
|
||||||
#include "memory.h"
|
#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) {
|
int _set(Interpreter* interpreter, LiteralArray* arguments) {
|
||||||
//if wrong number of arguments, fail
|
//if wrong number of arguments, fail
|
||||||
if (arguments->count != 3) {
|
if (arguments->count != 3) {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "interpreter.h"
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
int _index(Interpreter* interpreter, LiteralArray* arguments);
|
||||||
|
int _dot(Interpreter* interpreter, LiteralArray* arguments);
|
||||||
int _set(Interpreter* interpreter, LiteralArray* arguments);
|
int _set(Interpreter* interpreter, LiteralArray* arguments);
|
||||||
int _get(Interpreter* interpreter, LiteralArray* arguments);
|
int _get(Interpreter* interpreter, LiteralArray* arguments);
|
||||||
int _push(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 IS_TRUTHY(x) _isTruthy(x)
|
||||||
|
|
||||||
#define MAX_STRING_LENGTH 4096
|
#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 HASH_I(lit) ((lit).as.identifier.hash)
|
||||||
#define TYPE_PUSH_SUBTYPE(lit, subtype) _typePushSubtype(lit, subtype)
|
#define TYPE_PUSH_SUBTYPE(lit, subtype) _typePushSubtype(lit, subtype)
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,16 @@ void initLiteralArray(LiteralArray* array) {
|
|||||||
array->literals = NULL;
|
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) {
|
int pushLiteralArray(LiteralArray* array, Literal literal) {
|
||||||
if (array->capacity < array->count + 1) {
|
if (array->capacity < array->count + 1) {
|
||||||
int oldCapacity = array->capacity;
|
int oldCapacity = array->capacity;
|
||||||
@@ -39,16 +49,6 @@ Literal popLiteralArray(LiteralArray* array) {
|
|||||||
return ret;
|
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
|
//find a literal in the array that matches the "literal" argument
|
||||||
int findLiteralIndex(LiteralArray* array, Literal literal) {
|
int findLiteralIndex(LiteralArray* array, Literal literal) {
|
||||||
for (int i = 0; i < array->count; i++) {
|
for (int i = 0; i < array->count; i++) {
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ typedef struct LiteralArray {
|
|||||||
} LiteralArray;
|
} LiteralArray;
|
||||||
|
|
||||||
void initLiteralArray(LiteralArray* array);
|
void initLiteralArray(LiteralArray* array);
|
||||||
|
void freeLiteralArray(LiteralArray* array);
|
||||||
int pushLiteralArray(LiteralArray* array, Literal literal);
|
int pushLiteralArray(LiteralArray* array, Literal literal);
|
||||||
Literal popLiteralArray(LiteralArray* array);
|
Literal popLiteralArray(LiteralArray* array);
|
||||||
void freeLiteralArray(LiteralArray* array);
|
//TODO: set & get
|
||||||
|
|
||||||
int findLiteralIndex(LiteralArray* array, Literal literal);
|
int findLiteralIndex(LiteralArray* array, Literal literal);
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ typedef struct _entry {
|
|||||||
typedef struct LiteralDictionary {
|
typedef struct LiteralDictionary {
|
||||||
_entry* entries;
|
_entry* entries;
|
||||||
int capacity;
|
int capacity;
|
||||||
int contains; //count + tombstones
|
|
||||||
int count;
|
int count;
|
||||||
|
int contains; //count + tombstones, for internal use
|
||||||
} LiteralDictionary;
|
} LiteralDictionary;
|
||||||
|
|
||||||
void initLiteralDictionary(LiteralDictionary* dictionary);
|
void initLiteralDictionary(LiteralDictionary* dictionary);
|
||||||
|
|||||||
@@ -99,6 +99,13 @@ void freeNodeCustom(Node* node, bool freeSelf) {
|
|||||||
freeLiteral(node->import.identifier);
|
freeLiteral(node->import.identifier);
|
||||||
freeLiteral(node->import.alias);
|
freeLiteral(node->import.alias);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_INDEX:
|
||||||
|
case NODE_DOT:
|
||||||
|
freeNode(node->index.first);
|
||||||
|
freeNode(node->index.second);
|
||||||
|
freeNode(node->index.third);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (freeSelf) {
|
if (freeSelf) {
|
||||||
@@ -262,3 +269,25 @@ void emitNodeImport(Node** nodeHandle, NodeType mode, Literal identifier, Litera
|
|||||||
|
|
||||||
*nodeHandle = tmp;
|
*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_INCREMENT_POSTFIX,
|
||||||
NODE_IMPORT,
|
NODE_IMPORT,
|
||||||
NODE_EXPORT,
|
NODE_EXPORT,
|
||||||
|
NODE_INDEX,
|
||||||
|
NODE_DOT,
|
||||||
} NodeType;
|
} NodeType;
|
||||||
|
|
||||||
typedef struct NodeLiteral {
|
typedef struct NodeLiteral {
|
||||||
@@ -124,6 +126,13 @@ typedef struct NodeImport {
|
|||||||
Literal alias;
|
Literal alias;
|
||||||
} NodeImport;
|
} NodeImport;
|
||||||
|
|
||||||
|
typedef struct NodeIndex {
|
||||||
|
NodeType type;
|
||||||
|
Node* first;
|
||||||
|
Node* second;
|
||||||
|
Node* third;
|
||||||
|
} NodeIndex;
|
||||||
|
|
||||||
union _node {
|
union _node {
|
||||||
NodeType type;
|
NodeType type;
|
||||||
NodeLiteral atomic;
|
NodeLiteral atomic;
|
||||||
@@ -140,6 +149,7 @@ union _node {
|
|||||||
NodePath path;
|
NodePath path;
|
||||||
NodeIncrement increment;
|
NodeIncrement increment;
|
||||||
NodeImport import;
|
NodeImport import;
|
||||||
|
NodeIndex index;
|
||||||
};
|
};
|
||||||
|
|
||||||
void freeNode(Node* node);
|
void freeNode(Node* node);
|
||||||
@@ -158,3 +168,5 @@ void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postC
|
|||||||
void emitNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
void emitNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
||||||
void emitNodePostfixIncrement(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_IMPORT,
|
||||||
OP_EXPORT,
|
OP_EXPORT,
|
||||||
|
|
||||||
|
//for indexing
|
||||||
|
OP_INDEX,
|
||||||
|
OP_DOT,
|
||||||
|
|
||||||
|
OP_INDEX_ASSIGN,
|
||||||
|
OP_DOT_ASSIGN,
|
||||||
|
|
||||||
//comparion of values
|
//comparion of values
|
||||||
OP_COMPARE_EQUAL,
|
OP_COMPARE_EQUAL,
|
||||||
OP_COMPARE_NOT_EQUAL,
|
OP_COMPARE_NOT_EQUAL,
|
||||||
|
|||||||
@@ -717,6 +717,60 @@ static Opcode fnCall(Parser* parser, Node** nodeHandle) {
|
|||||||
return OP_EOF;
|
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
|
ParseRule parseRules[] = { //must match the token types
|
||||||
//types
|
//types
|
||||||
{atomic, NULL, PREC_PRIMARY},// TOKEN_NULL,
|
{atomic, NULL, PREC_PRIMARY},// TOKEN_NULL,
|
||||||
@@ -779,7 +833,7 @@ ParseRule parseRules[] = { //must match the token types
|
|||||||
//logical operators
|
//logical operators
|
||||||
{grouping, fnCall, PREC_CALL},// TOKEN_PAREN_LEFT,
|
{grouping, fnCall, PREC_CALL},// TOKEN_PAREN_LEFT,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_PAREN_RIGHT,
|
{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_BRACKET_RIGHT,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_BRACE_LEFT,
|
{NULL, NULL, PREC_NONE},// TOKEN_BRACE_LEFT,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_BRACE_RIGHT,
|
{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_COLON,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_SEMICOLON,
|
{NULL, NULL, PREC_NONE},// TOKEN_SEMICOLON,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_COMMA,
|
{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_PIPE,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_REST,
|
{NULL, NULL, PREC_NONE},// TOKEN_REST,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user