1597 lines
58 KiB
C
1597 lines
58 KiB
C
#include "parser.h"
|
|
#include "SolsNode.h"
|
|
|
|
#include "../include/estr.h"
|
|
#include "../include/ansii.h"
|
|
#include <groundvm.h>
|
|
|
|
SolsTokenPrecedence getPrecedence(SolsToken *token) {
|
|
switch (token->type) {
|
|
case STT_LINE_END: return STP_NEWLINE;
|
|
case STT_KW_PUTS: return STP_PUTS;
|
|
case STT_KW_IF: return STP_IF;
|
|
case STT_KW_WHILE: return STP_WHILE;
|
|
case STT_OP_ADDTO:
|
|
case STT_OP_SUBTO:
|
|
case STT_OP_MULTO:
|
|
case STT_OP_DIVTO:
|
|
case STT_OP_INCREMENT:
|
|
case STT_OP_DECREMENT:
|
|
case STT_OP_SET: return STP_SET;
|
|
// FIXME figure out how to do functions
|
|
case STT_OP_MUL: case STT_OP_DIV: return STP_MUL;
|
|
case STT_OP_ADD: case STT_OP_SUB: return STP_ADD;
|
|
case STT_OP_EQUAL:
|
|
case STT_OP_EQGREATER:
|
|
case STT_OP_EQLESSER:
|
|
case STT_OP_INEQUAL:
|
|
case STT_OP_GREATER:
|
|
case STT_OP_LESSER: return STP_COMPARE;
|
|
default: return STP_OTHER;
|
|
}
|
|
}
|
|
|
|
ResultType(SolsParser, charptr) createSolsParser(SolsTokens* input) {
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_ROOT);
|
|
if (node.error) {
|
|
Estr str = CREATE_ESTR(node.as.error);
|
|
APPEND_ESTR(str, " (in createSolsParser() function)");
|
|
return Error(SolsParser, charptr, str.str);
|
|
}
|
|
SolsParser parser = {
|
|
.input = input,
|
|
.current = 0,
|
|
.output = node.as.success,
|
|
.errors.capacity = 32,
|
|
.errors.count = 0,
|
|
.errors.at = malloc(sizeof(char*) * 32)
|
|
};
|
|
if (parser.errors.at == NULL) {
|
|
return Error(SolsParser, charptr, "Couldn't allocate memory to store errors (in createSolsParser() function)");
|
|
}
|
|
return Success(SolsParser, charptr, parser);
|
|
}
|
|
|
|
void addToParserErrors(SolsParser* parser, char* errors) {
|
|
if (parser->errors.count + 1 >= parser->errors.capacity) {
|
|
parser->errors.capacity *= 2;
|
|
char** tmp = realloc(parser->errors.at, sizeof(char*) * parser->errors.capacity);
|
|
if (tmp == NULL) {
|
|
parser->errors.at[parser->errors.count - 1] = "Failed to allocate more memory for addToParserErrors function";
|
|
return;
|
|
}
|
|
parser->errors.at = tmp;
|
|
}
|
|
parser->errors.at[parser->errors.count] = errors;
|
|
parser->errors.count++;
|
|
}
|
|
|
|
void createParserError(SolsParser* parser, char* what) {
|
|
|
|
ResultType(SolsToken, Nothing) prevToken = Error(SolsToken, Nothing, {});
|
|
SolsToken token = parserPeek(parser, 0).as.success;
|
|
ResultType(SolsToken, Nothing) nextToken = Error(SolsToken, Nothing, {});
|
|
|
|
// Find tokens for previous line
|
|
if (parser->current > 1) {
|
|
for (size_t i = parser->current - 1; i > 0; i--) {
|
|
ResultType(SolsToken, Nothing) check = parserLookAt(parser, i - 1);
|
|
if (check.error) break;
|
|
if (check.as.success.line.num != token.line.num) {
|
|
prevToken = check;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Find tokens for next line
|
|
for (size_t i = parser->current; i < parser->input->count; i++) {
|
|
ResultType(SolsToken, Nothing) check = parserLookAt(parser, i);
|
|
if (check.error) break;
|
|
if (check.as.success.line.num != token.line.num) {
|
|
nextToken = check;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (parser->errors.count + 1 >= parser->errors.capacity) {
|
|
parser->errors.capacity *= 2;
|
|
char** tmp = realloc(parser->errors.at, sizeof(char*) * parser->errors.capacity);
|
|
if (tmp == NULL) {
|
|
parser->errors.at[parser->errors.count - 1] = "Failed to allocate more memory for createParserError function";
|
|
return;
|
|
}
|
|
parser->errors.at = tmp;
|
|
}
|
|
Estr err = CREATE_ESTR(ESC_BOLD ESC_RED_FG "error: " ESC_RESET ESC_BOLD);
|
|
|
|
// Append the main error message and a newline
|
|
APPEND_ESTR(err, what);
|
|
APPEND_ESTR(err, "\n" ESC_RESET);
|
|
|
|
APPEND_ESTR(err, ESC_CYAN_FG "-> " ESC_RESET);
|
|
APPEND_ESTR(err, "on line ");
|
|
|
|
// Format the line number
|
|
char line_buf[16];
|
|
snprintf(line_buf, sizeof(line_buf), "%zu", token.line.num);
|
|
APPEND_ESTR(err, line_buf);
|
|
|
|
APPEND_ESTR(err, "\n\n");
|
|
// Append line before
|
|
if (!prevToken.error) {
|
|
APPEND_ESTR(err, prevToken.as.success.line.content);
|
|
APPEND_ESTR(err, "\n");
|
|
}
|
|
// Append the actual content of the line that failed
|
|
APPEND_ESTR(err, token.line.content);
|
|
APPEND_ESTR(err, "\n");
|
|
if (!nextToken.error) {
|
|
APPEND_ESTR(err, nextToken.as.success.line.content);
|
|
APPEND_ESTR(err, "\n");
|
|
}
|
|
|
|
// Output the final constructed error
|
|
parser->errors.at[parser->errors.count] = err.str;
|
|
parser->errors.count++;
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseIdentifier(SolsParser* parser) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) {
|
|
return Error(Nothing, charptr, "ruh roh");
|
|
}
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_IDENTIFIER, peek.as.success.as.idName);
|
|
if (node.error) {
|
|
Estr err = CREATE_ESTR(node.as.error);
|
|
APPEND_ESTR(err, " (in parseLiteral() function)");
|
|
return Error(Nothing, charptr, err.str);
|
|
}
|
|
node.as.success.line = peek.as.success.line;
|
|
node.as.success.accessArg = (GroundArg) {
|
|
.type = VALREF,
|
|
.value.refName = peek.as.success.as.idName
|
|
};
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseSet(SolsParser* parser) {
|
|
if (parser->currentParent->children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting identifier before '='");
|
|
}
|
|
if (parser->currentParent->children.at[parser->output.children.count - 1].type != SNT_IDENTIFIER) {
|
|
return Error(Nothing, charptr, "Expecting identifier before '='");
|
|
}
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
// Get the identifier (previous node)
|
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
size_t bracketCount = 0;
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
|
|
if (peek.as.success.type == STT_OPEN_CURLY) bracketCount++;
|
|
else if (peek.as.success.type == STT_CLOSE_CURLY && bracketCount > 0) bracketCount--;
|
|
|
|
if (bracketCount == 0 && getPrecedence(&peek.as.success) <= STP_SET) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_SET);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (putsParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting token after '='");
|
|
}
|
|
|
|
// Copy idnode into set node
|
|
addChildToSolsNode(&node.as.success, idNode);
|
|
|
|
// Copy nodes into the set node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
// Put the set node where the idNode was
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseAdd(SolsParser* parser) {
|
|
if (parser->currentParent->children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting something before '+'");
|
|
}
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
// Get the previous node
|
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (getPrecedence(&peek.as.success) <= STP_ADD) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_ADD);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (putsParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting token after '+'");
|
|
}
|
|
|
|
// Copy idnode into set node
|
|
addChildToSolsNode(&node.as.success, idNode);
|
|
|
|
// Copy nodes into the set node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
// Put the set node where the idNode was
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseSub(SolsParser* parser) {
|
|
if (parser->currentParent->children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting something before '-'");
|
|
}
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
// Get the previous node
|
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (getPrecedence(&peek.as.success) <= STP_ADD) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_SUB);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (putsParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting token after '-'");
|
|
}
|
|
|
|
// Copy idnode into set node
|
|
addChildToSolsNode(&node.as.success, idNode);
|
|
|
|
// Copy nodes into the set node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
// Put the set node where the idNode was
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseMul(SolsParser* parser) {
|
|
if (parser->currentParent->children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting something before '*'");
|
|
}
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
// Get the previous node
|
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (getPrecedence(&peek.as.success) <= STP_MUL) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_MUL);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (putsParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting token after '*'");
|
|
}
|
|
|
|
// Copy idnode into set node
|
|
addChildToSolsNode(&node.as.success, idNode);
|
|
|
|
// Copy nodes into the set node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
// Put the set node where the idNode was
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseDiv(SolsParser* parser) {
|
|
if (parser->currentParent->children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting something before '/'");
|
|
}
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
// Get the previous node
|
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (getPrecedence(&peek.as.success) <= STP_MUL) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_SUB);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (putsParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting token after '/'");
|
|
}
|
|
|
|
// Copy idnode into set node
|
|
addChildToSolsNode(&node.as.success, idNode);
|
|
|
|
// Copy nodes into the set node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
// Put the set node where the idNode was
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseEqual(SolsParser* parser) {
|
|
if (parser->currentParent->children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting something before '=='");
|
|
}
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
// Get the previous node
|
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (getPrecedence(&peek.as.success) <= STP_COMPARE) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_EQUAL);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (putsParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting token after '=='");
|
|
}
|
|
|
|
// Copy idnode into set node
|
|
addChildToSolsNode(&node.as.success, idNode);
|
|
|
|
// Copy nodes into the set node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
// Put the equal node where the idNode was
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseInequal(SolsParser* parser) {
|
|
if (parser->currentParent->children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting something before '!='");
|
|
}
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
// Get the previous node
|
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (getPrecedence(&peek.as.success) <= STP_COMPARE) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_INEQUAL);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (putsParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting token after '!='");
|
|
}
|
|
|
|
// Copy idnode into set node
|
|
addChildToSolsNode(&node.as.success, idNode);
|
|
|
|
// Copy nodes into the set node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
// Put the equal node where the idNode was
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseGreater(SolsParser* parser) {
|
|
if (parser->currentParent->children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting something before '>'");
|
|
}
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
// Get the previous node
|
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (getPrecedence(&peek.as.success) <= STP_COMPARE) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_GREATER);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (putsParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting token after '>'");
|
|
}
|
|
|
|
// Copy idnode into set node
|
|
addChildToSolsNode(&node.as.success, idNode);
|
|
|
|
// Copy nodes into the set node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
// Put the equal node where the idNode was
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseLesser(SolsParser* parser) {
|
|
if (parser->currentParent->children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting something before '<'");
|
|
}
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
// Get the previous node
|
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (getPrecedence(&peek.as.success) <= STP_COMPARE) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_LESSER);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (putsParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting token after '<'");
|
|
}
|
|
|
|
// Copy idnode into set node
|
|
addChildToSolsNode(&node.as.success, idNode);
|
|
|
|
// Copy nodes into the set node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
// Put the equal node where the idNode was
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseEqGreater(SolsParser* parser) {
|
|
if (parser->currentParent->children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting something before '>='");
|
|
}
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
// Get the previous node
|
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (getPrecedence(&peek.as.success) <= STP_COMPARE) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_EQGREATER);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (putsParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting token after '>='");
|
|
}
|
|
|
|
// Copy idnode into set node
|
|
addChildToSolsNode(&node.as.success, idNode);
|
|
|
|
// Copy nodes into the set node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
// Put the equal node where the idNode was
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseEqLesser(SolsParser* parser) {
|
|
if (parser->currentParent->children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting something before '<='");
|
|
}
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
// Get the previous node
|
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (getPrecedence(&peek.as.success) <= STP_COMPARE) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_EQLESSER);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (putsParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting token after '<='");
|
|
}
|
|
|
|
// Copy idnode into set node
|
|
addChildToSolsNode(&node.as.success, idNode);
|
|
|
|
// Copy nodes into the set node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
// Put the equal node where the idNode was
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseLiteral(SolsParser* parser) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) {
|
|
return Error(Nothing, charptr, "ruh roh");
|
|
}
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_LITERAL, peek.as.success.as.literal);
|
|
if (node.error) {
|
|
Estr err = CREATE_ESTR(node.as.error);
|
|
APPEND_ESTR(err, " (in parseLiteral() function)");
|
|
return Error(Nothing, charptr, err.str);
|
|
}
|
|
node.as.success.line = peek.as.success.line;
|
|
GroundValue value;
|
|
switch (peek.as.success.as.literal.type) {
|
|
case SLT_INT: {
|
|
value = groundCreateValue(INT, peek.as.success.as.literal.as.intv);
|
|
break;
|
|
}
|
|
case SLT_DOUBLE: {
|
|
value = groundCreateValue(DOUBLE, peek.as.success.as.literal.as.doublev);
|
|
break;
|
|
}
|
|
case SLT_STRING: {
|
|
value = groundCreateValue(STRING, peek.as.success.as.literal.as.stringv);
|
|
break;
|
|
}
|
|
case SLT_BOOL: {
|
|
value = groundCreateValue(BOOL, peek.as.success.as.literal.as.boolv);
|
|
break;
|
|
}
|
|
case SLT_CHAR: {
|
|
value = groundCreateValue(CHAR, peek.as.success.as.literal.as.charv);
|
|
break;
|
|
}
|
|
}
|
|
node.as.success.accessArg = (GroundArg) {
|
|
.type = VALUE,
|
|
.value.value = value
|
|
};
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parsePuts(SolsParser* parser) {
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (getPrecedence(&peek.as.success) <= STP_PUTS) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_PUTS);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
// Copy nodes into the sols node
|
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseCodeBlock(SolsParser* parser) {
|
|
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
size_t bracketCount = 1;
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) return Error(Nothing, charptr, "Expecting closing curly brace (})");
|
|
if (peek.as.success.type == STT_OPEN_CURLY) {
|
|
bracketCount++;
|
|
}
|
|
if (peek.as.success.type == STT_CLOSE_CURLY) {
|
|
bracketCount--;
|
|
if (bracketCount < 1) {
|
|
parserConsume(parser);
|
|
break;
|
|
}
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_CODE_BLOCK);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) codeBlockParser = createSolsParser(&tokens.as.success);
|
|
if (codeBlockParser.error) {
|
|
return Error(Nothing, charptr, codeBlockParser.as.error);
|
|
}
|
|
codeBlockParser.as.success.currentParent = &codeBlockParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&codeBlockParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
// Copy nodes into the sols node
|
|
for (size_t i = 0; i < codeBlockParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, codeBlockParser.as.success.output.children.at[i]);
|
|
}
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseWhile(SolsParser* parser) {
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (peek.as.success.type == STT_OPEN_CURLY) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_WHILE);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) whileParser = createSolsParser(&tokens.as.success);
|
|
if (whileParser.error) return Error(Nothing, charptr, whileParser.as.error);
|
|
whileParser.as.success.currentParent = &whileParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&whileParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
// Copy nodes into the sols node
|
|
for (size_t i = 0; i < whileParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, whileParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
if(parserPeek(parser, 1).as.success.type != STT_OPEN_CURLY) {
|
|
return Error(Nothing, charptr, "Expecting opening curly brace for while loop body");
|
|
}
|
|
|
|
parserConsume(parser);
|
|
|
|
ResultType(Nothing, charptr) res = parseCodeBlock(parser);
|
|
if(res.error) return res;
|
|
|
|
// Last child of parent is code block, we need to move it
|
|
SolsNode codeBlock = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(&node.as.success, codeBlock);
|
|
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseIf(SolsParser* parser) {
|
|
// Collect tokens for node
|
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
|
if (tokens.error) {
|
|
return Error(Nothing, charptr, tokens.as.error);
|
|
}
|
|
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
|
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) break;
|
|
if (peek.as.success.type == STT_OPEN_CURLY) {
|
|
break;
|
|
}
|
|
parserConsume(parser);
|
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
|
}
|
|
|
|
// Create node
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_IF);
|
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
|
node.as.success.line = peek.as.success.line;
|
|
|
|
// Parse selected tokens
|
|
ResultType(SolsParser, charptr) ifParser = createSolsParser(&tokens.as.success);
|
|
if (ifParser.error) return Error(Nothing, charptr, ifParser.as.error);
|
|
ifParser.as.success.currentParent = &ifParser.as.success.output;
|
|
ResultType(Nothing, charptr) parsed = parse(&ifParser.as.success);
|
|
|
|
// Add any error messages from parsing
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
// Copy nodes into the sols node
|
|
for (size_t i = 0; i < ifParser.as.success.output.children.count; i++) {
|
|
addChildToSolsNode(&node.as.success, ifParser.as.success.output.children.at[i]);
|
|
}
|
|
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
if(parserPeek(parser, 1).as.success.type != STT_OPEN_CURLY) {
|
|
return Error(Nothing, charptr, "Expecting opening curly brace for if statement body");
|
|
}
|
|
|
|
parserConsume(parser);
|
|
|
|
ResultType(Nothing, charptr) res = parseCodeBlock(parser);
|
|
if(res.error) return res;
|
|
|
|
// Last child of parent is code block, we need to move it
|
|
SolsNode codeBlock = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
parser->currentParent->children.count--;
|
|
addChildToSolsNode(&node.as.success, codeBlock);
|
|
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseCloseCurly(SolsParser* parser) {
|
|
(void)parser;
|
|
return Error(Nothing, charptr, "Extra closing curly brace");
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseLambda(SolsParser* parser) {
|
|
ResultType(SolsToken, Nothing) openBracket = parserConsume(parser);
|
|
if (openBracket.error || openBracket.as.success.type != STT_OPEN_PAREN) {
|
|
return Error(Nothing, charptr, "Expecting '(' after 'lambda'");
|
|
}
|
|
|
|
ResultType(SolsType, charptr) type = createSolsType(STT_FUN);
|
|
if (type.error) {
|
|
return Error(Nothing, charptr, type.as.error);
|
|
}
|
|
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_LAMBDA);
|
|
if (node.error) {
|
|
return Error(Nothing, charptr, node.as.error);
|
|
}
|
|
|
|
// Parse type signature
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) next = parserPeek(parser, 1);
|
|
if (next.error) {
|
|
return Error(Nothing, charptr, "Expecting ')' at end of lambda argument list");
|
|
}
|
|
if (next.as.success.type == STT_CLOSE_PAREN) {
|
|
parserConsume(parser);
|
|
break;
|
|
}
|
|
|
|
if (type.error) {
|
|
return Error(Nothing, charptr, type.as.error);
|
|
}
|
|
|
|
// Pattern of type, name, comma
|
|
|
|
SolsType tmpType;
|
|
|
|
if (next.as.success.type == STT_TYPE) {
|
|
tmpType = next.as.success.as.type;
|
|
} else if (next.as.success.type == STT_IDENTIFIER) {
|
|
tmpType.identifierType = next.as.success.as.idName;
|
|
} else {
|
|
return Error(Nothing, charptr, "Expecting a type or identifier of type in lambda argument list");
|
|
}
|
|
|
|
parserConsume(parser);
|
|
|
|
char* argName;
|
|
next = parserPeek(parser, 1);
|
|
|
|
if (next.as.success.type == STT_IDENTIFIER) {
|
|
argName = next.as.success.as.idName;
|
|
} else {
|
|
return Error(Nothing, charptr, "Expecting identifier after type in lambda argument list");
|
|
}
|
|
|
|
// Add type to constructed SolsType
|
|
addChildToSolsType(&type.as.success, tmpType, argName);
|
|
parserConsume(parser);
|
|
|
|
next = parserPeek(parser, 1);
|
|
if (next.error) {
|
|
return Error(Nothing, charptr, "Expecting a comma or closing bracket");
|
|
}
|
|
if (next.as.success.type == STT_CLOSE_PAREN) {
|
|
parserConsume(parser);
|
|
break;
|
|
}
|
|
if (next.as.success.type != STT_COMMA) {
|
|
return Error(Nothing, charptr, "Expecting a comma or closing bracket");
|
|
}
|
|
parserConsume(parser);
|
|
}
|
|
|
|
// Parse type at the end
|
|
ResultType(SolsToken, Nothing) retType = parserPeek(parser, 1);
|
|
if (retType.error) {
|
|
return Error(Nothing, charptr, "Expecting return type or identifier of type after lambda argument list");
|
|
}
|
|
|
|
if (retType.as.success.type == STT_TYPE) {
|
|
type.as.success.returnType = malloc(sizeof(SolsType));
|
|
if (type.as.success.returnType == NULL) {
|
|
return Error(Nothing, charptr, "Failed to allocate memory for type");
|
|
}
|
|
*type.as.success.returnType = retType.as.success.as.type;
|
|
} else if (retType.as.success.type == STT_IDENTIFIER) {
|
|
type.as.success.returnType = malloc(sizeof(SolsType));
|
|
if (type.as.success.returnType == NULL) {
|
|
return Error(Nothing, charptr, "Failed to allocate memory for type");
|
|
}
|
|
type.as.success.returnType->identifierType = retType.as.success.as.idName;
|
|
} else {
|
|
return Error(Nothing, charptr, "Expecting return type or identifier of type after lambda argument list");
|
|
}
|
|
|
|
// Add type to node
|
|
node.as.success.as.type = type.as.success;
|
|
|
|
parserConsume(parser); // Consumes return type
|
|
|
|
// Skip newlines before the opening curly brace
|
|
while (parserPeek(parser, 1).as.success.type == STT_LINE_END) {
|
|
parserConsume(parser);
|
|
}
|
|
|
|
ResultType(SolsToken, Nothing) openCurly = parserConsume(parser);
|
|
if (openCurly.error || openCurly.as.success.type != STT_OPEN_CURLY) {
|
|
return Error(Nothing, charptr, "Expecting opening curly brace ({) for lambda body");
|
|
}
|
|
|
|
// Add node to parent
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
// Parse code block
|
|
ResultType(Nothing, charptr) res = parseCodeBlock(parser);
|
|
if(res.error) return res;
|
|
|
|
// Last child of parent is code block, we need to move it
|
|
SolsNode codeBlock = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
parser->currentParent->children.count--;
|
|
|
|
// We need to get the actual node from the parent to modify it
|
|
SolsNode* lambdaNode = &parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
addChildToSolsNode(lambdaNode, codeBlock);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) {
|
|
// Consume and validate the function name identifier
|
|
ResultType(SolsToken, Nothing) nameTok = parserConsume(parser);
|
|
if (nameTok.error || nameTok.as.success.type != STT_IDENTIFIER) {
|
|
return Error(Nothing, charptr, "Expecting function name after 'def'");
|
|
}
|
|
|
|
ResultType(SolsToken, Nothing) openBracket = parserConsume(parser);
|
|
if (openBracket.error || openBracket.as.success.type != STT_OPEN_PAREN) {
|
|
return Error(Nothing, charptr, "Expecting '(' after function name in 'def'");
|
|
}
|
|
|
|
ResultType(SolsType, charptr) type = createSolsType(STT_FUN);
|
|
if (type.error) {
|
|
return Error(Nothing, charptr, type.as.error);
|
|
}
|
|
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_DEF);
|
|
if (node.error) {
|
|
return Error(Nothing, charptr, node.as.error);
|
|
}
|
|
|
|
// Add function name as the first child node
|
|
ResultType(SolsNode, charptr) nameNode = createSolsNode(SNT_IDENTIFIER, nameTok.as.success.as.idName);
|
|
if (nameNode.error) {
|
|
return Error(Nothing, charptr, nameNode.as.error);
|
|
}
|
|
nameNode.as.success.line = nameTok.as.success.line;
|
|
nameNode.as.success.accessArg = (GroundArg) {
|
|
.type = VALREF,
|
|
.value.refName = nameTok.as.success.as.idName
|
|
};
|
|
addChildToSolsNode(&node.as.success, nameNode.as.success);
|
|
|
|
// Parse type signature
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) next = parserPeek(parser, 1);
|
|
if (next.error) {
|
|
return Error(Nothing, charptr, "Expecting ')' at end of def argument list");
|
|
}
|
|
if (next.as.success.type == STT_CLOSE_PAREN) {
|
|
parserConsume(parser);
|
|
break;
|
|
}
|
|
|
|
if (type.error) {
|
|
return Error(Nothing, charptr, type.as.error);
|
|
}
|
|
|
|
// Pattern of type, name, comma
|
|
|
|
SolsType tmpType;
|
|
|
|
if (next.as.success.type == STT_TYPE) {
|
|
tmpType = next.as.success.as.type;
|
|
} else if (next.as.success.type == STT_IDENTIFIER) {
|
|
tmpType.identifierType = next.as.success.as.idName;
|
|
} else {
|
|
return Error(Nothing, charptr, "Expecting a type or identifier of type in def argument list");
|
|
}
|
|
|
|
parserConsume(parser);
|
|
|
|
char* argName;
|
|
next = parserPeek(parser, 1);
|
|
|
|
if (next.as.success.type == STT_IDENTIFIER) {
|
|
argName = next.as.success.as.idName;
|
|
} else {
|
|
return Error(Nothing, charptr, "Expecting identifier after type in def argument list");
|
|
}
|
|
|
|
// Add type to constructed SolsType
|
|
addChildToSolsType(&type.as.success, tmpType, argName);
|
|
parserConsume(parser);
|
|
|
|
next = parserPeek(parser, 1);
|
|
if (next.error) {
|
|
return Error(Nothing, charptr, "Expecting a comma or closing bracket");
|
|
}
|
|
if (next.as.success.type == STT_CLOSE_PAREN) {
|
|
parserConsume(parser);
|
|
break;
|
|
}
|
|
if (next.as.success.type != STT_COMMA) {
|
|
return Error(Nothing, charptr, "Expecting a comma or closing bracket");
|
|
}
|
|
parserConsume(parser);
|
|
}
|
|
|
|
// Parse return type after argument list
|
|
ResultType(SolsToken, Nothing) retType = parserPeek(parser, 1);
|
|
if (retType.error) {
|
|
return Error(Nothing, charptr, "Expecting return type or identifier of type after def argument list");
|
|
}
|
|
|
|
if (retType.as.success.type == STT_TYPE) {
|
|
type.as.success.returnType = malloc(sizeof(SolsType));
|
|
if (type.as.success.returnType == NULL) {
|
|
return Error(Nothing, charptr, "Failed to allocate memory for type");
|
|
}
|
|
*type.as.success.returnType = retType.as.success.as.type;
|
|
} else if (retType.as.success.type == STT_IDENTIFIER) {
|
|
type.as.success.returnType = malloc(sizeof(SolsType));
|
|
if (type.as.success.returnType == NULL) {
|
|
return Error(Nothing, charptr, "Failed to allocate memory for type");
|
|
}
|
|
type.as.success.returnType->identifierType = retType.as.success.as.idName;
|
|
} else {
|
|
return Error(Nothing, charptr, "Expecting return type or identifier of type after def argument list");
|
|
}
|
|
|
|
// Add type to node
|
|
node.as.success.as.type = type.as.success;
|
|
|
|
parserConsume(parser); // Consumes return type
|
|
|
|
// Skip newlines before the opening curly brace
|
|
while (parserPeek(parser, 1).as.success.type == STT_LINE_END) {
|
|
parserConsume(parser);
|
|
}
|
|
|
|
ResultType(SolsToken, Nothing) openCurly = parserConsume(parser);
|
|
if (openCurly.error || openCurly.as.success.type != STT_OPEN_CURLY) {
|
|
return Error(Nothing, charptr, "Expecting opening curly brace ({) for def body");
|
|
}
|
|
|
|
// Add node to parent
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
|
|
// Parse code block
|
|
ResultType(Nothing, charptr) res = parseCodeBlock(parser);
|
|
if (res.error) return res;
|
|
|
|
// Last child of parent is code block, we need to move it
|
|
SolsNode codeBlock = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
parser->currentParent->children.count--;
|
|
|
|
// We need to get the actual node from the parent to modify it
|
|
SolsNode* defNode = &parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
addChildToSolsNode(defNode, codeBlock);
|
|
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseFunctionCall(SolsParser* parser) {
|
|
|
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_FUNCTION_CALL);
|
|
if (node.error) {
|
|
return Error(Nothing, charptr, node.as.error);
|
|
}
|
|
|
|
// The identifier (function name) was already parsed as a node right before '('
|
|
if (parser->currentParent->children.count < 1 ||
|
|
parser->currentParent->children.at[parser->currentParent->children.count - 1].type != SNT_IDENTIFIER) {
|
|
return Error(Nothing, charptr, "Expecting identifier before '(' for function call");
|
|
}
|
|
|
|
SolsNode callee = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
parser->currentParent->children.count--; // remove callee identifier node; we'll replace it with the call node
|
|
|
|
node.as.success.as.idName = callee.as.idName;
|
|
node.as.success.line = callee.line;
|
|
|
|
// Empty argument list: foo()
|
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
|
if (peek.error) {
|
|
return Error(Nothing, charptr, "Expecting ')' or a value");
|
|
}
|
|
if (peek.as.success.type == STT_CLOSE_PAREN) {
|
|
parserConsume(parser); // consume ')'
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
// Parse each argument expression separated by commas until ')'
|
|
for (;;) {
|
|
ResultType(SolsTokens, charptr) resultTokens = createSolsTokens();
|
|
if (resultTokens.error) {
|
|
return Error(Nothing, charptr, resultTokens.as.error);
|
|
}
|
|
SolsTokens tokens = resultTokens.as.success;
|
|
|
|
size_t curlys = 0;
|
|
size_t parens = 0;
|
|
|
|
for (;;) {
|
|
peek = parserPeek(parser, 1);
|
|
if (peek.error) {
|
|
return Error(Nothing, charptr, "Expecting ')'");
|
|
}
|
|
|
|
if (peek.as.success.type == STT_OPEN_PAREN) parens++;
|
|
if (peek.as.success.type == STT_CLOSE_PAREN) {
|
|
if (parens == 0) break;
|
|
parens--;
|
|
}
|
|
|
|
if (peek.as.success.type == STT_OPEN_CURLY) curlys++;
|
|
if (peek.as.success.type == STT_CLOSE_CURLY) curlys--;
|
|
|
|
if (curlys == 0 && parens == 0 && peek.as.success.type == STT_COMMA) {
|
|
break;
|
|
}
|
|
|
|
addTokenToSolsTokens(&tokens, peek.as.success);
|
|
parserConsume(parser);
|
|
}
|
|
|
|
ResultType(SolsParser, charptr) newParser = createSolsParser(&tokens);
|
|
if (newParser.error) {
|
|
return Error(Nothing, charptr, newParser.as.error);
|
|
}
|
|
newParser.as.success.currentParent = &newParser.as.success.output;
|
|
|
|
ResultType(Nothing, charptr) parsed = parse(&newParser.as.success);
|
|
if (parsed.error) {
|
|
addToParserErrors(parser, parsed.as.error);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
if (newParser.as.success.output.children.count < 1) {
|
|
return Error(Nothing, charptr, "Expecting a value before ',' or ')'");
|
|
}
|
|
|
|
// One argument expression -> one AST node
|
|
addChildToSolsNode(&node.as.success, newParser.as.success.output.children.at[0]);
|
|
|
|
// Consume ',' or ')'
|
|
peek = parserConsume(parser);
|
|
if (peek.error) {
|
|
return Error(Nothing, charptr, "Expecting ')' or ','");
|
|
}
|
|
if (peek.as.success.type == STT_CLOSE_PAREN) {
|
|
break;
|
|
}
|
|
if (peek.as.success.type != STT_COMMA) {
|
|
return Error(Nothing, charptr, "Expecting ',' or ')'");
|
|
}
|
|
}
|
|
|
|
// Add the fully-built call node once
|
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseOpenParen(SolsParser* parser) {
|
|
return Error(Nothing, charptr, "WIP");
|
|
}
|
|
|
|
static inline ResultType(Nothing, charptr) parseCloseParen(SolsParser* parser) {
|
|
(void)parser;
|
|
return Error(Nothing, charptr, "Extra closing parenthases");
|
|
}
|
|
|
|
ResultType(Nothing, charptr) parse(SolsParser* parser) {
|
|
parser->currentParent = &parser->output;
|
|
for (;;) {
|
|
ResultType(SolsToken, Nothing) token = parserConsume(parser);
|
|
if (token.error) {
|
|
break;
|
|
}
|
|
switch (token.as.success.type) {
|
|
case STT_IDENTIFIER: PARSER_HANDLE(Identifier);
|
|
case STT_LITERAL: PARSER_HANDLE(Literal);
|
|
case STT_KW_PUTS: PARSER_HANDLE(Puts);
|
|
case STT_KW_IF: PARSER_HANDLE(If);
|
|
case STT_KW_WHILE: PARSER_HANDLE(While);
|
|
case STT_KW_LAMBDA: PARSER_HANDLE(Lambda);
|
|
case STT_KW_DEF: PARSER_HANDLE(Def);
|
|
case STT_OP_SET: PARSER_HANDLE(Set);
|
|
case STT_OP_ADD: PARSER_HANDLE(Add);
|
|
case STT_OP_SUB: PARSER_HANDLE(Sub);
|
|
case STT_OP_MUL: PARSER_HANDLE(Mul);
|
|
case STT_OP_DIV: PARSER_HANDLE(Div);
|
|
case STT_OP_EQUAL: PARSER_HANDLE(Equal);
|
|
case STT_OP_INEQUAL: PARSER_HANDLE(Inequal);
|
|
case STT_OP_GREATER: PARSER_HANDLE(Greater);
|
|
case STT_OP_LESSER: PARSER_HANDLE(Lesser);
|
|
case STT_OP_EQGREATER: PARSER_HANDLE(EqGreater);
|
|
case STT_OP_EQLESSER: PARSER_HANDLE(EqLesser);
|
|
case STT_OPEN_CURLY: PARSER_HANDLE(CodeBlock);
|
|
case STT_CLOSE_CURLY: PARSER_HANDLE(CloseCurly);
|
|
case STT_OPEN_PAREN: {
|
|
if (parser->output.children.count > 0 && parser->output.children.at[parser->output.children.count - 1].type == SNT_IDENTIFIER) {
|
|
PARSER_HANDLE(FunctionCall);
|
|
} else {
|
|
PARSER_HANDLE(OpenParen);
|
|
}
|
|
}
|
|
case STT_CLOSE_PAREN: PARSER_HANDLE(CloseParen);
|
|
}
|
|
}
|
|
if (parser->errors.count > 0) {
|
|
Estr estr = CREATE_ESTR("");
|
|
for (size_t i = 0; i < parser->errors.count; i++) {
|
|
APPEND_ESTR(estr, parser->errors.at[i]);
|
|
APPEND_ESTR(estr, "\n");
|
|
}
|
|
return Error(Nothing, charptr, estr.str);
|
|
}
|
|
return Success(Nothing, charptr, {});
|
|
}
|
|
|
|
ResultType(SolsToken, Nothing) parserLookAt(SolsParser* parser, size_t where) {
|
|
if (parser->input == NULL) {
|
|
return Error(SolsToken, Nothing, {});
|
|
}
|
|
if (where >= parser->input->count) {
|
|
return Error(SolsToken, Nothing, {});
|
|
}
|
|
return Success(SolsToken, Nothing, parser->input->at[where]);
|
|
}
|
|
|
|
ResultType(SolsToken, Nothing) parserPeek(SolsParser* parser, int64_t ahead) {
|
|
if (parser->input == NULL) {
|
|
return Error(SolsToken, Nothing, {});
|
|
}
|
|
if (parser->current + ahead - 1 >= parser->input->count) {
|
|
return Error(SolsToken, Nothing, {});
|
|
}
|
|
return Success(SolsToken, Nothing, parser->input->at[parser->current + ahead - 1]);
|
|
}
|
|
|
|
ResultType(SolsToken, Nothing) parserConsume(SolsParser* parser) {
|
|
if (parser->input == NULL) {
|
|
return Error(SolsToken, Nothing, {});
|
|
}
|
|
if (parser->current >= parser->input->count) {
|
|
return Error(SolsToken, Nothing, {});
|
|
}
|
|
return Success(SolsToken, Nothing, parser->input->at[parser->current ++]);
|
|
}
|