Support failure tests
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
#include "elna/source/lexer.hpp"
|
||||
#include <cassert>
|
||||
#include <variant>
|
||||
#include <sstream>
|
||||
|
||||
@ -212,6 +213,60 @@ namespace elna::source
|
||||
|| of() == type::boolean;
|
||||
}
|
||||
|
||||
std::string token::to_string() const
|
||||
{
|
||||
switch (this->m_type)
|
||||
{
|
||||
case type::number:
|
||||
return "«number»";
|
||||
case type::boolean:
|
||||
return "«boolean»";
|
||||
case type::term_operator:
|
||||
return "«term_operator»";
|
||||
case type::let:
|
||||
return "«const»";
|
||||
case type::identifier:
|
||||
return "«identifier»";
|
||||
case type::equals:
|
||||
return "«=»";
|
||||
case type::var:
|
||||
return "«var»";
|
||||
case type::semicolon:
|
||||
return "«;»";
|
||||
case type::left_paren:
|
||||
return "«(»";
|
||||
case type::right_paren:
|
||||
return "«)»";
|
||||
case type::dot:
|
||||
return "«)»";
|
||||
case type::comma:
|
||||
return "«,»";
|
||||
case type::factor_operator:
|
||||
return "«*»";
|
||||
case type::eof:
|
||||
return "«EOF»";
|
||||
case type::begin:
|
||||
return "«begin»";
|
||||
case type::end:
|
||||
return "«end»";
|
||||
case type::assignment:
|
||||
return "«:=»";
|
||||
case type::colon:
|
||||
return "«:»";
|
||||
case type::when:
|
||||
return "«if»";
|
||||
case type::then:
|
||||
return "«then»";
|
||||
case type::_while:
|
||||
return "«while»";
|
||||
case type::_do:
|
||||
return "«do»";
|
||||
case type::procedure:
|
||||
return "«proc»";
|
||||
};
|
||||
assert(false);
|
||||
}
|
||||
|
||||
unexpected_character::unexpected_character(const std::string& character, const source::position position)
|
||||
: error(position), character(character)
|
||||
{
|
||||
@ -233,7 +288,7 @@ namespace elna::source
|
||||
|
||||
std::string unexpected_token::what() const
|
||||
{
|
||||
return "Unexpected token";
|
||||
return "Unexpected token " + m_token.to_string();
|
||||
}
|
||||
|
||||
lexer::lexer(std::vector<token>&& tokens, const position last_position)
|
||||
|
@ -49,9 +49,9 @@ namespace elna::source
|
||||
|
||||
void empty_visitor::visit(block *block)
|
||||
{
|
||||
for (const auto& block_definition : block->definitions())
|
||||
for (const auto& constant : block->definitions())
|
||||
{
|
||||
block_definition->accept(this);
|
||||
constant->accept(this);
|
||||
}
|
||||
for (const auto& block_declaration : block->declarations())
|
||||
{
|
||||
@ -83,9 +83,6 @@ namespace elna::source
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* AST node.
|
||||
*/
|
||||
void node::accept(parser_visitor *)
|
||||
{
|
||||
}
|
||||
@ -381,14 +378,26 @@ namespace elna::source
|
||||
|
||||
std::unique_ptr<program> parser::parse()
|
||||
{
|
||||
auto definitions = parse_definitions();
|
||||
auto constants = parse_constant_definitions();
|
||||
auto declarations = parse_declarations();
|
||||
auto procedures = parse_procedure_definitions();
|
||||
auto parsed_statement = parse_statement();
|
||||
|
||||
if (parsed_statement == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
std::vector<std::unique_ptr<definition>> definitions(constants.size() + procedures.size());
|
||||
std::vector<std::unique_ptr<definition>>::iterator definition = definitions.begin();
|
||||
|
||||
for (auto& constant : constants)
|
||||
{
|
||||
*definition++ = std::move(constant);
|
||||
}
|
||||
for (auto& procedure : procedures)
|
||||
{
|
||||
*definition++ = std::move(procedure);
|
||||
}
|
||||
return std::make_unique<program>(std::move(definitions),
|
||||
std::move(declarations), std::move(parsed_statement));
|
||||
}
|
||||
@ -492,6 +501,28 @@ namespace elna::source
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<procedure_definition> parser::parse_procedure_definition()
|
||||
{
|
||||
if (!iterator.skip(token::type::procedure))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
auto definition_identifier = iterator.advance(token::type::identifier);
|
||||
|
||||
if (!definition_identifier.has_value() || !iterator.skip(token::type::semicolon))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
auto definition_body = parse_block();
|
||||
|
||||
if (definition_body == nullptr || !iterator.skip(token::type::semicolon))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_unique<procedure_definition>(definition_identifier->get().identifier(),
|
||||
std::move(definition_body));
|
||||
}
|
||||
|
||||
std::unique_ptr<declaration> parser::parse_declaration()
|
||||
{
|
||||
auto declaration_identifier = iterator.advance(token::type::identifier);
|
||||
@ -641,9 +672,9 @@ namespace elna::source
|
||||
return std::make_unique<while_statement>(std::move(condition), std::move(body));
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<definition>> parser::parse_definitions()
|
||||
std::vector<std::unique_ptr<constant_definition>> parser::parse_constant_definitions()
|
||||
{
|
||||
std::vector<std::unique_ptr<definition>> definitions;
|
||||
std::vector<std::unique_ptr<constant_definition>> definitions;
|
||||
|
||||
if (iterator->of() != token::type::let)
|
||||
{
|
||||
@ -651,7 +682,7 @@ namespace elna::source
|
||||
}
|
||||
++iterator; // Skip const.
|
||||
|
||||
std::unique_ptr<definition> parsed_definition;
|
||||
std::unique_ptr<constant_definition> parsed_definition;
|
||||
while ((parsed_definition = parse_constant_definition()) != nullptr)
|
||||
{
|
||||
definitions.push_back(std::move(parsed_definition));
|
||||
@ -674,6 +705,23 @@ namespace elna::source
|
||||
return definitions;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<procedure_definition>> parser::parse_procedure_definitions()
|
||||
{
|
||||
std::vector<std::unique_ptr<procedure_definition>> definitions;
|
||||
|
||||
while (iterator.current(token::type::procedure))
|
||||
{
|
||||
auto parsed_definition = parse_procedure_definition();
|
||||
|
||||
if (parsed_definition == nullptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
definitions.push_back(std::move(parsed_definition));
|
||||
}
|
||||
return definitions;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<declaration>> parser::parse_declarations()
|
||||
{
|
||||
std::vector<std::unique_ptr<declaration>> declarations;
|
||||
@ -709,7 +757,7 @@ namespace elna::source
|
||||
|
||||
std::unique_ptr<block> parser::parse_block()
|
||||
{
|
||||
auto definitions = parse_definitions();
|
||||
auto constants = parse_constant_definitions();
|
||||
auto declarations = parse_declarations();
|
||||
auto parsed_statement = parse_statement();
|
||||
|
||||
@ -717,6 +765,13 @@ namespace elna::source
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
std::vector<std::unique_ptr<definition>> definitions(constants.size());
|
||||
std::vector<std::unique_ptr<definition>>::iterator definition = definitions.begin();
|
||||
|
||||
for (auto& constant : constants)
|
||||
{
|
||||
*definition++ = std::move(constant);
|
||||
}
|
||||
return std::make_unique<block>(std::move(definitions),
|
||||
std::move(declarations), std::move(parsed_statement));
|
||||
}
|
||||
|
Reference in New Issue
Block a user