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"
|
2026-02-22 20:33:45 +11:00
|
|
|
#include "../include/ansii.h"
|
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)");
|
|
|
|
|
}
|
|
|
|
|
SolsParser parser = {
|
|
|
|
|
.input = input,
|
|
|
|
|
.current = 0,
|
2026-02-22 20:33:45 +11:00
|
|
|
.output = node.as.success,
|
|
|
|
|
.errors.capacity = 32,
|
|
|
|
|
.errors.count = 0,
|
|
|
|
|
.errors.at = malloc(sizeof(char*) * 32)
|
2026-02-22 12:40:47 +11:00
|
|
|
};
|
2026-02-22 20:33:45 +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
|
|
|
parser.currentParent = &parser.output;
|
|
|
|
|
return Success(SolsParser, charptr, parser);
|
2026-02-22 09:21:51 +11:00
|
|
|
}
|
2026-02-22 17:10:20 +11:00
|
|
|
|
2026-02-22 20:33:45 +11:00
|
|
|
void createParserError(SolsParser* parser, char* what) {
|
|
|
|
|
|
|
|
|
|
ResultType(SolsToken, Nothing) prevToken;
|
|
|
|
|
SolsToken token = parserPeek(parser, 0).as.success;
|
|
|
|
|
ResultType(SolsToken, Nothing) nextToken;
|
|
|
|
|
|
|
|
|
|
// Find tokens for previous line and next line
|
|
|
|
|
for (size_t i = parser->current; i > 0; i--) {
|
|
|
|
|
prevToken = parserLookAt(parser, i);
|
|
|
|
|
if (prevToken.error || prevToken.as.success.line.num != token.line.num) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (prevToken.error || prevToken.as.success.line.num == token.line.num) {
|
|
|
|
|
prevToken = Error(SolsToken, Nothing, {});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (size_t i = parser->current; i <= parser->input->count; i++) {
|
|
|
|
|
nextToken = parserLookAt(parser, i);
|
|
|
|
|
if (nextToken.error || nextToken.as.success.line.num != token.line.num) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (nextToken.error || nextToken.as.success.line.num == token.line.num) {
|
|
|
|
|
nextToken = Error(SolsToken, Nothing, {});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
return Error(Nothing, charptr, "Not an error, just curious what errors look like");
|
|
|
|
|
|
|
|
|
|
return Success(Nothing, charptr, {});
|
|
|
|
|
}
|
|
|
|
|
static inline ResultType(Nothing, charptr) parseLiteral(SolsParser* parser) {
|
|
|
|
|
return Error(Nothing, charptr, "Not an error, just curious what errors look like");
|
|
|
|
|
|
|
|
|
|
return Success(Nothing, charptr, {});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline ResultType(Nothing, charptr) parsePuts(SolsParser* parser) {
|
|
|
|
|
return Error(Nothing, charptr, "Not an error, just curious what errors look like");
|
|
|
|
|
return Success(Nothing, charptr, {});
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-22 17:10:20 +11:00
|
|
|
ResultType(Nothing, charptr) parse(SolsParser* parser) {
|
2026-02-22 20:33:45 +11:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ResultType(SolsToken, Nothing) parserPeek(SolsParser* parser, size_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 + 1 >= parser->input->count) {
|
|
|
|
|
return Error(SolsToken, Nothing, {});
|
|
|
|
|
}
|
|
|
|
|
return Success(SolsToken, Nothing, parser->input->at[parser->current ++]);
|
|
|
|
|
}
|