#include "Parser.hpp" #include "lib/Node.hpp" namespace wg { /*explicit*/ Parser::Parser() { } /*virtual*/ Parser::~Parser() { } std::shared_ptr Parser::parse(std::vector> 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 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(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(ss); } else { return consume(); } return nullptr; } std::shared_ptr 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 Parser::make_node(NodeType type) const { return std::make_shared(type, "", loc()); } std::shared_ptr Parser::parse_prog() { auto node = std::make_shared(NODE_PROG, "", Loc {}); while (m_cursor < m_tokens.size()) { node->add_child(parse_instr()); } return node; } std::shared_ptr 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 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 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 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 Parser::parse_ret() { auto node = make_node(NODE_RET); if (type_is(NODE_TYPE)) { node->add_child(consume()); } return node; } std::shared_ptr 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 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 Parser::parse_expr() { return parse_addsub(); } std::shared_ptr 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 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 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_INT) || 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(std::string() + "unknown literal '" + (NodeTypeStr[m_tokens[m_cursor]->type()] + strlen("NODE_")) + "'"); return nullptr; } std::shared_ptr 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 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 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; } }