This repository has been archived on 2024-03-07. You can view files and clone it, but cannot push or open issues/pull-requests.
wongola/lib/Parser.cpp

449 lines
8.3 KiB
C++

#include "Parser.hpp"
#include "lib/Node.hpp"
namespace wg
{
/*explicit*/ Parser::Parser()
{
}
/*virtual*/ Parser::~Parser()
{
}
std::shared_ptr<Node> Parser::parse(std::vector<std::shared_ptr<Node>>
const& tokens)
{
m_cursor = 0;
m_tokens = tokens;
return parse_prog();
}
Loc Parser::loc() const
{
if (m_cursor >= m_tokens.size())
{
return m_tokens.back()->loc();
}
return m_tokens[m_cursor]->loc();
}
std::shared_ptr<Node> Parser::consume(NodeType type)
{
if (m_cursor >= m_tokens.size())
{
std::stringstream ss;
ss << "type mismatch, expected '"
<< (NodeTypeStr[type] + strlen("NODE_"))
<< "', got nothing.";
loc().error<syntax_error>(ss);
}
auto current = m_tokens[m_cursor];
if (current->type() != type)
{
std::stringstream ss;
ss << "type mismatch, expected '"
<< (NodeTypeStr[type] + strlen("NODE_"))
<< "', got '"
<< (NodeTypeStr[current->type()] + strlen("NODE_"))
<< "'";
loc().error<syntax_error>(ss);
}
else
{
return consume();
}
return nullptr;
}
std::shared_ptr<Node> Parser::consume()
{
WG_ASSERT(m_cursor < m_tokens.size(), "cannot consume");
auto node = m_tokens[m_cursor];
m_cursor++;
return node;
}
bool Parser::type_is(NodeType type, int lookahead)
{
if (m_cursor + lookahead >= m_tokens.size())
{
return false;
}
return m_tokens[m_cursor + lookahead]->type() == type;
}
bool Parser::type_isnt(NodeType type, int lookahead)
{
return !type_is(type, lookahead);
}
std::shared_ptr<Node> Parser::make_node(NodeType type) const
{
return std::make_shared<Node>(type, "", loc());
}
std::shared_ptr<Node> Parser::parse_prog()
{
auto node = std::make_shared<Node>(NODE_PROG, "", Loc {});
while (m_cursor < m_tokens.size())
{
node->add_child(parse_instr());
}
return node;
}
std::shared_ptr<Node> Parser::parse_instr()
{
if (type_is(NODE_HASH))
{
return parse_dir();
}
if (type_is(NODE_FUN))
{
return parse_fundecl();
}
if (type_is(NODE_RETURN))
{
auto node = consume();
node->add_child(parse_expr());
consume(NODE_SEMICOLON);
return node;
}
if (type_is(NODE_EXTERN))
{
auto node = parse_extern();
consume(NODE_SEMICOLON);
return node;
}
auto expr = parse_expr();
consume(NODE_SEMICOLON);
return expr;
}
std::shared_ptr<Node> Parser::parse_extern()
{
auto node = consume(NODE_EXTERN);
consume(NODE_FUN);
node->add_child(consume(NODE_IDENT));
consume(NODE_OPAR);
node->add_child(parse_params());
consume(NODE_CPAR);
node->add_child(parse_ret());
return node;
}
std::shared_ptr<Node> Parser::parse_fundecl()
{
auto node = make_node(NODE_FUNDECL);
consume(NODE_FUN);
node->add_child(consume(NODE_IDENT));
consume(NODE_OPAR);
node->add_child(parse_params());
consume(NODE_CPAR);
node->add_child(parse_ret());
node->add_child(parse_block());
return node;
}
std::shared_ptr<Node> Parser::parse_params()
{
auto node = make_node(NODE_PARAMS);
if (type_is(NODE_CPAR))
{
return node;
}
node->add_child(consume(NODE_IDENT));
if (type_is(NODE_TYPE))
{
node->add_child(consume());
}
while (type_is(NODE_COMMA))
{
consume();
node->add_child(consume(NODE_IDENT));
if (type_is(NODE_TYPE))
{
node->add_child(consume());
}
}
return node;
}
std::shared_ptr<Node> Parser::parse_ret()
{
auto node = make_node(NODE_RET);
if (type_is(NODE_TYPE))
{
node->add_child(consume());
}
return node;
}
std::shared_ptr<Node> Parser::parse_block()
{
auto node = make_node(NODE_BLOCK);
consume(NODE_OBRACE);
while (type_isnt(NODE_CBRACE))
{
node->add_child(parse_instr());
}
consume(NODE_CBRACE);
return node;
}
std::shared_ptr<Node> Parser::parse_dir()
{
auto node = make_node(NODE_DIR);
consume(NODE_HASH);
node->add_child(consume(NODE_IDENT));
node->add_child(parse_expr());
if (type_is(NODE_AS))
{
consume();
node->add_child(consume(NODE_IDENT));
}
return node;
}
std::shared_ptr<Node> Parser::parse_expr()
{
return parse_or();
}
std::shared_ptr<Node> Parser::parse_or()
{
auto lhs = parse_and();
while (type_is(NODE_OR))
{
auto node = consume();
node->add_child(lhs);
node->add_child(parse_and());
lhs = node;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_and()
{
auto lhs = parse_eqne();
while (type_is(NODE_AND))
{
auto node = consume();
node->add_child(lhs);
node->add_child(parse_eqne());
lhs = node;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_eqne()
{
auto lhs = parse_cmp();
if (type_is(NODE_EQ)
|| type_is(NODE_NE))
{
auto node = consume();
node->add_child(lhs);
node->add_child(parse_cmp());
lhs = node;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_cmp()
{
auto lhs = parse_addsub();
if (type_is(NODE_LT)
|| type_is(NODE_LE)
|| type_is(NODE_GT)
|| type_is(NODE_GE))
{
auto node = consume();
node->add_child(lhs);
node->add_child(parse_addsub());
lhs = node;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_addsub()
{
auto lhs = parse_muldivmod();
while (type_is(NODE_ADD)
|| type_is(NODE_SUB))
{
auto node = consume();
node->add_child(lhs);
node->add_child(parse_muldivmod());
lhs = node;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_muldivmod()
{
auto lhs = parse_literal();
while (type_is(NODE_MUL)
|| type_is(NODE_DIV)
|| type_is(NODE_MOD))
{
auto node = consume();
node->add_child(lhs);
node->add_child(parse_literal());
lhs = node;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_literal()
{
if (type_is(NODE_IDENT)
&& type_is(NODE_OPAR, 1))
{
return parse_call();
}
if (type_is(NODE_IDENT)
&& type_is(NODE_DOT, 1))
{
return parse_ns();
}
if (type_is(NODE_NOT))
{
auto node = consume();
node->add_child(parse_literal());
return node;
}
if (type_is(NODE_INT)
|| type_is(NODE_BOOL)
|| type_is(NODE_IDENT))
{
return consume();
}
// Groups
if (type_is(NODE_OPAR))
{
consume(NODE_OPAR);
auto expr = parse_expr();
consume(NODE_CPAR);
return expr;
}
loc().error<syntax_error>(std::string()
+ "unknown literal '"
+ (NodeTypeStr[m_tokens[m_cursor]->type()]
+ strlen("NODE_"))
+ "'");
return nullptr;
}
std::shared_ptr<Node> Parser::parse_call()
{
auto node = make_node(NODE_CALL);
node->add_child(consume(NODE_IDENT));
consume(NODE_OPAR);
node->add_child(parse_args());
consume(NODE_CPAR);
return node;
}
std::shared_ptr<Node> Parser::parse_args()
{
auto node = make_node(NODE_ARGS);
if (type_is(NODE_CPAR))
{
return node;
}
node->add_child(parse_expr());
while (type_is(NODE_COMMA))
{
consume();
node->add_child(parse_expr());
}
return node;
}
std::shared_ptr<Node> Parser::parse_ns()
{
auto node = make_node(NODE_NS);
node->add_child(consume(NODE_IDENT));
while (type_is(NODE_DOT))
{
consume();
if (type_is(NODE_IDENT)
&& type_is(NODE_OPAR, 1))
{
node->add_child(parse_call());
}
else
{
node->add_child(consume(NODE_IDENT));
}
}
return node;
}
}