This repository has been archived on 2026-03-01. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
v2/src/parser/parser.c

1072 lines
38 KiB
C
Raw Normal View History

2026-02-22 09:21:51 +11:00
#include "parser.h"
2026-02-22 12:40:47 +11:00
#include "SolsNode.h"
#include "../include/estr.h"
#include "../include/ansii.h"
2026-02-24 21:01:30 +11:00
#include <groundvm.h>
2026-02-22 09:21:51 +11:00
2026-02-24 13:21:08 +11:00
SolsTokenPrecedence getPrecedence(SolsToken *token) {
switch (token->type) {
case STT_LINE_END: return STP_NEWLINE;
case STT_KW_PUTS: return STP_PUTS;
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;
2026-02-27 14:54:16 +11:00
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;
2026-02-24 13:21:08 +11:00
default: return STP_OTHER;
}
}
2026-02-22 09:21:51 +11:00
ResultType(SolsParser, charptr) createSolsParser(SolsTokens* input) {
2026-02-22 12:40:47 +11:00
ResultType(SolsNode, charptr) node = createSolsNode(SNT_ROOT);
if (node.error) {
Estr str = CREATE_ESTR(node.as.error);
APPEND_ESTR(str, " (in createSolsParser() function)");
2026-02-23 18:04:56 +11:00
return Error(SolsParser, charptr, str.str);
2026-02-22 12:40:47 +11:00
}
SolsParser parser = {
.input = input,
.current = 0,
.output = node.as.success,
.errors.capacity = 32,
.errors.count = 0,
.errors.at = malloc(sizeof(char*) * 32)
2026-02-22 12:40:47 +11:00
};
if (parser.errors.at == NULL) {
return Error(SolsParser, charptr, "Couldn't allocate memory to store errors (in createSolsParser() function)");
}
2026-02-22 12:40:47 +11:00
return Success(SolsParser, charptr, parser);
2026-02-22 09:21:51 +11:00
}
2026-02-22 17:10:20 +11:00
2026-02-24 13:21:08 +11:00
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) {
2026-02-22 21:52:00 +11:00
ResultType(SolsToken, Nothing) prevToken = Error(SolsToken, Nothing, {});
SolsToken token = parserPeek(parser, 0).as.success;
2026-02-22 21:52:00 +11:00
ResultType(SolsToken, Nothing) nextToken = Error(SolsToken, Nothing, {});
2026-02-22 21:52:00 +11:00
// 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;
}
}
}
2026-02-22 21:52:00 +11:00
// 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;
}
2026-02-23 18:04:56 +11:00
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);
2026-02-23 18:04:56 +11:00
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);
}
2026-02-24 19:33:41 +11:00
node.as.success.line = peek.as.success.line;
2026-02-24 21:01:30 +11:00
node.as.success.accessArg = (GroundArg) {
.type = VALREF,
.value.refName = peek.as.success.as.idName
};
2026-02-23 18:17:44 +11:00
addChildToSolsNode(parser->currentParent, node.as.success);
return Success(Nothing, charptr, {});
}
2026-02-24 13:21:08 +11:00
2026-02-24 21:22:50 +11:00
static inline ResultType(Nothing, charptr) parseSet(SolsParser* parser) {
2026-02-26 08:50:43 +11:00
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) {
2026-02-24 21:22:50 +11:00
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);
}
2026-02-26 08:50:43 +11:00
// Get the identifier (previous node)
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
2026-02-24 21:22:50 +11:00
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_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 '='");
}
2026-02-26 08:50:43 +11:00
// Copy idnode into set node
addChildToSolsNode(&node.as.success, idNode);
// Copy nodes into the set node
2026-02-24 21:22:50 +11:00
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
}
2026-02-26 08:50:43 +11:00
// Put the set node where the idNode was
parser->currentParent->children.count--;
2026-02-24 21:22:50 +11:00
addChildToSolsNode(parser->currentParent, node.as.success);
return Success(Nothing, charptr, {});
}
2026-02-26 11:46:29 +11:00
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, {});
}
2026-02-27 14:54:16 +11:00
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, {});
}
2026-02-28 10:25:26 +11:00
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) {
2026-02-23 18:04:56 +11:00
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);
}
2026-02-24 19:33:41 +11:00
node.as.success.line = peek.as.success.line;
2026-02-24 20:07:02 +11:00
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
};
2026-02-23 18:17:44 +11:00
addChildToSolsNode(parser->currentParent, node.as.success);
return Success(Nothing, charptr, {});
}
static inline ResultType(Nothing, charptr) parsePuts(SolsParser* parser) {
2026-02-24 13:21:08 +11:00
// Collect tokens for node
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
if (tokens.error) {
return Error(Nothing, charptr, tokens.as.error);
}
2026-02-24 19:33:41 +11:00
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
if (peek.error) return Error(Nothing, charptr, "ruh roh");
2026-02-24 13:21:08 +11:00
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);
2026-02-24 19:33:41 +11:00
node.as.success.line = peek.as.success.line;
2026-02-24 13:21:08 +11:00
// 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);
2026-02-24 21:22:50 +11:00
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]);
2026-02-24 13:21:08 +11:00
}
addChildToSolsNode(parser->currentParent, node.as.success);
return Success(Nothing, charptr, {});
}
2026-02-28 10:56:00 +11:00
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) parseCloseCurly(SolsParser* parser) {
(void)parser;
return Error(Nothing, charptr, "Extra closing curly brace");
}
2026-02-22 17:10:20 +11:00
ResultType(Nothing, charptr) parse(SolsParser* parser) {
2026-02-23 18:17:44 +11:00
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);
2026-02-24 21:22:50 +11:00
case STT_OP_SET: PARSER_HANDLE(Set);
2026-02-26 11:46:29 +11:00
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);
2026-02-27 14:54:16 +11:00
case STT_OP_EQUAL: PARSER_HANDLE(Equal);
2026-02-28 10:25:26 +11:00
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);
2026-02-28 10:56:00 +11:00
case STT_OPEN_CURLY: PARSER_HANDLE(CodeBlock);
case STT_CLOSE_CURLY: PARSER_HANDLE(CloseCurly);
}
}
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]);
2026-02-22 17:10:20 +11:00
}
2026-02-23 18:04:56 +11:00
ResultType(SolsToken, Nothing) parserPeek(SolsParser* parser, int64_t ahead) {
2026-02-22 17:10:20 +11:00
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, {});
}
2026-02-23 18:17:44 +11:00
if (parser->current >= parser->input->count) {
2026-02-22 17:10:20 +11:00
return Error(SolsToken, Nothing, {});
}
return Success(SolsToken, Nothing, parser->input->at[parser->current ++]);
}