Get rid of the raw pointers in the parser
This commit is contained in:
@ -1,254 +1,294 @@
|
||||
#include "elna/parser.hpp"
|
||||
#include "elna/source/parser.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace elna
|
||||
{
|
||||
namespace source
|
||||
{
|
||||
/**
|
||||
* AST node.
|
||||
*/
|
||||
void Node::accept(ParserVisitor *)
|
||||
void node::accept(ParserVisitor *)
|
||||
{
|
||||
}
|
||||
|
||||
void Definition::accept(ParserVisitor *visitor)
|
||||
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);
|
||||
}
|
||||
|
||||
void Block::accept(ParserVisitor *visitor)
|
||||
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);
|
||||
}
|
||||
|
||||
void Expression::accept(ParserVisitor *visitor)
|
||||
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);
|
||||
}
|
||||
|
||||
void Number::accept(ParserVisitor *visitor)
|
||||
std::int32_t integer_literal::number() const noexcept
|
||||
{
|
||||
return m_number;
|
||||
}
|
||||
|
||||
variable::variable(const std::string& name)
|
||||
: m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
void variable::accept(ParserVisitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
void Variable::accept(ParserVisitor *visitor)
|
||||
const std::string& variable::name() const noexcept
|
||||
{
|
||||
visitor->visit(this);
|
||||
return m_name;
|
||||
}
|
||||
|
||||
BinaryExpression::BinaryExpression(Expression *lhs, Expression *rhs, unsigned char _operator)
|
||||
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))
|
||||
{
|
||||
this->lhs = lhs;
|
||||
this->rhs = rhs;
|
||||
|
||||
switch (_operator)
|
||||
switch (operation)
|
||||
{
|
||||
case '+':
|
||||
this->_operator = BinaryOperator::sum;
|
||||
this->m_operator = binary_operator::sum;
|
||||
break;
|
||||
case '-':
|
||||
this->_operator = BinaryOperator::subtraction;
|
||||
this->m_operator = binary_operator::subtraction;
|
||||
break;
|
||||
case '*':
|
||||
this->_operator = BinaryOperator::multiplication;
|
||||
this->m_operator = binary_operator::multiplication;
|
||||
break;
|
||||
case '/':
|
||||
this->_operator = BinaryOperator::division;
|
||||
this->m_operator = binary_operator::division;
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("Invalid binary operator");
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryExpression::accept(ParserVisitor *visitor)
|
||||
void binary_expression::accept(ParserVisitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
void BangStatement::accept(ParserVisitor *visitor)
|
||||
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);
|
||||
}
|
||||
|
||||
Block *parse(lex::Token *tokenStream, std::size_t length)
|
||||
expression& bang_statement::body()
|
||||
{
|
||||
return parseBlock(&tokenStream, &length);
|
||||
return *m_body;
|
||||
}
|
||||
|
||||
Expression *parseFactor(lex::Token **tokens, size_t *length)
|
||||
parser::parser(const std::vector<token>& tokens)
|
||||
: tokens(tokens.cbegin()), end(tokens.cend())
|
||||
{
|
||||
if ((*tokens)[0].of() == lex::Token::type::identifier)
|
||||
{
|
||||
auto variable = new Variable();
|
||||
variable->identifier = (*tokens)[0].identifier();
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
return variable;
|
||||
}
|
||||
else if ((*tokens)[0].of() == lex::Token::Token::type::number)
|
||||
{
|
||||
auto number = new Number();
|
||||
number->value = (*tokens)[0].number();
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
return number;
|
||||
}
|
||||
else if ((*tokens)[0].of() == lex::Token::type::left_paren)
|
||||
{
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
}
|
||||
|
||||
auto expression = parseExpression(tokens, length);
|
||||
std::unique_ptr<block> parser::parse()
|
||||
{
|
||||
return parse_block();
|
||||
}
|
||||
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
std::unique_ptr<expression> parser::parse_factor()
|
||||
{
|
||||
if (tokens->of() == source::token::type::identifier)
|
||||
{
|
||||
auto result = std::make_unique<variable>(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;
|
||||
}
|
||||
|
||||
Expression *parseTerm(lex::Token **tokens, size_t *length)
|
||||
std::unique_ptr<expression> parser::parse_term()
|
||||
{
|
||||
auto lhs = parseFactor(tokens, length);
|
||||
if (lhs == nullptr || *length == 0 || (*tokens)[0].of() != lex::Token::type::factor_operator)
|
||||
auto lhs = parse_factor();
|
||||
if (lhs == nullptr || tokens == end || tokens->of() != source::token::type::factor_operator)
|
||||
{
|
||||
return lhs;
|
||||
}
|
||||
auto _operator = (*tokens)[0].identifier()[0];
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
auto _operator = tokens->identifier()[0];
|
||||
++tokens;
|
||||
|
||||
auto rhs = parseFactor(tokens, length);
|
||||
auto rhs = parse_factor();
|
||||
if (rhs != nullptr)
|
||||
{
|
||||
return new BinaryExpression(lhs, rhs, _operator);
|
||||
return std::make_unique<binary_expression>(std::move(lhs),
|
||||
std::move(rhs), _operator);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Expression *parseExpression(lex::Token **tokens, size_t *length)
|
||||
std::unique_ptr<expression> parser::parse_expression()
|
||||
{
|
||||
auto term = parseTerm(tokens, length);
|
||||
if (term == nullptr || *length == 0 || (*tokens)[0].of() != lex::Token::type::term_operator)
|
||||
auto term = parse_term();
|
||||
if (term == nullptr || tokens == end || tokens->of() != source::token::type::term_operator)
|
||||
{
|
||||
return term;
|
||||
}
|
||||
auto _operator = (*tokens)[0].identifier()[0];
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
auto _operator = tokens->identifier()[0];
|
||||
++tokens;
|
||||
|
||||
auto expression = parseExpression(tokens, length);
|
||||
auto rhs = parse_expression();
|
||||
|
||||
if (expression != nullptr)
|
||||
if (rhs != nullptr)
|
||||
{
|
||||
return new BinaryExpression(term, expression, _operator);
|
||||
return std::make_unique<binary_expression>(std::move(term),
|
||||
std::move(rhs), _operator);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Definition *parseDefinition(lex::Token **tokens, size_t *length)
|
||||
std::unique_ptr<definition> parser::parse_definition()
|
||||
{
|
||||
auto definition = new Definition();
|
||||
definition->identifier = (*tokens)[0].identifier(); // Copy.
|
||||
std::string definition_identifier = tokens->identifier(); // Copy.
|
||||
|
||||
++(*tokens);
|
||||
++(*tokens); // Skip the equals sign.
|
||||
*length -= 2;
|
||||
++tokens;
|
||||
++tokens; // Skip the equals sign.
|
||||
|
||||
if ((*tokens)[0].of() == lex::Token::type::number)
|
||||
if (tokens->of() == source::token::type::number)
|
||||
{
|
||||
auto number = new Number();
|
||||
number->value = (*tokens)[0].number();
|
||||
definition->number = number;
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
return definition;
|
||||
auto result = std::make_unique<definition>(std::move(definition_identifier),
|
||||
std::make_unique<integer_literal>(tokens->number()));
|
||||
++tokens;
|
||||
return result;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Statement *parseStatement(lex::Token **tokens, std::size_t *length)
|
||||
std::unique_ptr<statement> parser::parse_bang_statement()
|
||||
{
|
||||
if ((*tokens)[0].of() == lex::Token::type::bang)
|
||||
if (tokens->of() == source::token::type::bang)
|
||||
{
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
auto statement = new BangStatement();
|
||||
auto expression = parseExpression(tokens, length);
|
||||
if (expression != nullptr)
|
||||
++tokens;
|
||||
auto bang_body = parse_expression();
|
||||
if (bang_body != nullptr)
|
||||
{
|
||||
statement->expression = expression;
|
||||
return std::make_unique<bang_statement>(std::move(bang_body));
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Definition **parseDefinitions(lex::Token **tokens, size_t *length, size_t *resultLength)
|
||||
std::vector<std::unique_ptr<definition>> parser::parse_definitions()
|
||||
{
|
||||
++(*tokens); // Skip const.
|
||||
--(*length);
|
||||
++tokens; // Skip const.
|
||||
|
||||
Definition **definitions;
|
||||
*resultLength = 0;
|
||||
std::vector<std::unique_ptr<definition>> definitions;
|
||||
|
||||
while (*length != 0)
|
||||
while (tokens != end)
|
||||
{
|
||||
auto definition = parseDefinition(tokens, length);
|
||||
if (definition == nullptr)
|
||||
auto parsed_definition = parse_definition();
|
||||
if (parsed_definition == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
return definitions;
|
||||
}
|
||||
definitions = reinterpret_cast<Definition **>(
|
||||
realloc(definitions, (*resultLength + 1) * sizeof(Definition*)));
|
||||
definitions[(*resultLength)++] = definition;
|
||||
definitions.push_back(std::move(parsed_definition));
|
||||
|
||||
if ((*tokens)[0].of() == lex::Token::type::semicolon)
|
||||
if (tokens->of() == source::token::type::semicolon)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ((*tokens)[0].of() == lex::Token::type::comma)
|
||||
if (tokens->of() == source::token::type::comma)
|
||||
{
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
++tokens;
|
||||
}
|
||||
}
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
Block *parseBlock(lex::Token **tokens, std::size_t *length)
|
||||
std::unique_ptr<block> parser::parse_block()
|
||||
{
|
||||
auto block = new Block();
|
||||
if ((*tokens)[0].of() == lex::Token::type::let)
|
||||
std::vector<std::unique_ptr<definition>> definitions;
|
||||
if (tokens->of() == source::token::type::let)
|
||||
{
|
||||
size_t length_ = 0;
|
||||
auto constDefinitions = parseDefinitions(tokens, length, &length_);
|
||||
if (constDefinitions != nullptr)
|
||||
{
|
||||
block->definitionsLength = length_;
|
||||
block->definitions = constDefinitions;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
definitions = parse_definitions();
|
||||
++tokens;
|
||||
}
|
||||
auto statement = parseStatement(tokens, length);
|
||||
if (statement != nullptr)
|
||||
{
|
||||
block->statement = statement;
|
||||
}
|
||||
else
|
||||
auto parsed_statement = parse_bang_statement();
|
||||
if (parsed_statement == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return block;
|
||||
return std::make_unique<block>(std::move(definitions), std::move(parsed_statement));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user