449 lines
8.3 KiB
C++
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;
|
|
}
|
|
}
|