Files
dlang-sqlite/dlang.sqlite/dlang/src/parser.cpp
T

651 lines
16 KiB
C++

#include "../parser.hpp"
#include <algorithm>
std::string LocationText(const Token& t)
{
return "at line " + std::to_string(t.line) + " column " + std::to_string(t.column);
}
Token& Parser::Current()
{
if (_pos < _tokens.size())
return _tokens[_pos];
throw std::runtime_error("Unidentified token!");
}
Token& Parser::Consume()
{
if (_pos < _tokens.size())
return _tokens[_pos++];
throw std::runtime_error("Unidentified token!");
}
Token& Parser::Peek(size_t offset)
{
if (_pos + offset < _tokens.size())
return _tokens[_pos + offset];
throw std::runtime_error("Unidentified token!");
}
bool Parser::Match(TokenType type, const std::string& value)
{
const auto& current = Current();
if (current.type != type || current.value != value)
return false;
Consume();
return true;
}
Token& Parser::ShouldBe(TokenType type, const std::string& value)
{
const auto& current = Current();
if (current.type != type)
throw std::runtime_error("Syntax Error: Expected token type '" + std::string(TokenTypeToString(type)) +
"' but got '" + std::string(TokenTypeToString(current.type)) +
"' (value: '" + current.value + "') " + LocationText(current));
if (!value.empty() && value != current.value)
throw std::runtime_error("Syntax Error: Expected specific value '" + value +
"' but got '" + current.value + "' " + LocationText(current));
return Consume();
}
bool Parser::Match(TokenType type, char value)
{
return Match(type, std::string(1, value));
}
Token& Parser::ShouldBe(TokenType type, char value)
{
return ShouldBe(type, std::string(1, value));
}
Parser::Parser(const std::vector<Token>& tokens) : _tokens(tokens) { }
Program Parser::ParseProgram()
{
Program program;
while (_pos < _tokens.size())
program.statements.push_back(ParseStatement());
return program;
}
using namespace Dlang::Language;
#pragma region STATEMENTS
std::unique_ptr<Statement> Parser::ParseStatement()
{
if (Match(TokenType::KEYWORD, kw_var))
return ParseVariableDeclaration();
if (Match(TokenType::KEYWORD, kw_while))
return ParseWhileDeclaration();
if (Match(TokenType::KEYWORD, kw_for))
return ParseForDeclaration();
if (Match(TokenType::KEYWORD, kw_foreach))
return ParseForeachDeclaration();
if (Match(TokenType::KEYWORD, kw_if))
return ParseIfDeclaration();
if (Match(TokenType::KEYWORD, kw_func))
return ParseFunctionDeclaration();
if (Match(TokenType::KEYWORD, kw_return))
return ParseReturnStatement();
if (Match(TokenType::KEYWORD, kw_include))
return ParseIncludeStatement();
auto expr = ParseExpression();
if (Match(TokenType::SYNTAX, op_equals))
{
auto op = Peek(-1).value;
if (!dynamic_cast<IdentifierExpression*>(expr.get()) &&
!dynamic_cast<MemberAccessExpression*>(expr.get()) &&
!dynamic_cast<IndexAccessExpression*>(expr.get()))
{
throw std::runtime_error("Invalid left-hand side in assignment");
}
auto value = ParseExpression();
ShouldBe(TokenType::SYNTAX, op_endl);
auto assignment = std::make_unique<Assignment>();
assignment->lhs = std::move(expr);
assignment->value = std::move(value);
assignment->assignmentOperator = op;
return assignment;
}
if (Match(TokenType::SYNTAX, op_add_assign) || Match(TokenType::SYNTAX, op_sub_assign) || Match(TokenType::SYNTAX, op_mul_assign) || Match(TokenType::SYNTAX, op_div_assign))
{
std::string op = Peek(-1).value;
if (!dynamic_cast<IdentifierExpression*>(expr.get()) &&
!dynamic_cast<MemberAccessExpression*>(expr.get()) &&
!dynamic_cast<IndexAccessExpression*>(expr.get()))
{
throw std::runtime_error("Invalid left-hand side in assignment");
}
auto value = ParseExpression();
ShouldBe(TokenType::SYNTAX, op_endl);
auto assignment = std::make_unique<Assignment>();
assignment->lhs = std::move(expr);
assignment->value = std::move(value);
assignment->assignmentOperator = op;
return assignment;
}
ShouldBe(TokenType::SYNTAX, op_endl);
auto stmt = std::make_unique<ExpressionStatement>();
stmt->expression = std::move(expr);
return stmt;
}
std::unique_ptr<Statement> Parser::ParseVariableDeclaration()
{
auto name = ShouldBe(TokenType::IDENTIFIER);
ShouldBe(TokenType::SYNTAX, op_equals);
auto initializer = ParseExpression();
ShouldBe(TokenType::SYNTAX, op_endl);
auto declaration = std::make_unique<VariableDeclaration>();
declaration->name = name.value;
declaration->initializer = std::move(initializer);
return declaration;
}
std::unique_ptr<Statement> Parser::ParseAssignment()
{
auto lhs = ParseExpression();
if (!dynamic_cast<IdentifierExpression*>(lhs.get()) &&
!dynamic_cast<MemberAccessExpression*>(lhs.get()))
{
throw std::runtime_error("Invalid left-hand side in assignment");
}
ShouldBe(TokenType::SYNTAX, op_equals);
auto value = ParseExpression();
ShouldBe(TokenType::SYNTAX, op_endl);
auto assignment = std::make_unique<Assignment>();
assignment->lhs = std::move(lhs);
assignment->value = std::move(value);
return assignment;
}
std::unique_ptr<Statement> Parser::ParseWhileDeclaration()
{
ShouldBe(TokenType::SYNTAX, op_exprstart);
auto stmt = std::make_unique<WhileStatement>();
stmt->condition = ParseExpression();
ShouldBe(TokenType::SYNTAX, op_exprend);
ShouldBe(TokenType::KEYWORD, kw_do);
while (!Match(TokenType::KEYWORD, kw_end))
stmt->body.push_back(ParseStatement());
return stmt;
}
std::unique_ptr<Statement> Parser::ParseForDeclaration()
{
ShouldBe(TokenType::SYNTAX, op_exprstart);
auto varName = ShouldBe(TokenType::IDENTIFIER);
ShouldBe(TokenType::SYNTAX, op_separator);
auto from = ShouldBe(TokenType::NUMBER);
ShouldBe(TokenType::SYNTAX, op_separator);
auto to = ShouldBe(TokenType::NUMBER);
auto stmt = std::make_unique<ForStatement>();
stmt->var = varName.value;
stmt->from = std::stod(from.value);
stmt->to = std::stod(to.value);
if (Match(TokenType::SYNTAX, op_separator))
{
auto step = ShouldBe(TokenType::NUMBER);
stmt->step = std::stod(step.value);
}
ShouldBe(TokenType::SYNTAX, op_exprend);
ShouldBe(TokenType::KEYWORD, kw_do);
while (!Match(TokenType::KEYWORD, kw_end))
stmt->body.push_back(ParseStatement());
return stmt;
}
std::unique_ptr<Statement> Parser::ParseForeachDeclaration()
{
ShouldBe(TokenType::SYNTAX, op_exprstart);
auto varName = ShouldBe(TokenType::IDENTIFIER);
if (Match(TokenType::KEYWORD, kw_in))
{
auto list = ShouldBe(TokenType::IDENTIFIER);
ShouldBe(TokenType::SYNTAX, op_exprend);
ShouldBe(TokenType::KEYWORD, kw_do);
auto stmt = std::make_unique<ForeachStatement>();
stmt->var = varName.value;
stmt->list = list.value;
while (!Match(TokenType::KEYWORD, kw_end))
stmt->body.push_back(ParseStatement());
return stmt;
}
else {
ShouldBe(TokenType::SYNTAX, op_separator);
auto value = ShouldBe(TokenType::IDENTIFIER);
ShouldBe(TokenType::KEYWORD, kw_in);
auto table = ShouldBe(TokenType::IDENTIFIER);
ShouldBe(TokenType::SYNTAX, op_exprend);
ShouldBe(TokenType::KEYWORD, kw_do);
auto stmt = std::make_unique<ForeachTableStatement>();
stmt->varKey = varName.value;
stmt->varValue = value.value;
stmt->table = table.value;
while (!Match(TokenType::KEYWORD, kw_end))
stmt->body.push_back(ParseStatement());
return stmt;
}
}
std::unique_ptr<Statement> Parser::ParseIfDeclaration()
{
ShouldBe(TokenType::SYNTAX, op_exprstart);
auto expr = ParseExpression();
ShouldBe(TokenType::SYNTAX, op_exprend);
ShouldBe(TokenType::KEYWORD, kw_then);
auto stmt = std::make_unique<IfStatement>();
stmt->expression = std::move(expr);
Token t;
while (!Match(TokenType::KEYWORD, kw_else) && !Match(TokenType::KEYWORD, kw_end))
stmt->body.push_back(ParseStatement());
if (Peek(-1).type == TokenType::KEYWORD && Peek(-1).value == kw_else)
{
if (Match(TokenType::KEYWORD, kw_if))
stmt->elseBody.push_back(ParseIfDeclaration());
else
while (!Match(TokenType::KEYWORD, kw_end))
stmt->elseBody.push_back(ParseStatement());
}
return stmt;
}
std::unique_ptr<Statement> Parser::ParseFunctionDeclaration()
{
auto funcName = ShouldBe(TokenType::IDENTIFIER);
ShouldBe(TokenType::SYNTAX, op_exprstart);
std::vector<std::string> params;
if (!Match(TokenType::SYNTAX, op_exprend))
{
do
{
Token param = ShouldBe(TokenType::IDENTIFIER);
params.push_back(param.value);
} while (Match(TokenType::SYNTAX, op_separator));
ShouldBe(TokenType::SYNTAX, op_exprend);
}
auto stmt = std::make_unique<FunctionStatement>();
stmt->name = funcName.value;
stmt->parameters = params;
while (!Match(TokenType::KEYWORD, kw_end))
stmt->body.push_back(ParseStatement());
return stmt;
}
std::unique_ptr<Statement> Parser::ParseReturnStatement()
{
auto stmt = std::make_unique<ReturnStatement>();
if (!Match(TokenType::SYNTAX, op_endl))
{
stmt->expression = ParseExpression();
ShouldBe(TokenType::SYNTAX, op_endl);
}
return stmt;
}
std::unique_ptr<Statement> Parser::ParseIncludeStatement()
{
auto stmt = std::make_unique<IncludeStatement>();
ShouldBe(TokenType::SYNTAX, op_exprstart);
auto path = ShouldBe(TokenType::STRING).value;
ShouldBe(TokenType::SYNTAX, op_exprend);
ShouldBe(TokenType::SYNTAX, op_endl);
stmt->path = path;
return stmt;
}
#pragma endregion
#pragma region EXPRESSIONS
std::unique_ptr<Expression> Parser::ParseFunctionCall(std::unique_ptr<Expression> callee)
{
auto stmt = std::make_unique<CallExpression>();
stmt->callee = std::move(callee);
if (!Match(TokenType::SYNTAX, op_exprend))
{
do {
stmt->expressions.push_back(ParseExpression());
} while (Match(TokenType::SYNTAX, op_separator));
if (!Match(TokenType::SYNTAX, op_exprend))
throw std::runtime_error("Expected ')' after arguments " + LocationText(Current()));
}
return stmt;
}
std::unique_ptr<Expression> Parser::ParseExpression()
{
return ParseLogicalAndOr();
}
std::unique_ptr<Expression> Parser::ParsePrimary()
{
if (Match(TokenType::SYNTAX, op_exprstart))
{
auto expression = ParseExpression();
if (!Match(TokenType::SYNTAX, op_exprend))
throw std::runtime_error("Expected ')' " + LocationText(Current()));
return expression;
}
if (Match(TokenType::SYNTAX, op_arraystart))
return ParseTableLiteral();
if (Match(TokenType::SYNTAX, op_liststart))
return ParseListLiteral();
if (Match(TokenType::KEYWORD, kw_func))
return ParseFunctionExpression();
if (Match(TokenType::SYNTAX, op_size))
return ParseSizeExpression();
const auto& current = Current();
if (current.type == TokenType::NUMBER)
{
auto token = ShouldBe(TokenType::NUMBER);
auto expression = std::make_unique<NumberExpression>();
expression->value = std::stod(token.value);
return expression;
}
if (current.type == TokenType::BOOLEAN)
{
auto token = ShouldBe(TokenType::BOOLEAN);
auto expression = std::make_unique<BooleanExpression>();
expression->value = (token.value == kw_true ? true : false);
return expression;
}
if (current.type == TokenType::STRING)
{
auto token = ShouldBe(TokenType::STRING);
auto expression = std::make_unique<StringExpression>();
expression->value = token.value;
return expression;
}
if (current.type == TokenType::IDENTIFIER)
{
auto token = ShouldBe(TokenType::IDENTIFIER);
auto idExpr = std::make_unique<IdentifierExpression>();
idExpr->name = token.value;
std::unique_ptr<Expression> left;
if (Match(TokenType::SYNTAX, op_exprstart))
left = ParseFunctionCall(std::move(idExpr));
else
left = std::move(idExpr);
while (Match(TokenType::SYNTAX, op_dot) || Match(TokenType::SYNTAX, op_liststart))
{
if (Peek(-1).value[0] == op_dot)
{
auto memberExpr = std::make_unique<MemberAccessExpression>();
memberExpr->object = std::move(left);
memberExpr->memberName = ShouldBe(TokenType::IDENTIFIER).value;
left = std::move(memberExpr);
if (Match(TokenType::SYNTAX, op_exprstart))
{
left = ParseFunctionCall(std::move(left));
}
}
else
{
auto indexExpr = ParseExpression();
ShouldBe(TokenType::SYNTAX, op_listend);
auto indexAccess = std::make_unique<IndexAccessExpression>();
indexAccess->object = std::move(left);
indexAccess->memberIndex = std::move(indexExpr);
left = std::move(indexAccess);
}
}
return left;
}
std::string tokenDesc = std::string(TokenTypeToString(current.type));
if (!current.value.empty()) {
tokenDesc += " ('" + current.value + "')";
}
throw std::runtime_error("Expected expression, but found unexpected token type " + tokenDesc + " " + LocationText(current));
}
std::unique_ptr<Expression> Parser::ParseMultiplicative()
{
auto left = ParsePrimary();
while (Current().type == TokenType::SYNTAX &&
(Current().value[0] == op_multi || Current().value[0] == op_div))
{
auto op = Consume();
auto right = ParsePrimary();
auto expression = std::make_unique<BinaryExpression>();
expression->left = std::move(left);
expression->op = op.value;
expression->right = std::move(right);
left = std::move(expression);
}
return left;
}
std::unique_ptr<Expression> Parser::ParseAdditive()
{
auto left = ParseMultiplicative();
while (Current().type == TokenType::SYNTAX &&
(Current().value[0] == op_add || Current().value[0] == op_sub))
{
auto op = Consume();
auto right = ParseMultiplicative();
auto expression = std::make_unique<BinaryExpression>();
expression->left = std::move(left);
expression->op = op.value;
expression->right = std::move(right);
left = std::move(expression);
}
return left;
}
std::unique_ptr<Expression> Parser::ParseComparison()
{
auto left = ParseAdditive();
while (
Match(TokenType::SYNTAX, op_above) ||
Match(TokenType::SYNTAX, op_below) ||
Match(TokenType::SYNTAX, op_eq) ||
Match(TokenType::SYNTAX, op_gte) ||
Match(TokenType::SYNTAX, op_lte) ||
Match(TokenType::SYNTAX, op_neq)
) {
auto op = Peek(-1);
auto right = ParseAdditive();
auto expr = std::make_unique<BinaryExpression>();
expr->left = std::move(left);
expr->op = op.value;
expr->right = std::move(right);
left = std::move(expr);
}
return left;
}
std::unique_ptr<Expression> Parser::ParseTableLiteral()
{
auto expr = std::make_unique<TableLiteralExpression>();
while (!Match(TokenType::SYNTAX, op_arrayend))
{
std::string key = ShouldBe(TokenType::IDENTIFIER).value;
ShouldBe(TokenType::SYNTAX, op_colon);
auto valueExpr = ParseExpression();
expr->fields.push_back({ key, std::move(valueExpr) });
Match(TokenType::SYNTAX, op_separator);
}
return expr;
}
std::unique_ptr<Expression> Parser::ParseListLiteral()
{
auto expr = std::make_unique<ListLiteralExpression>();
while (!Match(TokenType::SYNTAX, op_listend))
{
auto valueExpr = ParseExpression();
expr->fields.push_back(std::move(valueExpr));
Match(TokenType::SYNTAX, op_separator);
}
return expr;
}
std::unique_ptr<Expression> Parser::ParseLogicalAndOr()
{
auto left = ParseComparison();
while (Match(TokenType::SYNTAX, op_and) || Match(TokenType::SYNTAX, op_or))
{
auto op = Peek(-1);
auto right = ParseComparison();
auto expr = std::make_unique<BinaryExpression>();
expr->left = std::move(left);
expr->op = op.value;
expr->right = std::move(right);
left = std::move(expr);
}
return left;
}
std::unique_ptr<Expression> Parser::ParseFunctionExpression()
{
ShouldBe(TokenType::SYNTAX, op_exprstart);
std::vector<std::string> params;
if (!Match(TokenType::SYNTAX, op_exprend))
{
do
{
Token param = ShouldBe(TokenType::IDENTIFIER);
params.push_back(param.value);
} while (Match(TokenType::SYNTAX, op_separator));
ShouldBe(TokenType::SYNTAX, op_exprend);
}
auto expr = std::make_unique<FunctionExpression>();
expr->parameters = params;
while (!Match(TokenType::KEYWORD, kw_end))
expr->body.push_back(ParseStatement());
return expr;
}
std::unique_ptr<Expression> Parser::ParseSizeExpression()
{
auto target = ShouldBe(TokenType::IDENTIFIER).value;
auto stmt = std::make_unique<SizeExpression>();
stmt->identifier = target;
return stmt;
}
#pragma endregion