Support surrounding begin and end
This commit is contained in:
parent
1af995eafd
commit
2d31c77c14
4
TODO
4
TODO
@ -8,6 +8,10 @@
|
|||||||
- Allow defining variables.
|
- Allow defining variables.
|
||||||
- Don't pass raw pointers to the visitor methods.
|
- Don't pass raw pointers to the visitor methods.
|
||||||
- Make error abstract and derive unexpected_token in the lex module from it.
|
- Make error abstract and derive unexpected_token in the lex module from it.
|
||||||
|
- Wrap the tokens in a struct with methods for incrementing and lookups.
|
||||||
|
- While loop.
|
||||||
|
- If condition.
|
||||||
|
- Grouping multiple statements with begin and end (compound_statement).
|
||||||
|
|
||||||
# Shell
|
# Shell
|
||||||
- Persist the history.
|
- Persist the history.
|
||||||
|
@ -209,6 +209,16 @@ namespace elna::source
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unexpected_token::unexpected_token(const token& token)
|
||||||
|
: error(token.position()), m_token(token)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string unexpected_token::what() const
|
||||||
|
{
|
||||||
|
return "Unexpected token";
|
||||||
|
}
|
||||||
|
|
||||||
source_result lex(const std::string& buffer)
|
source_result lex(const std::string& buffer)
|
||||||
{
|
{
|
||||||
std::vector<token> tokens;
|
std::vector<token> tokens;
|
||||||
@ -272,6 +282,14 @@ namespace elna::source
|
|||||||
{
|
{
|
||||||
tokens.emplace_back(token::type::var, iterator.position());
|
tokens.emplace_back(token::type::var, iterator.position());
|
||||||
}
|
}
|
||||||
|
else if (word == "begin")
|
||||||
|
{
|
||||||
|
tokens.emplace_back(token::type::begin, iterator.position());
|
||||||
|
}
|
||||||
|
else if (word == "end")
|
||||||
|
{
|
||||||
|
tokens.emplace_back(token::type::end, iterator.position());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tokens.emplace_back(token::type::identifier, word.c_str(), iterator.position());
|
tokens.emplace_back(token::type::identifier, word.c_str(), iterator.position());
|
||||||
@ -297,6 +315,8 @@ namespace elna::source
|
|||||||
}
|
}
|
||||||
++iterator;
|
++iterator;
|
||||||
}
|
}
|
||||||
|
tokens.push_back(token(token::type::eof, iterator.position()));
|
||||||
|
|
||||||
return source_result(std::move(tokens));
|
return source_result(std::move(tokens));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,26 @@ namespace elna::source
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
definition::definition(std::string&& identifier, std::unique_ptr<integer_literal>&& body)
|
declaration::declaration(const std::string& identifier)
|
||||||
|
: m_identifier(identifier)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& declaration::identifier() noexcept
|
||||||
|
{
|
||||||
|
return m_identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
definition::definition(const std::string& identifier, std::unique_ptr<integer_literal>&& body)
|
||||||
: m_identifier(std::move(identifier)), m_body(std::move(body))
|
: m_identifier(std::move(identifier)), m_body(std::move(body))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void declaration::accept(parser_visitor *visitor)
|
||||||
|
{
|
||||||
|
visitor->visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
void definition::accept(parser_visitor *visitor)
|
void definition::accept(parser_visitor *visitor)
|
||||||
{
|
{
|
||||||
visitor->visit(this);
|
visitor->visit(this);
|
||||||
@ -30,8 +45,10 @@ namespace elna::source
|
|||||||
return *m_body;
|
return *m_body;
|
||||||
}
|
}
|
||||||
|
|
||||||
block::block(std::vector<std::unique_ptr<definition>>&& definitions, std::unique_ptr<statement>&& body)
|
block::block(std::vector<std::unique_ptr<definition>>&& definitions,
|
||||||
: m_definitions(std::move(definitions)), m_body(std::move(body))
|
std::vector<std::unique_ptr<declaration>>&& declarations,
|
||||||
|
std::unique_ptr<statement>&& body)
|
||||||
|
: m_definitions(std::move(definitions)), m_declarations(std::move(declarations)), m_body(std::move(body))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +67,11 @@ namespace elna::source
|
|||||||
return m_definitions;
|
return m_definitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<declaration>>& block::declarations() noexcept
|
||||||
|
{
|
||||||
|
return m_declarations;
|
||||||
|
}
|
||||||
|
|
||||||
integer_literal::integer_literal(const std::int32_t value)
|
integer_literal::integer_literal(const std::int32_t value)
|
||||||
: m_number(value)
|
: m_number(value)
|
||||||
{
|
{
|
||||||
@ -138,6 +160,21 @@ namespace elna::source
|
|||||||
return *m_body;
|
return *m_body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compound_statement::compound_statement(std::vector<std::unique_ptr<statement>>&& statements)
|
||||||
|
: m_statements(std::move(statements))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void compound_statement::accept(parser_visitor *visitor)
|
||||||
|
{
|
||||||
|
visitor->visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<statement>>& compound_statement::statements()
|
||||||
|
{
|
||||||
|
return m_statements;
|
||||||
|
}
|
||||||
|
|
||||||
parser::parser(const std::vector<token>& tokens)
|
parser::parser(const std::vector<token>& tokens)
|
||||||
: tokens(tokens.cbegin()), end(tokens.cend())
|
: tokens(tokens.cbegin()), end(tokens.cend())
|
||||||
{
|
{
|
||||||
@ -215,14 +252,20 @@ namespace elna::source
|
|||||||
|
|
||||||
std::unique_ptr<definition> parser::parse_definition()
|
std::unique_ptr<definition> parser::parse_definition()
|
||||||
{
|
{
|
||||||
std::string definition_identifier = tokens->identifier(); // Copy.
|
auto definition_identifier = advance(token::type::identifier);
|
||||||
|
|
||||||
++tokens;
|
if (!definition_identifier.has_value())
|
||||||
++tokens; // Skip the equals sign.
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!skip(token::type::equals))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (tokens->of() == source::token::type::number)
|
if (tokens->of() == source::token::type::number)
|
||||||
{
|
{
|
||||||
auto result = std::make_unique<definition>(std::move(definition_identifier),
|
auto result = std::make_unique<definition>(definition_identifier.value().get().identifier(),
|
||||||
std::make_unique<integer_literal>(tokens->number()));
|
std::make_unique<integer_literal>(tokens->number()));
|
||||||
++tokens;
|
++tokens;
|
||||||
return result;
|
return result;
|
||||||
@ -230,61 +273,168 @@ namespace elna::source
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<statement> parser::parse_bang_statement()
|
std::unique_ptr<declaration> parser::parse_declaration()
|
||||||
|
{
|
||||||
|
auto declaration_identifier = advance(token::type::identifier);
|
||||||
|
|
||||||
|
if (!declaration_identifier.has_value())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return std::make_unique<declaration>(declaration_identifier.value().get().identifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<statement> parser::parse_statement()
|
||||||
{
|
{
|
||||||
if (tokens->of() == source::token::type::bang)
|
if (tokens->of() == source::token::type::bang)
|
||||||
{
|
{
|
||||||
++tokens;
|
return parse_bang_statement();
|
||||||
|
}
|
||||||
|
else if (tokens->of() == source::token::type::begin)
|
||||||
|
{
|
||||||
|
return parse_compound_statement();
|
||||||
|
}
|
||||||
|
errors.push_back(std::make_unique<unexpected_token>(unexpected_token{ *tokens }));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<bang_statement> parser::parse_bang_statement()
|
||||||
|
{
|
||||||
|
if (!advance(token::type::bang))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
auto bang_body = parse_expression();
|
auto bang_body = parse_expression();
|
||||||
|
|
||||||
if (bang_body != nullptr)
|
if (bang_body != nullptr)
|
||||||
{
|
{
|
||||||
return std::make_unique<bang_statement>(std::move(bang_body));
|
return std::make_unique<bang_statement>(std::move(bang_body));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<compound_statement> parser::parse_compound_statement()
|
||||||
|
{
|
||||||
|
if (!advance(token::type::begin))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto result = std::make_unique<compound_statement>();
|
||||||
|
std::unique_ptr<statement> next_statement;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if ((next_statement = parse_statement()) == nullptr)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
result->statements().push_back(std::move(next_statement));
|
||||||
|
}
|
||||||
|
while (tokens->of() != token::type::end);
|
||||||
|
++tokens;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<definition>> parser::parse_definitions()
|
std::vector<std::unique_ptr<definition>> parser::parse_definitions()
|
||||||
{
|
{
|
||||||
++tokens; // Skip const.
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<definition>> definitions;
|
std::vector<std::unique_ptr<definition>> definitions;
|
||||||
|
|
||||||
while (tokens != end)
|
if (tokens->of() != token::type::let)
|
||||||
{
|
|
||||||
auto parsed_definition = parse_definition();
|
|
||||||
if (parsed_definition == nullptr)
|
|
||||||
{
|
{
|
||||||
return definitions;
|
return definitions;
|
||||||
}
|
}
|
||||||
|
++tokens; // Skip const.
|
||||||
|
|
||||||
|
std::unique_ptr<definition> parsed_definition;
|
||||||
|
while ((parsed_definition = parse_definition()) != nullptr)
|
||||||
|
{
|
||||||
definitions.push_back(std::move(parsed_definition));
|
definitions.push_back(std::move(parsed_definition));
|
||||||
|
|
||||||
if (tokens->of() == source::token::type::semicolon)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (tokens->of() == source::token::type::comma)
|
if (tokens->of() == source::token::type::comma)
|
||||||
{
|
{
|
||||||
++tokens;
|
++tokens;
|
||||||
}
|
}
|
||||||
|
else if (tokens->of() == source::token::type::semicolon)
|
||||||
|
{
|
||||||
|
++tokens;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errors.push_back(std::make_unique<unexpected_token>(*tokens));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return definitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
return definitions;
|
std::vector<std::unique_ptr<declaration>> parser::parse_declarations()
|
||||||
|
{
|
||||||
|
std::vector<std::unique_ptr<declaration>> declarations;
|
||||||
|
|
||||||
|
if (tokens->of() != token::type::var)
|
||||||
|
{
|
||||||
|
return declarations;
|
||||||
|
}
|
||||||
|
++tokens; // Skip var.
|
||||||
|
|
||||||
|
std::unique_ptr<declaration> parsed_declaration;
|
||||||
|
while ((parsed_declaration = parse_declaration()) != nullptr)
|
||||||
|
{
|
||||||
|
declarations.push_back(std::move(parsed_declaration));
|
||||||
|
|
||||||
|
if (tokens->of() == token::type::comma)
|
||||||
|
{
|
||||||
|
++tokens;
|
||||||
|
}
|
||||||
|
else if (tokens->of() == token::type::semicolon)
|
||||||
|
{
|
||||||
|
++tokens;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errors.push_back(std::make_unique<unexpected_token>(*tokens));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return declarations;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<block> parser::parse_block()
|
std::unique_ptr<block> parser::parse_block()
|
||||||
{
|
{
|
||||||
std::vector<std::unique_ptr<definition>> definitions;
|
auto definitions = parse_definitions();
|
||||||
if (tokens->of() == source::token::type::let)
|
auto declarations = parse_declarations();
|
||||||
{
|
auto parsed_statement = parse_statement();
|
||||||
definitions = parse_definitions();
|
|
||||||
++tokens;
|
|
||||||
}
|
|
||||||
auto parsed_statement = parse_bang_statement();
|
|
||||||
if (parsed_statement == nullptr)
|
if (parsed_statement == nullptr)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return std::make_unique<block>(std::move(definitions), std::move(parsed_statement));
|
return std::make_unique<block>(std::move(definitions),
|
||||||
|
std::move(declarations), std::move(parsed_statement));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::reference_wrapper<const token>> parser::advance(const token::type token_type)
|
||||||
|
{
|
||||||
|
if (tokens->of() == token_type)
|
||||||
|
{
|
||||||
|
return std::make_optional<>(std::cref(*tokens++));
|
||||||
|
}
|
||||||
|
errors.push_back(std::make_unique<unexpected_token>(*tokens));
|
||||||
|
return std::optional<std::reference_wrapper<const token>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parser::skip(const token::type token_type)
|
||||||
|
{
|
||||||
|
if (tokens->of() == token_type)
|
||||||
|
{
|
||||||
|
++tokens;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
errors.push_back(std::make_unique<unexpected_token>(*tokens));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
namespace elna::source
|
namespace elna::source
|
||||||
{
|
{
|
||||||
|
name_collision::name_collision(const std::string& name, const position current, const position previous)
|
||||||
|
: error(current), name(name), previous(previous)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name_collision::what() const
|
||||||
|
{
|
||||||
|
return "Name '" + name + "' was already defined";
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<info> symbol_table::lookup(const std::string& name)
|
std::shared_ptr<info> symbol_table::lookup(const std::string& name)
|
||||||
{
|
{
|
||||||
auto entry = entries.find(name);
|
auto entry = entries.find(name);
|
||||||
@ -42,31 +52,49 @@ namespace elna::source
|
|||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable_info::variable_info(std::size_t offset)
|
||||||
|
: m_offset(offset)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
variable_info::~variable_info()
|
variable_info::~variable_info()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void name_analysis_visitor::visit(source::definition *definition)
|
std::size_t variable_info::offset() const noexcept
|
||||||
|
{
|
||||||
|
return m_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void name_analysis_visitor::visit(declaration *declaration)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void name_analysis_visitor::visit(source::bang_statement *statement)
|
void name_analysis_visitor::visit(definition *definition)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void name_analysis_visitor::visit(source::block *block)
|
void name_analysis_visitor::visit(bang_statement *statement)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void name_analysis_visitor::visit(source::integer_literal *number)
|
void name_analysis_visitor::visit(compound_statement *statement)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void name_analysis_visitor::visit(source::variable_expression *variable)
|
void name_analysis_visitor::visit(block *block)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void name_analysis_visitor::visit(source::binary_expression *expression)
|
void name_analysis_visitor::visit(integer_literal *number)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void name_analysis_visitor::visit(variable_expression *variable)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void name_analysis_visitor::visit(binary_expression *expression)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
tests/declare_variable.eln
Normal file
4
tests/declare_variable.eln
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
var x;
|
||||||
|
begin
|
||||||
|
! 5
|
||||||
|
end.
|
1
tests/expectations/declare_variable.txt
Normal file
1
tests/expectations/declare_variable.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
5
|
Loading…
Reference in New Issue
Block a user