This repository has been archived on 2023-09-10. You can view files and clone it, but cannot push or open issues/pull-requests.
joko/lib/Parser.cpp

208 lines
4.3 KiB
C++

#include "Parser.hpp"
namespace jk
{
/*explicit*/ Parser::Parser(Logger& logger, std::shared_ptr<Lexer> lexer)
: m_logger { logger }
, m_lexer { lexer }
{
}
/*virtual*/ Parser::~Parser()
{
}
std::shared_ptr<Node> Parser::parse(std::string const& source)
{
std::shared_ptr<Node> tok;
m_cursor = 0;
m_lexer->scan(source);
while ( (tok=m_lexer->next()) )
{
m_tokens.push_back(tok);
}
if (m_tokens.empty())
{
return std::make_shared<Node>(NODE_PROG, "",
Loc {m_lexer->loc().path(), 1, 1});
}
return parse_prog();
}
std::shared_ptr<Node> Parser::current() const
{
assert(m_cursor < m_tokens.size());
return m_tokens[m_cursor];
}
Loc Parser::loc() const
{
return current()->loc();
}
std::shared_ptr<Node> Parser::consume()
{
assert(m_cursor < m_tokens.size());
auto tok = m_tokens[m_cursor];
m_cursor++;
return tok;
}
std::shared_ptr<Node> Parser::consume(NodeType type)
{
assert(m_cursor < m_tokens.size());
if (m_tokens[m_cursor]->type() != type)
{
std::stringstream ss;
ss << "expected '"
<< std::string(NodeTypeStr[type])
.substr(std::string("NODE_").size())
<< "', got '"
<< std::string(NodeTypeStr[m_tokens[m_cursor]->type()])
.substr(std::string("NODE_").size())
<< "'";
m_logger.log<syntax_error>(LOG_ERROR,
m_tokens[m_cursor]->loc(),
ss.str());
}
return consume();
}
bool Parser::type_is(NodeType type, int lookahead) const
{
if (m_cursor + lookahead >= m_tokens.size())
{
return false;
}
return m_tokens[m_cursor + lookahead]->type() == type;
}
std::shared_ptr<Node> Parser::parse_prog()
{
auto root = std::make_shared<Node>(NODE_PROG, "", loc());
while (m_cursor < m_tokens.size())
{
root->add_child(parse_expr());
}
return root;
}
std::shared_ptr<Node> Parser::parse_expr()
{
if (type_is(NODE_OPAR)
&& type_is(NODE_IDENT, 1))
{
return parse_funcall();
}
if (type_is(NODE_OPAR)
&& type_is(NODE_DECL, 1))
{
return parse_vardecl();
}
if (type_is(NODE_OPAR)
&& type_is(NODE_RARROW, 1))
{
return parse_lambda();
}
return parse_literal();
}
std::shared_ptr<Node> Parser::parse_vardecl()
{
auto root = std::make_shared<Node>(NODE_VARDECL, "", loc());
consume(NODE_OPAR);
consume(NODE_DECL);
root->add_child(consume(NODE_IDENT));
root->add_child(parse_expr());
consume(NODE_CPAR);
return root;
}
std::shared_ptr<Node> Parser::parse_lambda()
{
auto root = std::make_shared<Node>(NODE_LAMBDA, "", loc());
consume(NODE_OPAR);
consume(NODE_RARROW);
consume(NODE_OPAR);
root->add_child(parse_params());
consume(NODE_CPAR);
root->add_child(parse_body());
consume(NODE_CPAR);
return root;
}
std::shared_ptr<Node> Parser::parse_params()
{
auto root = std::make_shared<Node>(NODE_PARAMS, "", loc());
while (!type_is(NODE_CPAR))
{
root->add_child(consume(NODE_IDENT));
}
return root;
}
std::shared_ptr<Node> Parser::parse_body()
{
auto root = std::make_shared<Node>(NODE_BODY, "", loc());
while (!type_is(NODE_CPAR))
{
root->add_child(parse_expr());
}
return root;
}
std::shared_ptr<Node> Parser::parse_funcall()
{
auto root = std::make_shared<Node>(NODE_FUNCALL, "", loc());
consume(NODE_OPAR);
while (!type_is(NODE_CPAR))
{
root->add_child(parse_expr());
}
consume(NODE_CPAR);
return root;
}
std::shared_ptr<Node> Parser::parse_literal()
{
if (type_is(NODE_INT)
|| type_is(NODE_IDENT))
{
return consume();
}
m_logger.log<syntax_error>(LOG_ERROR,
loc(),
std::string()
+ "unexpected token '"
+ NodeTypeStr[current()->type()]
+ "' ('"
+ current()->repr()
+ "')");
abort();
}
}