mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
WE ARE THE CHAMPIONS!
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
void freeNode(Node* node) {
|
void freeNodeCustom(Node* node, bool freeSelf) {
|
||||||
//don't free a NULL node
|
//don't free a NULL node
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
return;
|
return;
|
||||||
@@ -35,14 +35,14 @@ void freeNode(Node* node) {
|
|||||||
|
|
||||||
case NODE_BLOCK:
|
case NODE_BLOCK:
|
||||||
for (int i = 0; i < node->block.count; i++) {
|
for (int i = 0; i < node->block.count; i++) {
|
||||||
freeNode(node->block.nodes + i);
|
freeNodeCustom(node->block.nodes + i, false);
|
||||||
}
|
}
|
||||||
FREE_ARRAY(Node, node->block.nodes, node->block.capacity);
|
FREE_ARRAY(Node, node->block.nodes, node->block.capacity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_COMPOUND:
|
case NODE_COMPOUND:
|
||||||
for (int i = 0; i < node->compound.count; i++) {
|
for (int i = 0; i < node->compound.count; i++) {
|
||||||
freeNode(node->compound.nodes + i);
|
freeNodeCustom(node->compound.nodes + i, false);
|
||||||
}
|
}
|
||||||
FREE_ARRAY(Node, node->compound.nodes, node->compound.capacity);
|
FREE_ARRAY(Node, node->compound.nodes, node->compound.capacity);
|
||||||
break;
|
break;
|
||||||
@@ -67,7 +67,7 @@ void freeNode(Node* node) {
|
|||||||
|
|
||||||
case NODE_FN_COLLECTION:
|
case NODE_FN_COLLECTION:
|
||||||
for (int i = 0; i < node->fnCollection.count; i++) {
|
for (int i = 0; i < node->fnCollection.count; i++) {
|
||||||
freeNode(node->fnCollection.nodes + i);
|
freeNodeCustom(node->fnCollection.nodes + i, false);
|
||||||
}
|
}
|
||||||
FREE_ARRAY(Node, node->fnCollection.nodes, node->fnCollection.capacity);
|
FREE_ARRAY(Node, node->fnCollection.nodes, node->fnCollection.capacity);
|
||||||
break;
|
break;
|
||||||
@@ -94,6 +94,14 @@ void freeNode(Node* node) {
|
|||||||
freeLiteral(node->increment.identifier);
|
freeLiteral(node->increment.identifier);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (freeSelf) {
|
||||||
|
FREE(Node, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeNode(Node* node) {
|
||||||
|
freeNodeCustom(node, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitNodeLiteral(Node** nodeHandle, Literal literal) {
|
void emitNodeLiteral(Node** nodeHandle, Literal literal) {
|
||||||
@@ -101,7 +109,7 @@ void emitNodeLiteral(Node** nodeHandle, Literal literal) {
|
|||||||
*nodeHandle = ALLOCATE(Node, 1);
|
*nodeHandle = ALLOCATE(Node, 1);
|
||||||
|
|
||||||
(*nodeHandle)->type = NODE_LITERAL;
|
(*nodeHandle)->type = NODE_LITERAL;
|
||||||
(*nodeHandle)->atomic.literal = literal;
|
(*nodeHandle)->atomic.literal = copyLiteral(literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitNodeUnary(Node** nodeHandle, Opcode opcode, Node* child) {
|
void emitNodeUnary(Node** nodeHandle, Opcode opcode, Node* child) {
|
||||||
@@ -156,14 +164,11 @@ void emitNodeCompound(Node** nodeHandle, LiteralType literalType) {
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitNodePair(Node** nodeHandle, Node* left, Node* right) {
|
void setNodePair(Node* node, Node* left, Node* right) {
|
||||||
Node* tmp = ALLOCATE(Node, 1);
|
//assume the node has already been allocated
|
||||||
|
node->type = NODE_PAIR;
|
||||||
tmp->type = NODE_PAIR;
|
node->pair.left = left;
|
||||||
tmp->pair.left = left;
|
node->pair.right = right;
|
||||||
tmp->pair.right = right;
|
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal typeLiteral, Node* expression) {
|
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal typeLiteral, Node* expression) {
|
||||||
@@ -226,7 +231,7 @@ void emitNodePrefixIncrement(Node** nodeHandle, Literal identifier, int incremen
|
|||||||
Node* tmp = ALLOCATE(Node, 1);
|
Node* tmp = ALLOCATE(Node, 1);
|
||||||
|
|
||||||
tmp->type = NODE_INCREMENT_PREFIX;
|
tmp->type = NODE_INCREMENT_PREFIX;
|
||||||
tmp->increment.identifier = identifier;
|
tmp->increment.identifier = copyLiteral(identifier);
|
||||||
tmp->increment.increment = increment;
|
tmp->increment.increment = increment;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
@@ -236,7 +241,7 @@ void emitNodePostfixIncrement(Node** nodeHandle, Literal identifier, int increme
|
|||||||
Node* tmp = ALLOCATE(Node, 1);
|
Node* tmp = ALLOCATE(Node, 1);
|
||||||
|
|
||||||
tmp->type = NODE_INCREMENT_POSTFIX;
|
tmp->type = NODE_INCREMENT_POSTFIX;
|
||||||
tmp->increment.identifier = identifier;
|
tmp->increment.identifier = copyLiteral(identifier);
|
||||||
tmp->increment.increment = increment;
|
tmp->increment.increment = increment;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ void emitNodeBinary(Node** nodeHandle, Node* rhs, Opcode opcode); //handled node
|
|||||||
void emitNodeGrouping(Node** nodeHandle);
|
void emitNodeGrouping(Node** nodeHandle);
|
||||||
void emitNodeBlock(Node** nodeHandle);
|
void emitNodeBlock(Node** nodeHandle);
|
||||||
void emitNodeCompound(Node** nodeHandle, LiteralType literalType);
|
void emitNodeCompound(Node** nodeHandle, LiteralType literalType);
|
||||||
void emitNodePair(Node** nodeHandle, Node* left, Node* right);
|
void setNodePair(Node* node, Node* left, Node* right);
|
||||||
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal type, Node* expression);
|
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal type, Node* expression);
|
||||||
void emitNodeFnDecl(Node** nodeHandle, Literal identifier, Node* arguments, Node* returns, Node* block);
|
void emitNodeFnDecl(Node** nodeHandle, Literal identifier, Node* arguments, Node* returns, Node* block);
|
||||||
void emitFnCall(Node** nodeHandle, Node* arguments);
|
void emitFnCall(Node** nodeHandle, Node* arguments);
|
||||||
|
|||||||
114
source/parser.c
114
source/parser.c
@@ -125,6 +125,8 @@ static Opcode forceType(Parser* parser, Node** nodeHandle) {
|
|||||||
|
|
||||||
emitNodeLiteral(nodeHandle, literal);
|
emitNodeLiteral(nodeHandle, literal);
|
||||||
|
|
||||||
|
freeLiteral(literal);
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,9 +194,7 @@ static Opcode compound(Parser* parser, Node** nodeHandle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//store the left and right in the node
|
//store the left and right in the node
|
||||||
Node* pair = NULL;
|
setNodePair(&dictionary->compound.nodes[dictionary->compound.count++], left, right);
|
||||||
emitNodePair(&pair, left, right);
|
|
||||||
dictionary->compound.nodes[dictionary->compound.count++] = *pair;
|
|
||||||
}
|
}
|
||||||
//detect an array
|
//detect an array
|
||||||
else {
|
else {
|
||||||
@@ -218,8 +218,9 @@ static Opcode compound(Parser* parser, Node** nodeHandle) {
|
|||||||
array->compound.nodes = GROW_ARRAY(Node, array->compound.nodes, oldCapacity, array->compound.capacity);
|
array->compound.nodes = GROW_ARRAY(Node, array->compound.nodes, oldCapacity, array->compound.capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
//store the left in the array
|
//copy into the array, and manually free the temp node
|
||||||
array->compound.nodes[array->compound.count++] = *left;
|
array->compound.nodes[array->compound.count++] = *left;
|
||||||
|
FREE(Node, left);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +256,9 @@ static Opcode string(Parser* parser, Node** nodeHandle) {
|
|||||||
error(parser, parser->previous, buffer);
|
error(parser, parser->previous, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitNodeLiteral(nodeHandle, TO_STRING_LITERAL(copyString(parser->previous.lexeme, length), length));
|
Literal literal = TO_STRING_LITERAL(copyString(parser->previous.lexeme, length), length);
|
||||||
|
emitNodeLiteral(nodeHandle, literal);
|
||||||
|
freeLiteral(literal);
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,29 +515,43 @@ static Opcode identifier(Parser* parser, Node** nodeHandle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* cpy = copyString(identifierToken.lexeme, length);
|
char* cpy = copyString(identifierToken.lexeme, length);
|
||||||
Literal identifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
|
Literal identifier = _toIdentifierLiteral(cpy, length); //BUGFIX: use this instead of the macro
|
||||||
|
|
||||||
emitNodeLiteral(nodeHandle, identifier);
|
emitNodeLiteral(nodeHandle, identifier);
|
||||||
|
|
||||||
|
freeLiteral(identifier); //don't leave it hanging
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Opcode castingPrefix(Parser* parser, Node** nodeHandle) {
|
static Opcode castingPrefix(Parser* parser, Node** nodeHandle) {
|
||||||
switch(parser->previous.type) {
|
switch(parser->previous.type) {
|
||||||
case TOKEN_BOOLEAN:
|
case TOKEN_BOOLEAN: {
|
||||||
emitNodeLiteral(nodeHandle, TO_TYPE_LITERAL(LITERAL_BOOLEAN, false));
|
Literal literal = TO_TYPE_LITERAL(LITERAL_BOOLEAN, false);
|
||||||
|
emitNodeLiteral(nodeHandle, literal);
|
||||||
|
freeLiteral(literal);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOKEN_INTEGER:
|
case TOKEN_INTEGER: {
|
||||||
emitNodeLiteral(nodeHandle, TO_TYPE_LITERAL(LITERAL_INTEGER, false));
|
Literal literal = TO_TYPE_LITERAL(LITERAL_INTEGER, false);
|
||||||
|
emitNodeLiteral(nodeHandle, literal);
|
||||||
|
freeLiteral(literal);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOKEN_FLOAT:
|
case TOKEN_FLOAT: {
|
||||||
emitNodeLiteral(nodeHandle, TO_TYPE_LITERAL(LITERAL_FLOAT, false));
|
Literal literal = TO_TYPE_LITERAL(LITERAL_FLOAT, false);
|
||||||
|
emitNodeLiteral(nodeHandle, literal);
|
||||||
|
freeLiteral(literal);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOKEN_STRING:
|
case TOKEN_STRING: {
|
||||||
emitNodeLiteral(nodeHandle, TO_TYPE_LITERAL(LITERAL_STRING, false));
|
Literal literal = TO_TYPE_LITERAL(LITERAL_STRING, false);
|
||||||
|
emitNodeLiteral(nodeHandle, literal);
|
||||||
|
freeLiteral(literal);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -586,6 +603,8 @@ static Opcode incrementPrefix(Parser* parser, Node** nodeHandle) {
|
|||||||
|
|
||||||
emitNodePrefixIncrement(nodeHandle, node->atomic.literal, 1);
|
emitNodePrefixIncrement(nodeHandle, node->atomic.literal, 1);
|
||||||
|
|
||||||
|
freeNode(node);
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -597,6 +616,8 @@ static Opcode incrementInfix(Parser* parser, Node** nodeHandle) {
|
|||||||
|
|
||||||
emitNodePostfixIncrement(nodeHandle, node->atomic.literal, 1);
|
emitNodePostfixIncrement(nodeHandle, node->atomic.literal, 1);
|
||||||
|
|
||||||
|
freeNode(node);
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,10 +625,12 @@ static Opcode decrementPrefix(Parser* parser, Node** nodeHandle) {
|
|||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
Node* node = NULL;
|
Node* node = NULL;
|
||||||
identifier(parser, &node);
|
identifier(parser, &node); //weird
|
||||||
|
|
||||||
emitNodePrefixIncrement(nodeHandle, node->atomic.literal, -1);
|
emitNodePrefixIncrement(nodeHandle, node->atomic.literal, -1);
|
||||||
|
|
||||||
|
freeNode(node);
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,6 +642,8 @@ static Opcode decrementInfix(Parser* parser, Node** nodeHandle) {
|
|||||||
|
|
||||||
emitNodePostfixIncrement(nodeHandle, node->atomic.literal, -1);
|
emitNodePostfixIncrement(nodeHandle, node->atomic.literal, -1);
|
||||||
|
|
||||||
|
freeNode(node);
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,6 +672,7 @@ static Opcode fnCall(Parser* parser, Node** nodeHandle) {
|
|||||||
Node* node = NULL;
|
Node* node = NULL;
|
||||||
parsePrecedence(parser, &node, PREC_TERNARY);
|
parsePrecedence(parser, &node, PREC_TERNARY);
|
||||||
arguments->fnCollection.nodes[arguments->fnCollection.count++] = *node;
|
arguments->fnCollection.nodes[arguments->fnCollection.count++] = *node;
|
||||||
|
FREE(Node, node);
|
||||||
} while(match(parser, TOKEN_COMMA));
|
} while(match(parser, TOKEN_COMMA));
|
||||||
|
|
||||||
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of argument list");
|
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of argument list");
|
||||||
@@ -1007,21 +1033,14 @@ static void blockStmt(Parser* parser, Node** nodeHandle) {
|
|||||||
(*nodeHandle)->block.nodes = GROW_ARRAY(Node, (*nodeHandle)->block.nodes, oldCapacity, (*nodeHandle)->block.capacity);
|
(*nodeHandle)->block.nodes = GROW_ARRAY(Node, (*nodeHandle)->block.nodes, oldCapacity, (*nodeHandle)->block.capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
//use the next node in sequence
|
Node* node = NULL;
|
||||||
(*nodeHandle)->block.nodes[(*nodeHandle)->block.count].type = NODE_ERROR; //BUGFIX: so freeing won't break the damn thing
|
|
||||||
|
|
||||||
Node* ptr = &((*nodeHandle)->block.nodes[(*nodeHandle)->block.count]);
|
|
||||||
|
|
||||||
//process the grammar rule for this line
|
//process the grammar rule for this line
|
||||||
declaration(parser, &ptr);
|
declaration(parser, &node);
|
||||||
|
|
||||||
// //BUGFIX: if ptr has been re-assigned, copy the new value into the block's child
|
//BUGFIX: statements no longer require an existing node
|
||||||
// if (&((*nodeHandle)->block.nodes[(*nodeHandle)->block.count]) != ptr) {
|
((*nodeHandle)->block.nodes[(*nodeHandle)->block.count++]) = *node;
|
||||||
// ((*nodeHandle)->block.nodes[(*nodeHandle)->block.count]) = *ptr;
|
FREE(Node, node); //simply free the tmp node
|
||||||
// FREE(Node, ptr);
|
|
||||||
// }
|
|
||||||
|
|
||||||
(*nodeHandle)->block.count++;
|
|
||||||
|
|
||||||
// Ground floor: perfumery / Stationery and leather goods / Wigs and haberdashery / Kitchenware and food / Going up!
|
// Ground floor: perfumery / Stationery and leather goods / Wigs and haberdashery / Kitchenware and food / Going up!
|
||||||
if (parser->panic) {
|
if (parser->panic) {
|
||||||
@@ -1032,15 +1051,16 @@ static void blockStmt(Parser* parser, Node** nodeHandle) {
|
|||||||
|
|
||||||
static void printStmt(Parser* parser, Node** nodeHandle) {
|
static void printStmt(Parser* parser, Node** nodeHandle) {
|
||||||
//set the node info
|
//set the node info
|
||||||
(*nodeHandle)->type = NODE_UNARY;
|
Node* node = NULL;
|
||||||
(*nodeHandle)->unary.opcode = OP_PRINT;
|
expression(parser, &node);
|
||||||
expression(parser, &((*nodeHandle)->unary.child));
|
emitNodeUnary(nodeHandle, OP_PRINT, node);
|
||||||
|
|
||||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of print statement");
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of print statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void assertStmt(Parser* parser, Node** nodeHandle) {
|
static void assertStmt(Parser* parser, Node** nodeHandle) {
|
||||||
//set the node info
|
//set the node info
|
||||||
|
(*nodeHandle) = ALLOCATE(Node, 1); //special case, because I'm lazy
|
||||||
(*nodeHandle)->type = NODE_BINARY;
|
(*nodeHandle)->type = NODE_BINARY;
|
||||||
(*nodeHandle)->binary.opcode = OP_ASSERT;
|
(*nodeHandle)->binary.opcode = OP_ASSERT;
|
||||||
|
|
||||||
@@ -1062,16 +1082,13 @@ static void ifStmt(Parser* parser, Node** nodeHandle) {
|
|||||||
|
|
||||||
//read the then path
|
//read the then path
|
||||||
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of if clause");
|
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of if clause");
|
||||||
thenPath = ALLOCATE(Node, 1);
|
|
||||||
declaration(parser, &thenPath);
|
declaration(parser, &thenPath);
|
||||||
|
|
||||||
//read the optional else path
|
//read the optional else path
|
||||||
if (match(parser, TOKEN_ELSE)) {
|
if (match(parser, TOKEN_ELSE)) {
|
||||||
elsePath = ALLOCATE(Node, 1);
|
|
||||||
declaration(parser, &elsePath);
|
declaration(parser, &elsePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
freeNode(*nodeHandle); //free the initial node
|
|
||||||
emitNodePath(nodeHandle, NODE_PATH_IF, NULL, NULL, condition, thenPath, elsePath);
|
emitNodePath(nodeHandle, NODE_PATH_IF, NULL, NULL, condition, thenPath, elsePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1085,18 +1102,16 @@ static void whileStmt(Parser* parser, Node** nodeHandle) {
|
|||||||
|
|
||||||
//read the then path
|
//read the then path
|
||||||
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of while clause");
|
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of while clause");
|
||||||
thenPath = ALLOCATE(Node, 1);
|
|
||||||
declaration(parser, &thenPath);
|
declaration(parser, &thenPath);
|
||||||
|
|
||||||
freeNode(*nodeHandle); //free the initial node
|
|
||||||
emitNodePath(nodeHandle, NODE_PATH_WHILE, NULL, NULL, condition, thenPath, NULL);
|
emitNodePath(nodeHandle, NODE_PATH_WHILE, NULL, NULL, condition, thenPath, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void forStmt(Parser* parser, Node** nodeHandle) {
|
static void forStmt(Parser* parser, Node** nodeHandle) {
|
||||||
Node* preClause = ALLOCATE(Node, 1);
|
Node* preClause = NULL;
|
||||||
Node* postClause = NULL;
|
Node* postClause = NULL;
|
||||||
Node* condition = NULL;
|
Node* condition = NULL;
|
||||||
Node* thenPath = ALLOCATE(Node, 1);
|
Node* thenPath = NULL;
|
||||||
|
|
||||||
//read the clauses
|
//read the clauses
|
||||||
consume(parser, TOKEN_PAREN_LEFT, "Expected '(' at beginning of for clause");
|
consume(parser, TOKEN_PAREN_LEFT, "Expected '(' at beginning of for clause");
|
||||||
@@ -1110,22 +1125,18 @@ static void forStmt(Parser* parser, Node** nodeHandle) {
|
|||||||
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause");
|
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause");
|
||||||
|
|
||||||
//read the path
|
//read the path
|
||||||
thenPath = ALLOCATE(Node, 1);
|
|
||||||
declaration(parser, &thenPath);
|
declaration(parser, &thenPath);
|
||||||
|
|
||||||
freeNode(*nodeHandle); //free the initial node
|
|
||||||
emitNodePath(nodeHandle, NODE_PATH_FOR, preClause, postClause, condition, thenPath, NULL);
|
emitNodePath(nodeHandle, NODE_PATH_FOR, preClause, postClause, condition, thenPath, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void breakStmt(Parser* parser, Node** nodeHandle) {
|
static void breakStmt(Parser* parser, Node** nodeHandle) {
|
||||||
freeNode(*nodeHandle);
|
|
||||||
emitNodePath(nodeHandle, NODE_PATH_BREAK, NULL, NULL, NULL, NULL, NULL);
|
emitNodePath(nodeHandle, NODE_PATH_BREAK, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of break statement");
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of break statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void continueStmt(Parser* parser, Node** nodeHandle) {
|
static void continueStmt(Parser* parser, Node** nodeHandle) {
|
||||||
freeNode(*nodeHandle);
|
|
||||||
emitNodePath(nodeHandle, NODE_PATH_CONTINUE, NULL, NULL, NULL, NULL, NULL);
|
emitNodePath(nodeHandle, NODE_PATH_CONTINUE, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of continue statement");
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of continue statement");
|
||||||
@@ -1136,7 +1147,7 @@ static void returnStmt(Parser* parser, Node** nodeHandle) {
|
|||||||
emitNodeFnCollection(&returnValues);
|
emitNodeFnCollection(&returnValues);
|
||||||
|
|
||||||
if (!match(parser, TOKEN_SEMICOLON)) {
|
if (!match(parser, TOKEN_SEMICOLON)) {
|
||||||
do {
|
do { //loop for multiple returns (disabled later in the pipeline)
|
||||||
//append the node to the return list (grow the node if needed)
|
//append the node to the return list (grow the node if needed)
|
||||||
if (returnValues->fnCollection.capacity < returnValues->fnCollection.count + 1) {
|
if (returnValues->fnCollection.capacity < returnValues->fnCollection.count + 1) {
|
||||||
int oldCapacity = returnValues->fnCollection.capacity;
|
int oldCapacity = returnValues->fnCollection.capacity;
|
||||||
@@ -1149,12 +1160,12 @@ static void returnStmt(Parser* parser, Node** nodeHandle) {
|
|||||||
parsePrecedence(parser, &node, PREC_TERNARY);
|
parsePrecedence(parser, &node, PREC_TERNARY);
|
||||||
|
|
||||||
returnValues->fnCollection.nodes[returnValues->fnCollection.count++] = *node;
|
returnValues->fnCollection.nodes[returnValues->fnCollection.count++] = *node;
|
||||||
|
FREE(Node, node);
|
||||||
} while(match(parser, TOKEN_COMMA));
|
} while(match(parser, TOKEN_COMMA));
|
||||||
|
|
||||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of return statement");
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of return statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
freeNode(*nodeHandle); //free the initial node
|
|
||||||
emitNodePath(nodeHandle, NODE_PATH_RETURN, NULL, NULL, NULL, returnValues, NULL);
|
emitNodePath(nodeHandle, NODE_PATH_RETURN, NULL, NULL, NULL, returnValues, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1162,8 +1173,7 @@ static void returnStmt(Parser* parser, Node** nodeHandle) {
|
|||||||
static void expressionStmt(Parser* parser, Node** nodeHandle) {
|
static void expressionStmt(Parser* parser, Node** nodeHandle) {
|
||||||
//BUGFIX: check for empty statements
|
//BUGFIX: check for empty statements
|
||||||
if (match(parser, TOKEN_SEMICOLON)) {
|
if (match(parser, TOKEN_SEMICOLON)) {
|
||||||
(*nodeHandle)->type = NODE_LITERAL;
|
emitNodeLiteral(nodeHandle, TO_NULL_LITERAL);
|
||||||
(*nodeHandle)->atomic.literal = TO_NULL_LITERAL;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1172,8 +1182,7 @@ static void expressionStmt(Parser* parser, Node** nodeHandle) {
|
|||||||
expression(parser, &ptr);
|
expression(parser, &ptr);
|
||||||
|
|
||||||
if (ptr != NULL) {
|
if (ptr != NULL) {
|
||||||
**nodeHandle = *ptr;
|
*nodeHandle = ptr;
|
||||||
FREE(Node, ptr); //BUGFIX: this thread of execution is nuts
|
|
||||||
}
|
}
|
||||||
|
|
||||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' at the end of expression statement");
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at the end of expression statement");
|
||||||
@@ -1383,7 +1392,7 @@ static void fnDecl(Parser* parser, Node** nodeHandle) {
|
|||||||
char* cpy = copyString(identifierToken.lexeme, length);
|
char* cpy = copyString(identifierToken.lexeme, length);
|
||||||
Literal identifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
|
Literal identifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
|
||||||
|
|
||||||
//TODO: read the parameters and arity
|
//read the parameters and arity
|
||||||
consume(parser, TOKEN_PAREN_LEFT, "Expected '(' after function identifier");
|
consume(parser, TOKEN_PAREN_LEFT, "Expected '(' after function identifier");
|
||||||
|
|
||||||
//for holding the array of arguments
|
//for holding the array of arguments
|
||||||
@@ -1426,6 +1435,7 @@ static void fnDecl(Parser* parser, Node** nodeHandle) {
|
|||||||
emitNodeVarDecl(&literalNode, argIdentifier, argTypeLiteral, NULL);
|
emitNodeVarDecl(&literalNode, argIdentifier, argTypeLiteral, NULL);
|
||||||
|
|
||||||
argumentNode->fnCollection.nodes[argumentNode->fnCollection.count++] = *literalNode;
|
argumentNode->fnCollection.nodes[argumentNode->fnCollection.count++] = *literalNode;
|
||||||
|
FREE(Node, literalNode);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1469,6 +1479,7 @@ static void fnDecl(Parser* parser, Node** nodeHandle) {
|
|||||||
emitNodeVarDecl(&literalNode, argIdentifier, argTypeLiteral, NULL);
|
emitNodeVarDecl(&literalNode, argIdentifier, argTypeLiteral, NULL);
|
||||||
|
|
||||||
argumentNode->fnCollection.nodes[argumentNode->fnCollection.count++] = *literalNode;
|
argumentNode->fnCollection.nodes[argumentNode->fnCollection.count++] = *literalNode;
|
||||||
|
FREE(Node, literalNode);
|
||||||
|
|
||||||
} while (match(parser, TOKEN_COMMA)); //if comma is read, continue
|
} while (match(parser, TOKEN_COMMA)); //if comma is read, continue
|
||||||
|
|
||||||
@@ -1493,13 +1504,14 @@ static void fnDecl(Parser* parser, Node** nodeHandle) {
|
|||||||
emitNodeLiteral(&literalNode, readTypeToLiteral(parser));
|
emitNodeLiteral(&literalNode, readTypeToLiteral(parser));
|
||||||
|
|
||||||
returnNode->fnCollection.nodes[returnNode->fnCollection.count++] = *literalNode;
|
returnNode->fnCollection.nodes[returnNode->fnCollection.count++] = *literalNode;
|
||||||
|
FREE(Node, literalNode);
|
||||||
} while(match(parser, TOKEN_COMMA));
|
} while(match(parser, TOKEN_COMMA));
|
||||||
}
|
}
|
||||||
|
|
||||||
//read the function body
|
//read the function body
|
||||||
consume(parser, TOKEN_BRACE_LEFT, "Expected '{' after return list");
|
consume(parser, TOKEN_BRACE_LEFT, "Expected '{' after return list");
|
||||||
|
|
||||||
Node* blockNode = ALLOCATE(Node, 1);
|
Node* blockNode = NULL;
|
||||||
blockStmt(parser, &blockNode);
|
blockStmt(parser, &blockNode);
|
||||||
|
|
||||||
//declare it
|
//declare it
|
||||||
@@ -1547,8 +1559,7 @@ Node* scanParser(Parser* parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//returns nodes on the heap
|
//returns nodes on the heap
|
||||||
Node* node = ALLOCATE(Node, 1);
|
Node* node = NULL;
|
||||||
node->type = NODE_ERROR; //BUGFIX: so freeing won't break the damn thing
|
|
||||||
|
|
||||||
//process the grammar rule for this line
|
//process the grammar rule for this line
|
||||||
declaration(parser, &node);
|
declaration(parser, &node);
|
||||||
@@ -1563,3 +1574,4 @@ Node* scanParser(Parser* parser) {
|
|||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1023
test/sample_code.toy
Normal file
1023
test/sample_code.toy
Normal file
File diff suppressed because it is too large
Load Diff
49
test/test_lexer.c
Normal file
49
test/test_lexer.c
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#include "lexer.h"
|
||||||
|
|
||||||
|
#include "console_colors.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
{
|
||||||
|
//source
|
||||||
|
char* source = "print null;";
|
||||||
|
|
||||||
|
//test init & quit
|
||||||
|
Lexer lexer;
|
||||||
|
initLexer(&lexer, source);
|
||||||
|
|
||||||
|
//get each token
|
||||||
|
Token print = scanLexer(&lexer);
|
||||||
|
Token null = scanLexer(&lexer);
|
||||||
|
Token semi = scanLexer(&lexer);
|
||||||
|
Token eof = scanLexer(&lexer);
|
||||||
|
|
||||||
|
//test each token is correct
|
||||||
|
if (strncmp(print.lexeme, "print", print.length)) {
|
||||||
|
fprintf(stderr, ERROR "ERROR: print lexeme is wrong: %s" RESET, print.lexeme);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (strncmp(null.lexeme, "null", null.length)) {
|
||||||
|
fprintf(stderr, ERROR "ERROR: null lexeme is wrong: %s" RESET, null.lexeme);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(semi.lexeme, ";", semi.length)) {
|
||||||
|
fprintf(stderr, ERROR "ERROR: semicolon lexeme is wrong: %s" RESET, semi.lexeme);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eof.type != TOKEN_EOF) {
|
||||||
|
fprintf(stderr, ERROR "ERROR: Failed to find EOF token" RESET);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(NOTICE "All good\n" RESET);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -10,8 +10,11 @@ int main() {
|
|||||||
//test literals
|
//test literals
|
||||||
char* str = "foobar";
|
char* str = "foobar";
|
||||||
|
|
||||||
|
Literal literal = TO_STRING_LITERAL(copyString(str, strlen(str)), strlen(str));
|
||||||
|
|
||||||
Node* node;
|
Node* node;
|
||||||
emitNodeLiteral(&node, TO_STRING_LITERAL(copyString(str, strlen(str)), strlen(str)) );
|
emitNodeLiteral(&node, literal);
|
||||||
|
freeLiteral(literal);
|
||||||
freeNode(node);
|
freeNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,9 +27,12 @@ int main() {
|
|||||||
Node* left;
|
Node* left;
|
||||||
Node* right;
|
Node* right;
|
||||||
|
|
||||||
|
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn, strlen(idn)), strlen(idn));
|
||||||
|
Literal string = TO_STRING_LITERAL(copyString(str, strlen(str)), strlen(str));
|
||||||
|
|
||||||
emitNodeCompound(&dictionary, LITERAL_DICTIONARY);
|
emitNodeCompound(&dictionary, LITERAL_DICTIONARY);
|
||||||
emitNodeLiteral(&left, TO_IDENTIFIER_LITERAL(copyString(idn, strlen(idn)), strlen(idn)) );
|
emitNodeLiteral(&left, identifier);
|
||||||
emitNodeLiteral(&right, TO_STRING_LITERAL(copyString(str, strlen(str)), strlen(str)) );
|
emitNodeLiteral(&right, string);
|
||||||
|
|
||||||
//grow the node if needed
|
//grow the node if needed
|
||||||
if (dictionary->compound.capacity < dictionary->compound.count + 1) {
|
if (dictionary->compound.capacity < dictionary->compound.count + 1) {
|
||||||
@@ -37,12 +43,12 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//store the left and right in the node
|
//store the left and right in the node
|
||||||
Node* pair = NULL;
|
setNodePair(&dictionary->compound.nodes[dictionary->compound.count++], left, right);
|
||||||
emitNodePair(&pair, left, right);
|
|
||||||
dictionary->compound.nodes[dictionary->compound.count++] = *pair;
|
|
||||||
|
|
||||||
//the real test
|
//the real test
|
||||||
freeNode(dictionary);
|
freeNode(dictionary);
|
||||||
|
freeLiteral(identifier);
|
||||||
|
freeLiteral(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(NOTICE "All good\n" RESET);
|
||||||
|
|||||||
120
test/test_parser.c
Normal file
120
test/test_parser.c
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
#include "console_colors.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//IO functions
|
||||||
|
char* readFile(char* path, size_t* fileSize) {
|
||||||
|
FILE* file = fopen(path, "rb");
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
fprintf(stderr, ERROR "Could not open file \"%s\"\n" RESET, path);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(file, 0L, SEEK_END);
|
||||||
|
*fileSize = ftell(file);
|
||||||
|
rewind(file);
|
||||||
|
|
||||||
|
char* buffer = (char*)malloc(*fileSize + 1);
|
||||||
|
|
||||||
|
if (buffer == NULL) {
|
||||||
|
fprintf(stderr, ERROR "Not enough memory to read \"%s\"\n" RESET, path);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file);
|
||||||
|
|
||||||
|
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
|
||||||
|
|
||||||
|
if (bytesRead < *fileSize) {
|
||||||
|
fprintf(stderr, ERROR "Could not read file \"%s\"\n" RESET, path);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
{
|
||||||
|
//source
|
||||||
|
char* source = "print null;";
|
||||||
|
|
||||||
|
//test init & quit
|
||||||
|
Lexer lexer;
|
||||||
|
Parser parser;
|
||||||
|
initLexer(&lexer, source);
|
||||||
|
initParser(&parser, &lexer);
|
||||||
|
|
||||||
|
freeParser(&parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//source
|
||||||
|
char* source = "print null;";
|
||||||
|
|
||||||
|
//test parsing
|
||||||
|
Lexer lexer;
|
||||||
|
Parser parser;
|
||||||
|
initLexer(&lexer, source);
|
||||||
|
initParser(&parser, &lexer);
|
||||||
|
|
||||||
|
Node* node = scanParser(&parser);
|
||||||
|
|
||||||
|
//inspect the node
|
||||||
|
if (node == NULL) {
|
||||||
|
fprintf(stderr, ERROR "ERROR: Node is null" RESET);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type != NODE_UNARY || node->unary.opcode != OP_PRINT) {
|
||||||
|
fprintf(stderr, ERROR "ERROR: Node is not a print instruction" RESET);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->unary.child->type != NODE_LITERAL || !IS_NULL(node->unary.child->atomic.literal)) {
|
||||||
|
fprintf(stderr, ERROR "ERROR: Node to be printed is not a null value" RESET);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
freeNode(node);
|
||||||
|
freeParser(&parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//get the source file
|
||||||
|
size_t size = 0;
|
||||||
|
char* source = readFile("sample_code.toy", &size);
|
||||||
|
|
||||||
|
//test parsing a chunk of junk (valgrind will find leaks)
|
||||||
|
Lexer lexer;
|
||||||
|
Parser parser;
|
||||||
|
initLexer(&lexer, source);
|
||||||
|
initParser(&parser, &lexer);
|
||||||
|
|
||||||
|
Node* node = scanParser(&parser);
|
||||||
|
|
||||||
|
while (node != NULL) {
|
||||||
|
if (node->type == NODE_ERROR) {
|
||||||
|
fprintf(stderr, ERROR "ERROR: Error node detected" RESET);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeNode(node);
|
||||||
|
node = scanParser(&parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
freeParser(&parser);
|
||||||
|
free((void*)source);
|
||||||
|
}
|
||||||
|
printf(NOTICE "All good\n" RESET);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user