diff --git a/src/parser/Parser.cpp b/src/parser/Parser.cpp new file mode 100644 index 0000000..6351669 --- /dev/null +++ b/src/parser/Parser.cpp @@ -0,0 +1,801 @@ +/* +* Copyright (c) 2024 - Nathanne Isip +* This file is part of Zhivo. +* +* Zhivo is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 3 of the License, +* or (at your option) any later version. +* +* Zhivo is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Zhivo. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +Parser Parser::fromFile(const std::string& fileName) { + std::unique_ptr tokenizer = Tokenizer::loadFile(fileName); + tokenizer->scan(); + + return Parser(tokenizer->getTokens()); +} + +bool Parser::isAtEnd() const { + return this->index == this->length; +} + +void Parser::advance() { + this->index++; +} + +Token Parser::peek() const { + if(this->isAtEnd()) + throw ParserException("Encountered end-of-file."); + + return this->tokens[this->index]; +} + +bool Parser::isNext(const std::string& image) const { + if(this->isAtEnd()) + return false; + + return this->peek().getImage() == image; +} + +Token Parser::consume(const std::string& image) { + if(this->isAtEnd()) + throw ParserException("Expecting \"" + image + "\", encountered end-of-code."); + + Token token = this->peek(); + if(token.getImage() != image) + throw ParserException("Expecting \"" + image + "\", encountered " + token.getImage()); + + this->advance(); + return token; +} + +Token Parser::consume(TokenType type) { + if(this->isAtEnd()) + throw ParserException("Expecting token type, encountered end-of-code."); + + Token token = this->peek(); + if(token.getType() != type) + throw ParserException( + "Expecting " + tokenTypeToString(type) + + ", encountered " + tokenTypeToString(token.getType()) + ); + + this->advance(); + return token; +} + +const std::vector>& Parser::getGlobalStatements() const { + return this->globalStatements; +} + +std::unique_ptr Parser::exprArray() { + Token address = this->consume("["); + std::vector> expressions; + + while(!this->isNext("]")) { + if(!expressions.empty()) + this->consume(","); + + expressions.push_back(this->expression()); + } + + this->consume("]"); + return std::make_unique( + std::make_unique(address), + std::move(expressions) + ); +} + +std::unique_ptr Parser::exprBlock() { + Token address = this->consume("{"); + std::vector> body; + + while(!this->isNext("}")) + body.emplace_back(this->expression()); + + return std::make_unique( + std::make_unique(address), + std::move(body) + ); +} + +std::unique_ptr Parser::exprCatchHandle() { + Token address = this->consume("catch"); + std::unique_ptr catchExpr = this->expression(); + this->consume("handle"); + + Token handler = this->consume(TokenType::IDENTIFIER); + std::unique_ptr handleExpr = this->expression(); + + std::unique_ptr finalExpr = nullptr; + if(this->isNext("handle")) { + this->consume("handle"); + finalExpr = this->expression(); + } + + return std::make_unique( + std::make_unique(address), + std::move(catchExpr), + std::move(handleExpr), + std::make_unique(handler), + std::move(finalExpr) + ); +} + +std::unique_ptr Parser::exprDoWhile() { + Token address = this->consume("do"); + std::unique_ptr body = this->expression(); + + this->consume("while"); + this->consume("("); + + std::unique_ptr condition = this->expression(); + this->consume(")"); + + return std::make_unique( + std::make_unique(address), + std::move(body), + std::move(condition) + ); +} + +std::unique_ptr Parser::exprFunctionDecl() { + Token address = this->consume("func"); + this->consume("("); + + std::vector> parameters; + while(!this->isNext(")")) { + if(!parameters.empty()) + this->consume(","); + + parameters.emplace_back( + std::make_unique( + this->consume(TokenType::IDENTIFIER) + ) + ); + } + this->consume(")"); + + std::unique_ptr body = this->expression(); + return std::make_unique( + std::make_unique(address), + std::move(parameters), + std::move(body) + ); +} + +std::unique_ptr Parser::exprLoop() { + Token address = this->consume("loop"); + this->consume("("); + + std::unique_ptr initial = this->expression(); + this->consume(";"); + + std::unique_ptr condition = this->expression(); + this->consume(";"); + + std::unique_ptr postexpr = this->expression(); + this->consume(")"); + + std::unique_ptr body = this->expression(); + return std::make_unique( + std::make_unique(address), + std::move(initial), + std::move(condition), + std::move(postexpr), + std::move(body) + ); +} + +std::unique_ptr Parser::exprIf() { + Token address = this->consume("if"); + this->consume("("); + + std::unique_ptr condition = this->expression(); + this->consume(")"); + + std::unique_ptr thenExpr = this->expression(); + std::unique_ptr elseExpr = nullptr; + + if(this->isNext("else")) { + this->consume("else"); + elseExpr = this->expression(); + } + + return std::make_unique( + std::make_unique(address), + std::move(condition), + std::move(thenExpr), + std::move(elseExpr) + ); +} + +std::unique_ptr Parser::exprLiteral() { + std::unique_ptr expr = nullptr; + + if(this->isNext("true")) + expr = std::make_unique( + std::make_unique(this->consume("true")), + true + ); + else if(this->isNext("false")) + expr = std::make_unique( + std::make_unique(this->consume("false")), + false + ); + else if(this->isNext("maybe")) + expr = std::make_unique( + std::make_unique(this->consume("maybe")) + ); + else if(this->isNext("nil")) + expr = std::make_unique( + std::make_unique(this->consume("nil")) + ); + else if(this->peek().getType() == TokenType::STRING) { + Token stringToken = this->consume(TokenType::STRING); + expr = std::make_unique( + std::make_unique(stringToken), + stringToken.getImage() + ); + } + else if(this->peek().getType() == TokenType::DIGIT) { + Token digitToken = this->consume(TokenType::DIGIT); + expr = std::make_unique( + std::make_unique(digitToken), + ZhivoUtil::Convert::translateDigit(digitToken.getImage()) + ); + } + + if(!expr) + throw ParserException( + "Expecting expression, encountered " + + this->peek().getImage() + ); + + return expr; +} + +std::unique_ptr Parser::exprRandom() { + Token address = this->consume("random"); + std::unique_ptr thenExpr = this->expression(); + std::unique_ptr elseExpr = nullptr; + + if(this->isNext("else")) { + this->consume("else"); + elseExpr = this->expression(); + } + + return std::make_unique( + std::make_unique(address), + std::move(thenExpr), + std::move(elseExpr) + ); +} + +std::unique_ptr Parser::exprRender() { + Token address = this->consume("render"); + std::unique_ptr expression = this->expression(); + + return std::make_unique( + std::make_unique(address), + std::move(expression) + ); +} + +std::unique_ptr Parser::exprType() { + Token address = this->consume("type"); + std::unique_ptr expression = this->expression(); + + return std::make_unique( + std::make_unique(address), + std::move(expression) + ); +} + +std::unique_ptr Parser::exprUnless() { + Token address = this->consume("unless"); + this->consume("("); + + std::unique_ptr condition = this->expression(); + this->consume(")"); + + std::unique_ptr thenExpr = this->expression(); + std::unique_ptr elseExpr = nullptr; + + if(this->isNext("else")) { + this->consume("else"); + elseExpr = this->expression(); + } + + return std::make_unique( + std::make_unique(address), + std::move(condition), + std::move(thenExpr), + std::move(elseExpr) + ); +} + +std::unique_ptr Parser::exprWhen() { + Token address = this->consume("when"); + this->consume("("); + + std::unique_ptr expression = this->expression(); + this->consume(")"); + this->consume("{"); + + std::vector, std::unique_ptr>> cases; + std::unique_ptr defaultCase = nullptr; + + while(!this->isNext("}")) { + if(!cases.empty()) + this->consume(","); + + if(this->isNext("if")) { + this->consume("if"); + this->consume("("); + + std::unique_ptr caseExpr = this->expression(); + this->consume(")"); + + std::unique_ptr thenBlock = this->expression(); + cases.emplace_back(std::make_pair( + std::move(caseExpr), + std::move(thenBlock) + )); + } + else if(this->isNext("else")) { + if(defaultCase) + throw std::runtime_error("Cannot have more than one (1) else for when expression."); + + this->consume("else"); + defaultCase = this->expression(); + } + } + + return std::make_unique( + std::make_unique(address), + std::move(expression), + std::move(cases), + std::move(defaultCase) + ); +} + +std::unique_ptr Parser::exprWhile() { + Token address = this->consume("while"); + this->consume("("); + + std::unique_ptr condition = this->expression(); + this->consume(")"); + + return std::make_unique( + std::make_unique(address), + std::move(condition), + this->expression() + ); +} + +std::unique_ptr Parser::exprPrimary() { + std::unique_ptr expression = nullptr; + + if(this->isNext("+") || this->isNext("-") || this->isNext("~")) { + Token address = this->consume(TokenType::OPERATOR); + expression = std::make_unique( + std::make_unique(address), + std::move(std::string(address.getImage())), + this->expression() + ); + } + else if(this->isNext("(")) { + Token address = this->consume("("); + std::unique_ptr innerExpr = this->expression(); + + expression = std::make_unique( + std::make_unique(address), + std::move(innerExpr) + ); + this->consume(")"); + } + else if(this->isNext("{")) { + Token address = this->consume(TokenType::IDENTIFIER); + std::vector> statements; + + while(!this->isNext("}")) { + std::unique_ptr stmt = this->statement(); + statements.emplace_back(std::move(stmt)); + } + this->consume("}"); + + expression = std::make_unique( + std::make_unique(address), + std::move(statements) + ); + } + else if(this->isNext("render")) + expression = this->exprRender(); + else if(this->isNext("catch")) + expression = this->exprCatchHandle(); + else if(this->isNext("do")) + expression = this->exprDoWhile(); + else if(this->isNext("while")) + expression = this->exprWhile(); + else if(this->isNext("loop")) + expression = this->exprLoop(); + else if(this->isNext("unless")) + expression = this->exprUnless(); + else if(this->isNext("when")) + expression = this->exprWhen(); + else if(this->isNext("func")) + expression = this->exprFunctionDecl(); + else if(this->isNext("[")) + expression = this->exprArray(); + else if(this->peek().getType() == TokenType::IDENTIFIER) { + expression = std::make_unique( + std::make_unique(this->consume(TokenType::IDENTIFIER)) + ); + + while(this->isNext("[")) { + Token address = this->consume("["); + std::unique_ptr indexExpr = this->expression(); + + this->consume("]"); + expression = std::make_unique( + std::make_unique(address), + std::move(expression), + std::move(indexExpr) + ); + } + } + else expression = this->exprLiteral(); + + while(this->isNext("(") || this->isNext("[")) { + while(this->isNext("(")) { + Token address = this->consume("("); + std::vector> arguments; + + while(!this->isNext(")")) { + if(!arguments.empty()) + this->consume(","); + + arguments.emplace_back( + std::move(this->expression()) + ); + } + + this->consume(")"); + expression = std::make_unique( + std::make_unique(address), + std::move(expression), + std::move(arguments) + ); + } + + while(this->isNext("[")) { + Token address = this->consume("["); + std::unique_ptr indexExpr = this->expression(); + + this->consume("]"); + expression = std::make_unique( + std::make_unique(address), + std::move(expression), + std::move(indexExpr) + ); + } + } + + return expression; +} + +std::unique_ptr Parser::exprLogicOr() { + std::unique_ptr expression = this->exprLogicAnd(); + + while(this->isNext("||")) + expression = std::make_unique( + std::make_unique( + this->consume(TokenType::OPERATOR) + ), + std::move(expression), + "||", + std::move(this->exprLogicAnd()) + ); + + return expression; +} + +std::unique_ptr Parser::exprLogicAnd() { + std::unique_ptr expression = this->exprBitwiseOr(); + + while(this->isNext("&&")) + expression = std::make_unique( + std::make_unique( + this->consume(TokenType::OPERATOR) + ), + std::move(expression), + "&&", + std::move(this->exprBitwiseOr()) + ); + + return expression; +} + +std::unique_ptr Parser::exprBitwiseOr() { + std::unique_ptr expression = this->exprBitwiseXor(); + + while(this->isNext("|")) + expression = std::make_unique( + std::make_unique( + this->consume(TokenType::OPERATOR) + ), + std::move(expression), + "|", + std::move(this->exprBitwiseXor()) + ); + + return expression; +} + +std::unique_ptr Parser::exprBitwiseXor() { + std::unique_ptr expression = this->exprBitwiseAnd(); + + while(this->isNext("^")) + expression = std::make_unique( + std::make_unique( + this->consume(TokenType::OPERATOR) + ), + std::move(expression), + "^", + std::move(this->exprBitwiseAnd()) + ); + + return expression; +} + +std::unique_ptr Parser::exprBitwiseAnd() { + std::unique_ptr expression = this->exprNilCoalescing(); + + while(this->isNext("&")) + expression = std::make_unique( + std::make_unique( + this->consume(TokenType::OPERATOR) + ), + std::move(expression), + "&", + std::move(this->exprNilCoalescing()) + ); + + return expression; +} + +std::unique_ptr Parser::exprNilCoalescing() { + std::unique_ptr expression = this->exprEquality(); + + while(this->isNext("?")) + expression = std::make_unique( + std::make_unique( + this->consume(TokenType::OPERATOR) + ), + std::move(expression), + std::move(this->exprEquality()) + ); + + return expression; +} + +std::unique_ptr Parser::exprEquality() { + std::unique_ptr expression = this->exprComparison(); + + while(this->isNext("==") || this->isNext("!=") || this->isNext("=")) { + Token op = this->consume(TokenType::OPERATOR); + expression = std::make_unique( + std::make_unique(op), + std::move(expression), + op.getImage(), + std::move(this->exprComparison()) + ); + } + + return expression; +} + +std::unique_ptr Parser::exprComparison() { + std::unique_ptr expression = this->exprShift(); + + while(this->isNext("<") || + this->isNext("<=") || + this->isNext(">") || + this->isNext(">=") + ) { + Token op = this->consume(TokenType::OPERATOR); + expression = std::make_unique( + std::make_unique(op), + std::move(expression), + op.getImage(), + std::move(this->exprShift()) + ); + } + + return expression; +} + +std::unique_ptr Parser::exprShift() { + std::unique_ptr expression = this->exprTerm(); + + while(this->isNext("<<") || this->isNext(">>")) { + Token op = this->consume(TokenType::OPERATOR); + expression = std::make_unique( + std::make_unique(op), + std::move(expression), + op.getImage(), + std::move(this->exprTerm()) + ); + } + + return expression; +} + +std::unique_ptr Parser::exprTerm() { + std::unique_ptr expression = this->exprFactor(); + + while(this->isNext("+") || this->isNext("-")) { + Token op = this->consume(TokenType::OPERATOR); + expression = std::make_unique( + std::make_unique(op), + std::move(expression), + op.getImage(), + std::move(this->exprFactor()) + ); + } + + return expression; +} + +std::unique_ptr Parser::exprFactor() { + std::unique_ptr expression = this->exprPrimary(); + + while(this->isNext("*") || this->isNext("/") || this->isNext("%")) { + Token op = this->consume(TokenType::OPERATOR); + expression = std::make_unique( + std::make_unique(op), + std::move(expression), + op.getImage(), + std::move(this->exprPrimary()) + ); + } + + return expression; +} + +std::unique_ptr Parser::expression() { + return this->exprLogicOr(); +} + +std::unique_ptr Parser::stmtBreak() { + Token address = this->consume("break"); + this->consume(";"); + + return std::make_unique( + std::make_unique(address) + ); +} + +std::unique_ptr Parser::stmtContinue() { + Token address = this->consume("continue"); + this->consume(";"); + + return std::make_unique( + std::make_unique(address) + ); +} + +std::unique_ptr Parser::stmtRet() { + Token address = this->consume("ret"); + std::unique_ptr expression = this->expression(); + + this->consume(";"); + return std::make_unique( + std::make_unique(address), + std::move(expression) + ); +} + +std::unique_ptr Parser::stmtThrow() { + Token address = this->consume("throw"); + std::unique_ptr expression = this->expression(); + + this->consume(";"); + return std::make_unique( + std::make_unique(address), + std::move(expression) + ); +} + +std::unique_ptr Parser::stmtTest() { + Token address = this->consume("test"); + this->consume("("); + + std::unique_ptr testName = this->expression(); + this->consume(")"); + + std::unique_ptr testBody = this->expression(); + this->consume(";"); + + return std::make_unique( + std::make_unique(address), + std::move(testName), + std::move(testBody) + ); +} + +std::unique_ptr Parser::statement() { + if(this->isNext("break")) + return this->stmtBreak(); + else if(this->isNext("continue")) + return this->stmtContinue(); + else if(this->isNext("ret")) + return this->stmtRet(); + else if(this->isNext("throw")) + return this->stmtThrow(); + else if(this->isNext("test")) + return this->stmtTest(); + + std::unique_ptr expr = this->expression(); + this->consume(";"); + + return expr; +} + +void Parser::parse() { + while(!this->isAtEnd()) + this->globalStatements.push_back(this->statement()); +}