#include "parser.h" #include "SolsNode.h" #include "../include/estr.h" #include "../include/ansii.h" #include 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 ++]); }