Plumbing for index and dot notations is working

This commit is contained in:
2022-09-05 17:43:42 +01:00
parent 82c03ecb33
commit 304e1a5fb0
14 changed files with 708 additions and 29 deletions

View File

@@ -34,7 +34,9 @@ DONE: Import/export keywords
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: Nullish types?
TODO: hooks on the external libraries, triggered on import
@@ -42,7 +44,8 @@ TODO: standard library
TODO: external script runner library
TODO: document how it all works - book?
TODO: maximum recursion/function depth
TODO: better API
TODO: packaging for release?
NOPE: a = b = c = 1;
NOPE: functions return a set number of values

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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)

View File

@@ -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++) {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {
@@ -262,3 +269,25 @@ void emitNodeImport(Node** nodeHandle, NodeType mode, Literal identifier, Litera
*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;
}

View File

@@ -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);
@@ -158,3 +168,5 @@ void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postC
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 emitNodeIndex(Node** nodeHandle, Node* first, Node* second, Node* third);
void emitNodeDot(Node** nodeHandle, Node* first);

View File

@@ -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,

View File

@@ -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,