mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-17 15:54:07 +10:00
Arrays and dictionaries have been implemented, read more
The arrays and dictionaries are currently being printed out correctly, afaik. This means I should be able to go back and work on the type system, assuming nothing happens.
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
#include "literal.h"
|
||||
#include "literal_array.h"
|
||||
#include "literal_dictionary.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void initCompiler(Compiler* compiler) {
|
||||
@@ -90,6 +94,72 @@ void writeCompiler(Compiler* compiler, Node* node) {
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_END; //1 byte
|
||||
break;
|
||||
|
||||
case NODE_COMPOUND: {
|
||||
int index = -1;
|
||||
|
||||
//for both, stored as an array
|
||||
LiteralArray* store = ALLOCATE(LiteralArray, 1);
|
||||
initLiteralArray(store);
|
||||
|
||||
//emit an array or a dictionary definition
|
||||
if (node->compound.nodes->type == NODE_PAIR) {
|
||||
//ensure each literal key and value are in the cache, individually
|
||||
for (int i = 0; i < node->compound.count; i++) {
|
||||
//keys
|
||||
int key = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.left->atomic.literal);
|
||||
if (key < 0) {
|
||||
key = pushLiteralArray(&compiler->literalCache, node->compound.nodes[i].pair.left->atomic.literal);
|
||||
}
|
||||
|
||||
//values
|
||||
int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.right->atomic.literal);
|
||||
if (val < 0) {
|
||||
val = pushLiteralArray(&compiler->literalCache, node->compound.nodes[i].pair.right->atomic.literal);
|
||||
}
|
||||
|
||||
pushLiteralArray(store, TO_INTEGER_LITERAL(key));
|
||||
pushLiteralArray(store, TO_INTEGER_LITERAL(val));
|
||||
}
|
||||
|
||||
//push the store to the cache, with instructions about how pack it
|
||||
index = pushLiteralArray(&compiler->literalCache, TO_DICTIONARY_LITERAL(store));
|
||||
}
|
||||
else {
|
||||
//ensure each literal value is in the cache, individually
|
||||
for (int i = 0; i < node->compound.count; i++) {
|
||||
//values
|
||||
int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].atomic.literal);
|
||||
if (val < 0) {
|
||||
val = pushLiteralArray(&compiler->literalCache, node->compound.nodes[i].atomic.literal);
|
||||
}
|
||||
|
||||
pushLiteralArray(store, TO_INTEGER_LITERAL(val));
|
||||
}
|
||||
|
||||
//push the store to the cache, with instructions about how pack it
|
||||
index = pushLiteralArray(&compiler->literalCache, TO_ARRAY_LITERAL(store));
|
||||
}
|
||||
|
||||
//push the node opcode to the bytecode
|
||||
if (index >= 256) {
|
||||
//push a "long" index
|
||||
compiler->bytecode[compiler->count++] = OP_LITERAL_LONG; //1 byte
|
||||
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)index; //2 bytes
|
||||
|
||||
compiler->count += sizeof(unsigned short);
|
||||
}
|
||||
else {
|
||||
//push the index
|
||||
compiler->bytecode[compiler->count++] = OP_LITERAL; //1 byte
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)index; //1 byte
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_PAIR:
|
||||
fprintf(stderr, "[Internal] NODE_PAIR encountered in writeCompiler()");
|
||||
break;
|
||||
|
||||
case NODE_VAR_TYPES:
|
||||
//TODO: OP_TYPE_DECL
|
||||
break;
|
||||
@@ -221,6 +291,39 @@ unsigned char* collateCompiler(Compiler* compiler, int* size) {
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_ARRAY: {
|
||||
emitByte(&collation, &capacity, &count, LITERAL_ARRAY);
|
||||
|
||||
LiteralArray* ptr = AS_ARRAY(compiler->literalCache.literals[i]);
|
||||
|
||||
//length of the array, as a short
|
||||
emitShort(&collation, &capacity, &count, ptr->count);
|
||||
|
||||
//each element of the array
|
||||
for (int i = 0; i < ptr->count; i++) {
|
||||
emitShort(&collation, &capacity, &count, (unsigned short)AS_INTEGER(ptr->literals[i])); //shorts representing the indexes of the values
|
||||
}
|
||||
|
||||
freeLiteralArray(ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_DICTIONARY:
|
||||
emitByte(&collation, &capacity, &count, LITERAL_DICTIONARY);
|
||||
|
||||
LiteralArray* ptr = AS_ARRAY(compiler->literalCache.literals[i]); //used an array for storage above
|
||||
|
||||
//length of the array, as a short
|
||||
emitShort(&collation, &capacity, &count, ptr->count); //count is the array size, NOT the dictionary size
|
||||
|
||||
//each element of the array
|
||||
for (int i = 0; i < ptr->count; i++) {
|
||||
emitShort(&collation, &capacity, &count, (unsigned short)AS_INTEGER(ptr->literals[i])); //shorts representing the indexes of the values
|
||||
}
|
||||
|
||||
freeLiteralArray(ptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "[Internal] Unknown literal type encountered within literal cache\n");
|
||||
return NULL;
|
||||
|
||||
@@ -306,6 +306,11 @@ static void execInterpreter(Interpreter* interpreter) {
|
||||
}
|
||||
|
||||
void runInterpreter(Interpreter* interpreter) {
|
||||
if (!interpreter->bytecode) {
|
||||
printf(ERROR "Error: No valid bytecode given\n" RESET);
|
||||
return;
|
||||
}
|
||||
|
||||
//header section
|
||||
const unsigned char major = readByte(interpreter->bytecode, &interpreter->count);
|
||||
const unsigned char minor = readByte(interpreter->bytecode, &interpreter->count);
|
||||
@@ -385,6 +390,53 @@ void runInterpreter(Interpreter* interpreter) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_ARRAY: {
|
||||
LiteralArray* array = ALLOCATE(LiteralArray, 1);
|
||||
initLiteralArray(array);
|
||||
|
||||
unsigned short length = readShort(interpreter->bytecode, &interpreter->count);
|
||||
|
||||
//read each index, then unpack the value from the existing literal cache
|
||||
for (int i = 0; i < length; i++) {
|
||||
int index = readShort(interpreter->bytecode, &interpreter->count);
|
||||
pushLiteralArray(array, interpreter->literalCache.literals[index]);
|
||||
}
|
||||
|
||||
if (command.verbose) {
|
||||
printf("(array ");
|
||||
printLiteral(TO_ARRAY_LITERAL(array));
|
||||
printf(")\n");
|
||||
}
|
||||
|
||||
//finally, push the array proper
|
||||
pushLiteralArray(&interpreter->literalCache, TO_ARRAY_LITERAL(array));
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_DICTIONARY: {
|
||||
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
|
||||
initLiteralDictionary(dictionary);
|
||||
|
||||
unsigned short length = readShort(interpreter->bytecode, &interpreter->count);
|
||||
|
||||
//read each index, then unpack the value from the existing literal cache
|
||||
for (int i = 0; i < length / 2; i++) {
|
||||
int key = readShort(interpreter->bytecode, &interpreter->count);
|
||||
int val = readShort(interpreter->bytecode, &interpreter->count);
|
||||
setLiteralDictionary(dictionary, interpreter->literalCache.literals[key], interpreter->literalCache.literals[val]);
|
||||
}
|
||||
|
||||
if (command.verbose) {
|
||||
printf("(dictionary ");
|
||||
printLiteral(TO_DICTIONARY_LITERAL(dictionary));
|
||||
printf(")\n");
|
||||
}
|
||||
|
||||
//finally, push the dictionary proper
|
||||
pushLiteralArray(&interpreter->literalCache, TO_DICTIONARY_LITERAL(dictionary));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ static void eatWhitespace(Lexer* lexer) {
|
||||
advance(lexer);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
|
||||
107
source/literal.c
107
source/literal.c
@@ -1,13 +1,35 @@
|
||||
#include "literal.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include "literal_array.h"
|
||||
#include "literal_dictionary.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
//utils
|
||||
static void stdoutWrapper(const char* output) {
|
||||
fprintf(stdout, output);
|
||||
}
|
||||
|
||||
//buffer the prints
|
||||
static char* globalPrintBuffer = NULL;
|
||||
static size_t globalPrintCapacity = 0;
|
||||
static size_t globalPrintCount = 0;
|
||||
|
||||
static void printToBuffer(const char* str) {
|
||||
while (strlen(str) + globalPrintCount > globalPrintCapacity) {
|
||||
int oldCapacity = globalPrintCapacity;
|
||||
|
||||
globalPrintCapacity = GROW_CAPACITY(globalPrintCapacity);
|
||||
globalPrintBuffer = GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity);
|
||||
}
|
||||
|
||||
snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str);
|
||||
globalPrintCount += strlen(str);
|
||||
}
|
||||
|
||||
//exposed functions
|
||||
void printLiteral(Literal literal) {
|
||||
printLiteralCustom(literal, stdoutWrapper);
|
||||
}
|
||||
@@ -37,12 +59,93 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
||||
break;
|
||||
|
||||
case LITERAL_STRING: {
|
||||
char buffer[256];
|
||||
snprintf(buffer, 256, "%.*s", STRLEN(literal), AS_STRING(literal));
|
||||
char buffer[4096];
|
||||
snprintf(buffer, 4096, "\"%.*s\"", STRLEN(literal), AS_STRING(literal));
|
||||
printFn(buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_ARRAY: {
|
||||
LiteralArray* ptr = AS_ARRAY(literal);
|
||||
|
||||
//hold potential parent-call buffers
|
||||
char* cacheBuffer = globalPrintBuffer;
|
||||
globalPrintBuffer = NULL;
|
||||
int cacheCapacity = globalPrintCapacity;
|
||||
globalPrintCapacity = 0;
|
||||
int cacheCount = globalPrintCount;
|
||||
globalPrintCount = 0;
|
||||
|
||||
//print the contents to the global buffer
|
||||
printToBuffer("[");
|
||||
for (int i = 0; i < ptr->count; i++) {
|
||||
printLiteralCustom(ptr->literals[i], printToBuffer);
|
||||
|
||||
if (i + 1 < ptr->count) {
|
||||
printToBuffer(",");
|
||||
}
|
||||
}
|
||||
printToBuffer("]");
|
||||
|
||||
//swap the parent-call buffer back into place
|
||||
char* printBuffer = globalPrintBuffer;
|
||||
int printCapacity = globalPrintCapacity;
|
||||
int printCount = globalPrintCount;
|
||||
|
||||
globalPrintBuffer = cacheBuffer;
|
||||
globalPrintCapacity = cacheCapacity;
|
||||
globalPrintCount = cacheCount;
|
||||
|
||||
//finally, output and cleanup
|
||||
printFn(printBuffer);
|
||||
FREE_ARRAY(char, printBuffer, printCapacity);
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_DICTIONARY: {
|
||||
LiteralDictionary* ptr = AS_DICTIONARY(literal);
|
||||
|
||||
//hold potential parent-call buffers
|
||||
char* cacheBuffer = globalPrintBuffer;
|
||||
globalPrintBuffer = NULL;
|
||||
int cacheCapacity = globalPrintCapacity;
|
||||
globalPrintCapacity = 0;
|
||||
int cacheCount = globalPrintCount;
|
||||
globalPrintCount = 0;
|
||||
|
||||
//print the contents to the global buffer
|
||||
int delimCount = 0;
|
||||
printToBuffer("[");
|
||||
for (int i = 0; i < ptr->capacity; i++) {
|
||||
if (ptr->entries[i].key.type == LITERAL_NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (delimCount++ > 0) {
|
||||
printToBuffer(",");
|
||||
}
|
||||
|
||||
printLiteralCustom(ptr->entries[i].key, printToBuffer);
|
||||
printToBuffer(":");
|
||||
printLiteralCustom(ptr->entries[i].value, printToBuffer);
|
||||
}
|
||||
printToBuffer("]");
|
||||
|
||||
//swap the parent-call buffer back into place
|
||||
char* printBuffer = globalPrintBuffer;
|
||||
int printCapacity = globalPrintCapacity;
|
||||
int printCount = globalPrintCount;
|
||||
|
||||
globalPrintBuffer = cacheBuffer;
|
||||
globalPrintCapacity = cacheCapacity;
|
||||
globalPrintCount = cacheCount;
|
||||
|
||||
//finally, output and cleanup
|
||||
printFn(printBuffer);
|
||||
FREE_ARRAY(char, printBuffer, printCapacity);
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_IDENTIFIER: {
|
||||
char buffer[256];
|
||||
snprintf(buffer, 256, "%.*s", STRLEN_I(literal), AS_IDENTIFIER(literal));
|
||||
|
||||
@@ -10,10 +10,11 @@ typedef enum {
|
||||
LITERAL_INTEGER,
|
||||
LITERAL_FLOAT,
|
||||
LITERAL_STRING,
|
||||
// LITERAL_ARRAY,
|
||||
// LITERAL_DICTIONARY,
|
||||
LITERAL_ARRAY,
|
||||
LITERAL_DICTIONARY,
|
||||
// LITERAL_FUNCTION,
|
||||
LITERAL_IDENTIFIER,
|
||||
// LITERAL_TYPE,
|
||||
} LiteralType;
|
||||
|
||||
typedef struct {
|
||||
@@ -27,15 +28,17 @@ typedef struct {
|
||||
int length;
|
||||
} string;
|
||||
|
||||
// //experimental
|
||||
// void* array;
|
||||
// void* dictionary;
|
||||
void* array;
|
||||
void* dictionary;
|
||||
|
||||
// void* function;
|
||||
|
||||
struct { //for variable names
|
||||
char* ptr;
|
||||
int length;
|
||||
} identifier;
|
||||
|
||||
//TODO: type
|
||||
} as;
|
||||
} Literal;
|
||||
|
||||
@@ -53,8 +56,8 @@ typedef struct {
|
||||
#define AS_INTEGER(value) ((value).as.integer)
|
||||
#define AS_FLOAT(value) ((value).as.number)
|
||||
#define AS_STRING(value) ((value).as.string.ptr)
|
||||
// #define AS_ARRAY(value)
|
||||
// #define AS_DICTIONARY(value)
|
||||
#define AS_ARRAY(value) ((value).as.array)
|
||||
#define AS_DICTIONARY(value) ((value).as.dictionary)
|
||||
// #define AS_FUNCTION(value)
|
||||
#define AS_IDENTIFIER(value) ((value).as.identifier.ptr)
|
||||
|
||||
@@ -63,8 +66,8 @@ typedef struct {
|
||||
#define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }})
|
||||
#define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }})
|
||||
#define TO_STRING_LITERAL(value) _toStringLiteral(value)
|
||||
// #define TO_ARRAY_LITERAL
|
||||
// #define TO_DICTIONARY_LITERAL
|
||||
#define TO_ARRAY_LITERAL(value) ((Literal){LITERAL_ARRAY, { .array = value }})
|
||||
#define TO_DICTIONARY_LITERAL(value) ((Literal){LITERAL_DICTIONARY, { .dictionary = value }})
|
||||
// #define TO_FUNCTION_LITERAL
|
||||
#define TO_IDENTIFIER_LITERAL(value) _toIdentifierLiteral(value)
|
||||
|
||||
|
||||
@@ -37,14 +37,26 @@ void freeNode(Node* node) {
|
||||
for (int i = 0; i < node->block.count; i++) {
|
||||
freeNode(node->block.nodes + i);
|
||||
}
|
||||
//each sub-node gets freed individually
|
||||
FREE_ARRAY(Node, node->block.nodes, node->block.capacity);
|
||||
break;
|
||||
|
||||
case NODE_COMPOUND:
|
||||
for (int i = 0; i < node->compound.count; i++) {
|
||||
freeNode(node->compound.nodes + i);
|
||||
}
|
||||
FREE_ARRAY(Node, node->compound.nodes, node->compound.capacity);
|
||||
break;
|
||||
|
||||
case NODE_PAIR:
|
||||
freeNode(node->pair.left);
|
||||
freeNode(node->pair.right);
|
||||
break;
|
||||
|
||||
case NODE_VAR_TYPES:
|
||||
for (int i = 0; i < node->varTypes.count; i++) {
|
||||
freeNode(node->varTypes.nodes + 1);
|
||||
}
|
||||
//each sub-node gets freed individually
|
||||
FREE_ARRAY(Node, node->varTypes.nodes, node->varTypes.capacity);
|
||||
break;
|
||||
|
||||
case NODE_VAR_DECL:
|
||||
@@ -53,8 +65,6 @@ void freeNode(Node* node) {
|
||||
freeNode(node->varDecl.expression);
|
||||
break;
|
||||
}
|
||||
|
||||
FREE(Node, node);
|
||||
}
|
||||
|
||||
void emitNodeLiteral(Node** nodeHandle, Literal literal) {
|
||||
@@ -105,6 +115,27 @@ void emitNodeBlock(Node** nodeHandle) {
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
void emitNodeCompound(Node** nodeHandle) {
|
||||
Node* tmp = ALLOCATE(Node, 1);
|
||||
|
||||
tmp->type = NODE_COMPOUND;
|
||||
tmp->compound.nodes = NULL;
|
||||
tmp->compound.capacity = 0;
|
||||
tmp->compound.count = 0;
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
void emitNodePair(Node** nodeHandle, Node* left, Node* right) {
|
||||
Node* tmp = ALLOCATE(Node, 1);
|
||||
|
||||
tmp->type = NODE_PAIR;
|
||||
tmp->pair.left = left;
|
||||
tmp->pair.right = right;
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
void emitNodeVarTypes(Node** nodeHandle, unsigned char mask) {
|
||||
Node* tmp = ALLOCATE(Node, 1);
|
||||
|
||||
@@ -172,8 +203,26 @@ void printNode(Node* node) {
|
||||
printf("}\n");
|
||||
break;
|
||||
|
||||
case NODE_COMPOUND:
|
||||
printf("compound[\n");
|
||||
|
||||
for (int i = 0; i < node->compound.count; i++) {
|
||||
printNode(&(node->compound.nodes[i]));
|
||||
}
|
||||
|
||||
printf("]\n");
|
||||
break;
|
||||
|
||||
case NODE_PAIR:
|
||||
printf("pair-left:");
|
||||
printNode(node->pair.left);
|
||||
printf(";pair-right:");
|
||||
printNode(node->pair.right);
|
||||
printf(";");
|
||||
break;
|
||||
|
||||
case NODE_VAR_TYPES:
|
||||
printf("[\n");
|
||||
printf("type[\n");
|
||||
|
||||
for (int i = 0; i < node->varTypes.count; i++) {
|
||||
printNode(&(node->varTypes.nodes[i]));
|
||||
|
||||
@@ -9,10 +9,12 @@ typedef union _node Node;
|
||||
typedef enum NodeType {
|
||||
NODE_ERROR,
|
||||
NODE_LITERAL, //a simple value
|
||||
NODE_UNARY, //one child
|
||||
NODE_BINARY, //two children, left and right
|
||||
NODE_UNARY, //one child + opcode
|
||||
NODE_BINARY, //two children, left and right + opcode
|
||||
NODE_GROUPING, //one child
|
||||
NODE_BLOCK, //contains sub-node array
|
||||
NODE_BLOCK, //contains a sub-node array
|
||||
NODE_COMPOUND, //contains a sub-node array
|
||||
NODE_PAIR, //contains a left and right
|
||||
NODE_VAR_TYPES, //contains a type mask and a sub-node array for compound types
|
||||
NODE_VAR_DECL, //contains identifier literal, typenode, expression definition
|
||||
// NODE_CONDITIONAL, //three children: conditional, then path, else path
|
||||
@@ -48,6 +50,19 @@ typedef struct NodeBlock {
|
||||
int count;
|
||||
} NodeBlock;
|
||||
|
||||
typedef struct NodeCompound {
|
||||
NodeType type;
|
||||
Node* nodes;
|
||||
int capacity;
|
||||
int count;
|
||||
} NodeCompound;
|
||||
|
||||
typedef struct NodePair {
|
||||
NodeType type;
|
||||
Node* left;
|
||||
Node* right;
|
||||
} NodePair;
|
||||
|
||||
typedef struct NodeVarTypes {
|
||||
NodeType type;
|
||||
unsigned char mask;
|
||||
@@ -70,6 +85,8 @@ union _node {
|
||||
NodeBinary binary;
|
||||
NodeGrouping grouping;
|
||||
NodeBlock block;
|
||||
NodeCompound compound;
|
||||
NodePair pair;
|
||||
NodeVarTypes varTypes;
|
||||
NodeVarDecl varDecl;
|
||||
};
|
||||
@@ -80,6 +97,8 @@ void emitNodeUnary(Node** nodeHandle, Opcode opcode);
|
||||
void emitNodeBinary(Node** nodeHandle, Node* rhs, Opcode opcode);
|
||||
void emitNodeGrouping(Node** nodeHandle);
|
||||
void emitNodeBlock(Node** nodeHandle);
|
||||
void emitNodeCompound(Node** nodeHandle);
|
||||
void emitNodePair(Node** nodeHandle, Node* left, Node* right);
|
||||
void emitNodeVarTypes(Node** nodeHandle, unsigned char mask);
|
||||
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Node* varType, Node* expression);
|
||||
|
||||
|
||||
111
source/parser.c
111
source/parser.c
@@ -36,6 +36,7 @@ static void advance(Parser* parser) {
|
||||
|
||||
if (parser->current.type == TOKEN_ERROR) {
|
||||
error(parser, parser->current, "Lexer error");
|
||||
printf(parser->lexer->source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +116,106 @@ static void declaration(Parser* parser, Node** nodeHandle);
|
||||
static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule);
|
||||
|
||||
//the expression rules
|
||||
static Opcode compound(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
//read either an array or a dictionary into a literal node
|
||||
|
||||
int iterations = 0; //count the number of entries iterated over
|
||||
|
||||
//compound nodes to store what is read
|
||||
Node* array = NULL;
|
||||
Node* dictionary = NULL;
|
||||
|
||||
while (!match(parser, TOKEN_BRACKET_RIGHT)) {
|
||||
//if empty dictionary, there will be a colon between the brackets
|
||||
if (iterations == 0 && match(parser, TOKEN_COLON)) {
|
||||
consume(parser, TOKEN_BRACE_RIGHT, "Expected ']' at the end of empty dictionary definition");
|
||||
break;
|
||||
}
|
||||
|
||||
if (iterations > 0) {
|
||||
consume(parser, TOKEN_COMMA, "Expected ',' in array or dictionary");
|
||||
}
|
||||
|
||||
iterations++;
|
||||
|
||||
Node* left = NULL;
|
||||
Node* right = NULL;
|
||||
|
||||
//store the left
|
||||
parsePrecedence(parser, &left, PREC_PRIMARY);
|
||||
|
||||
//detect a dictionary
|
||||
if (match(parser, TOKEN_COLON)) {
|
||||
parsePrecedence(parser, &right, PREC_PRIMARY);
|
||||
|
||||
//check we ARE defining a dictionary
|
||||
if (array) {
|
||||
error(parser, parser->previous, "Incorrect detection between array and dictionary");
|
||||
freeNode(array);
|
||||
return OP_EOF;
|
||||
}
|
||||
|
||||
//init the dictionary
|
||||
if (!dictionary) {
|
||||
emitNodeCompound(&dictionary);
|
||||
}
|
||||
|
||||
//grow the node if needed
|
||||
if (dictionary->compound.capacity < dictionary->compound.count + 1) {
|
||||
int oldCapacity = dictionary->compound.capacity;
|
||||
|
||||
dictionary->compound.capacity = GROW_CAPACITY(oldCapacity);
|
||||
dictionary->compound.nodes = GROW_ARRAY(Node, dictionary->compound.nodes, oldCapacity, dictionary->compound.capacity);
|
||||
}
|
||||
|
||||
//store the left and right in the node
|
||||
Node* pair = NULL;
|
||||
emitNodePair(&pair, left, right);
|
||||
dictionary->compound.nodes[dictionary->compound.count++] = *pair;
|
||||
}
|
||||
//detect an array
|
||||
else {
|
||||
//check we ARE defining an array
|
||||
if (dictionary) {
|
||||
error(parser, parser->current, "Incorrect detection between array and dictionary");
|
||||
freeNode(dictionary);
|
||||
return OP_EOF;
|
||||
}
|
||||
|
||||
//init the array
|
||||
if (!array) {
|
||||
emitNodeCompound(&array);
|
||||
}
|
||||
|
||||
//grow the node if needed
|
||||
if (array->compound.capacity < array->compound.count + 1) {
|
||||
int oldCapacity = array->compound.capacity;
|
||||
|
||||
array->compound.capacity = GROW_CAPACITY(oldCapacity);
|
||||
array->compound.nodes = GROW_ARRAY(Node, array->compound.nodes, oldCapacity, array->compound.capacity);
|
||||
}
|
||||
|
||||
//store the left in the array
|
||||
array->compound.nodes[array->compound.count++] = *left;
|
||||
}
|
||||
}
|
||||
|
||||
//save the result
|
||||
if (array) {
|
||||
(*nodeHandle) = array;
|
||||
}
|
||||
else if (dictionary) {
|
||||
(*nodeHandle) = dictionary;
|
||||
}
|
||||
else {
|
||||
error(parser, parser->current, "[internal] Couldn't determine if should save an array or dictionary");
|
||||
}
|
||||
|
||||
|
||||
//ignored
|
||||
return OP_EOF;
|
||||
}
|
||||
|
||||
static Opcode string(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
//handle strings
|
||||
switch(parser->previous.type) {
|
||||
@@ -330,7 +431,7 @@ ParseRule parseRules[] = { //must match the token types
|
||||
//logical operators
|
||||
{grouping, NULL, PREC_CALL},// TOKEN_PAREN_LEFT,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_PAREN_RIGHT,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_BRACKET_LEFT,
|
||||
{compound, NULL, 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,
|
||||
@@ -348,7 +449,7 @@ ParseRule parseRules[] = { //must match the token types
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_ASSIGN,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_COLON,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_SEMICOLON,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_COMMA,
|
||||
{NULL, NULL, PREC_CALL},// TOKEN_COMMA,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_DOT,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_PIPE,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_REST,
|
||||
@@ -570,9 +671,9 @@ static void assertStmt(Parser* parser, Node* node) {
|
||||
node->type = NODE_BINARY;
|
||||
node->unary.opcode = OP_ASSERT;
|
||||
|
||||
expression(parser, &(node->binary.left));
|
||||
parsePrecedence(parser, &(node->binary.left), PREC_PRIMARY);
|
||||
consume(parser, TOKEN_COMMA, "Expected ',' in assert statement");
|
||||
expression(parser, &(node->binary.right));
|
||||
parsePrecedence(parser, &(node->binary.right), PREC_PRIMARY);
|
||||
|
||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of assert statement");
|
||||
}
|
||||
@@ -607,7 +708,7 @@ static void statement(Parser* parser, Node* node) {
|
||||
|
||||
//declarations and definitions
|
||||
static void readVarType(Parser* parser, Node** nodeHandle) {
|
||||
//TODO: compound types with the "type" keyword
|
||||
//TODO: custom types with the "type" keyword
|
||||
advance(parser);
|
||||
|
||||
unsigned char typeMask = 0;
|
||||
|
||||
@@ -25,7 +25,7 @@ char* readFile(char* path, size_t* fileSize) {
|
||||
*fileSize = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
char* buffer = (char*)malloc(*fileSize);
|
||||
char* buffer = (char*)malloc(*fileSize + 1);
|
||||
|
||||
if (buffer == NULL) {
|
||||
fprintf(stderr, "Not enough memory to read \"%s\"\n", path);
|
||||
@@ -34,6 +34,8 @@ char* readFile(char* path, size_t* fileSize) {
|
||||
|
||||
size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file);
|
||||
|
||||
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
|
||||
|
||||
if (bytesRead < *fileSize) {
|
||||
fprintf(stderr, "Could not read file \"%s\"\n", path);
|
||||
exit(-1);
|
||||
@@ -109,13 +111,19 @@ void runBinary(unsigned char* tb, size_t size) {
|
||||
void runBinaryFile(char* fname) {
|
||||
size_t size = 0; //not used
|
||||
unsigned char* tb = (unsigned char*)readFile(fname, &size);
|
||||
if (!tb) {
|
||||
return;
|
||||
}
|
||||
runBinary(tb, size);
|
||||
//interpreter takes ownership of the binary data
|
||||
}
|
||||
|
||||
void runSource(char* source) {
|
||||
size_t size;
|
||||
size_t size = 0;
|
||||
unsigned char* tb = compileString(source, &size);
|
||||
if (!tb) {
|
||||
return;
|
||||
}
|
||||
runBinary(tb, size);
|
||||
}
|
||||
|
||||
@@ -169,11 +177,11 @@ void repl() {
|
||||
int size = 0;
|
||||
unsigned char* tb = collateCompiler(&compiler, &size);
|
||||
|
||||
// for (int i = 0; i < size; i++) {
|
||||
// printf("%d ", tb[i]);
|
||||
// }
|
||||
for (int i = 0; i < size; i++) {
|
||||
printf("%d ", tb[i]);
|
||||
}
|
||||
|
||||
// printf("\n");
|
||||
printf("\n");
|
||||
|
||||
//run the bytecode
|
||||
initInterpreter(&interpreter, tb, size);
|
||||
|
||||
Reference in New Issue
Block a user