292 lines
7.1 KiB
C++
292 lines
7.1 KiB
C++
#include "elna/source/parser.hpp"
|
|
#include <stdexcept>
|
|
|
|
namespace elna::source
|
|
{
|
|
/**
|
|
* AST node.
|
|
*/
|
|
void node::accept(ParserVisitor *)
|
|
{
|
|
}
|
|
|
|
definition::definition(std::string&& identifier, std::unique_ptr<integer_literal>&& body)
|
|
: m_identifier(std::move(identifier)), m_body(std::move(body))
|
|
{
|
|
}
|
|
|
|
void definition::accept(ParserVisitor *visitor)
|
|
{
|
|
visitor->visit(this);
|
|
}
|
|
|
|
std::string& definition::identifier() noexcept
|
|
{
|
|
return m_identifier;
|
|
}
|
|
|
|
integer_literal& definition::body()
|
|
{
|
|
return *m_body;
|
|
}
|
|
|
|
block::block(std::vector<std::unique_ptr<definition>>&& definitions, std::unique_ptr<statement>&& body)
|
|
: m_definitions(std::move(definitions)), m_body(std::move(body))
|
|
{
|
|
}
|
|
|
|
void block::accept(ParserVisitor *visitor)
|
|
{
|
|
visitor->visit(this);
|
|
}
|
|
|
|
statement& block::body()
|
|
{
|
|
return *m_body;
|
|
}
|
|
|
|
std::vector<std::unique_ptr<definition>>& block::definitions() noexcept
|
|
{
|
|
return m_definitions;
|
|
}
|
|
|
|
integer_literal::integer_literal(const std::int32_t value)
|
|
: m_number(value)
|
|
{
|
|
}
|
|
|
|
void integer_literal::accept(ParserVisitor *visitor)
|
|
{
|
|
visitor->visit(this);
|
|
}
|
|
|
|
std::int32_t integer_literal::number() const noexcept
|
|
{
|
|
return m_number;
|
|
}
|
|
|
|
variable_expression::variable_expression(const std::string& name)
|
|
: m_name(name)
|
|
{
|
|
}
|
|
|
|
void variable_expression::accept(ParserVisitor *visitor)
|
|
{
|
|
visitor->visit(this);
|
|
}
|
|
|
|
const std::string& variable_expression::name() const noexcept
|
|
{
|
|
return m_name;
|
|
}
|
|
|
|
binary_expression::binary_expression(std::unique_ptr<expression>&& lhs,
|
|
std::unique_ptr<expression>&& rhs, const unsigned char operation)
|
|
: m_lhs(std::move(lhs)), m_rhs(std::move(rhs))
|
|
{
|
|
switch (operation)
|
|
{
|
|
case '+':
|
|
this->m_operator = binary_operator::sum;
|
|
break;
|
|
case '-':
|
|
this->m_operator = binary_operator::subtraction;
|
|
break;
|
|
case '*':
|
|
this->m_operator = binary_operator::multiplication;
|
|
break;
|
|
case '/':
|
|
this->m_operator = binary_operator::division;
|
|
break;
|
|
default:
|
|
throw std::logic_error("Invalid binary operator");
|
|
}
|
|
}
|
|
|
|
void binary_expression::accept(ParserVisitor *visitor)
|
|
{
|
|
visitor->visit(this);
|
|
}
|
|
|
|
expression& binary_expression::lhs()
|
|
{
|
|
return *m_lhs;
|
|
}
|
|
|
|
expression& binary_expression::rhs()
|
|
{
|
|
return *m_rhs;
|
|
}
|
|
|
|
binary_operator binary_expression::operation() const noexcept
|
|
{
|
|
return m_operator;
|
|
}
|
|
|
|
bang_statement::bang_statement(std::unique_ptr<expression>&& body)
|
|
: m_body(std::move(body))
|
|
{
|
|
}
|
|
|
|
void bang_statement::accept(ParserVisitor *visitor)
|
|
{
|
|
visitor->visit(this);
|
|
}
|
|
|
|
expression& bang_statement::body()
|
|
{
|
|
return *m_body;
|
|
}
|
|
|
|
parser::parser(const std::vector<token>& tokens)
|
|
: tokens(tokens.cbegin()), end(tokens.cend())
|
|
{
|
|
}
|
|
|
|
std::unique_ptr<block> parser::parse()
|
|
{
|
|
return parse_block();
|
|
}
|
|
|
|
std::unique_ptr<expression> parser::parse_factor()
|
|
{
|
|
if (tokens->of() == source::token::type::identifier)
|
|
{
|
|
auto result = std::make_unique<variable_expression>(tokens->identifier());
|
|
++tokens;
|
|
return result;
|
|
}
|
|
else if (tokens->of() == source::token::token::type::number)
|
|
{
|
|
auto result = std::make_unique<integer_literal>(tokens->number());
|
|
++tokens;
|
|
return result;
|
|
}
|
|
else if (tokens->of() == source::token::type::left_paren)
|
|
{
|
|
++tokens;
|
|
|
|
auto expression = parse_expression();
|
|
|
|
++tokens;
|
|
|
|
return expression;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<expression> parser::parse_term()
|
|
{
|
|
auto lhs = parse_factor();
|
|
if (lhs == nullptr || tokens == end || tokens->of() != source::token::type::factor_operator)
|
|
{
|
|
return lhs;
|
|
}
|
|
auto _operator = tokens->identifier()[0];
|
|
++tokens;
|
|
|
|
auto rhs = parse_factor();
|
|
if (rhs != nullptr)
|
|
{
|
|
return std::make_unique<binary_expression>(std::move(lhs),
|
|
std::move(rhs), _operator);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<expression> parser::parse_expression()
|
|
{
|
|
auto term = parse_term();
|
|
if (term == nullptr || tokens == end || tokens->of() != source::token::type::term_operator)
|
|
{
|
|
return term;
|
|
}
|
|
auto _operator = tokens->identifier()[0];
|
|
++tokens;
|
|
|
|
auto rhs = parse_expression();
|
|
|
|
if (rhs != nullptr)
|
|
{
|
|
return std::make_unique<binary_expression>(std::move(term),
|
|
std::move(rhs), _operator);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<definition> parser::parse_definition()
|
|
{
|
|
std::string definition_identifier = tokens->identifier(); // Copy.
|
|
|
|
++tokens;
|
|
++tokens; // Skip the equals sign.
|
|
|
|
if (tokens->of() == source::token::type::number)
|
|
{
|
|
auto result = std::make_unique<definition>(std::move(definition_identifier),
|
|
std::make_unique<integer_literal>(tokens->number()));
|
|
++tokens;
|
|
return result;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<statement> parser::parse_bang_statement()
|
|
{
|
|
if (tokens->of() == source::token::type::bang)
|
|
{
|
|
++tokens;
|
|
auto bang_body = parse_expression();
|
|
if (bang_body != nullptr)
|
|
{
|
|
return std::make_unique<bang_statement>(std::move(bang_body));
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::vector<std::unique_ptr<definition>> parser::parse_definitions()
|
|
{
|
|
++tokens; // Skip const.
|
|
|
|
std::vector<std::unique_ptr<definition>> definitions;
|
|
|
|
while (tokens != end)
|
|
{
|
|
auto parsed_definition = parse_definition();
|
|
if (parsed_definition == nullptr)
|
|
{
|
|
return definitions;
|
|
}
|
|
definitions.push_back(std::move(parsed_definition));
|
|
|
|
if (tokens->of() == source::token::type::semicolon)
|
|
{
|
|
break;
|
|
}
|
|
if (tokens->of() == source::token::type::comma)
|
|
{
|
|
++tokens;
|
|
}
|
|
}
|
|
|
|
return definitions;
|
|
}
|
|
|
|
std::unique_ptr<block> parser::parse_block()
|
|
{
|
|
std::vector<std::unique_ptr<definition>> definitions;
|
|
if (tokens->of() == source::token::type::let)
|
|
{
|
|
definitions = parse_definitions();
|
|
++tokens;
|
|
}
|
|
auto parsed_statement = parse_bang_statement();
|
|
if (parsed_statement == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
return std::make_unique<block>(std::move(definitions), std::move(parsed_statement));
|
|
}
|
|
}
|