2023-09-09 13:09:43 +00:00
|
|
|
#include "Parser.hpp"
|
|
|
|
|
|
|
|
namespace jk
|
|
|
|
{
|
|
|
|
/*explicit*/ Parser::Parser(Logger& logger, std::shared_ptr<Lexer> lexer)
|
|
|
|
: m_logger { logger }
|
|
|
|
, m_lexer { lexer }
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*virtual*/ Parser::~Parser()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-09-09 22:03:28 +00:00
|
|
|
std::shared_ptr<Node> Parser::parse(std::string const& source)
|
2023-09-09 13:09:43 +00:00
|
|
|
{
|
2023-09-09 22:03:28 +00:00
|
|
|
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())
|
|
|
|
{
|
2023-09-10 06:06:34 +00:00
|
|
|
root->add_child(parse_expr());
|
2023-09-09 22:03:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<Node> Parser::parse_expr()
|
|
|
|
{
|
2023-09-10 09:10:30 +00:00
|
|
|
if (type_is(NODE_OPAR)
|
|
|
|
&& type_is(NODE_DECL, 1)
|
|
|
|
&& type_is(NODE_OPAR, 2))
|
|
|
|
{
|
|
|
|
return parse_fundecl();
|
|
|
|
}
|
|
|
|
|
2023-09-10 06:06:34 +00:00
|
|
|
if (type_is(NODE_OPAR)
|
|
|
|
&& type_is(NODE_IDENT, 1))
|
2023-09-09 22:03:28 +00:00
|
|
|
{
|
|
|
|
return parse_funcall();
|
|
|
|
}
|
|
|
|
|
2023-09-10 06:06:34 +00:00
|
|
|
if (type_is(NODE_OPAR)
|
|
|
|
&& type_is(NODE_DECL, 1))
|
|
|
|
{
|
|
|
|
return parse_vardecl();
|
|
|
|
}
|
|
|
|
|
2023-09-10 07:59:51 +00:00
|
|
|
if (type_is(NODE_OPAR)
|
|
|
|
&& type_is(NODE_RARROW, 1))
|
|
|
|
{
|
|
|
|
return parse_lambda();
|
|
|
|
}
|
|
|
|
|
2023-09-09 22:03:28 +00:00
|
|
|
return parse_literal();
|
|
|
|
}
|
|
|
|
|
2023-09-10 06:06:34 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-09-10 09:10:30 +00:00
|
|
|
std::shared_ptr<Node> Parser::parse_fundecl()
|
|
|
|
{
|
|
|
|
consume(NODE_OPAR);
|
|
|
|
consume(NODE_DECL);
|
|
|
|
|
|
|
|
consume(NODE_OPAR);
|
|
|
|
auto ident = consume(NODE_IDENT);
|
|
|
|
auto params = parse_params();
|
|
|
|
|
|
|
|
consume(NODE_CPAR);
|
|
|
|
|
|
|
|
auto body = parse_body();
|
|
|
|
consume(NODE_CPAR);
|
|
|
|
|
|
|
|
auto vardecl = std::make_shared<Node>(NODE_VARDECL, "", ident->loc());
|
|
|
|
vardecl->add_child(ident);
|
|
|
|
|
|
|
|
auto lambda = std::make_shared<Node>(NODE_LAMBDA, "", ident->loc());
|
|
|
|
lambda->add_child(params);
|
|
|
|
lambda->add_child(body);
|
|
|
|
vardecl->add_child(lambda);
|
|
|
|
|
|
|
|
return vardecl;
|
|
|
|
}
|
|
|
|
|
2023-09-10 07:59:51 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-09-09 22:03:28 +00:00
|
|
|
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)
|
2023-09-10 12:39:23 +00:00
|
|
|
|| type_is(NODE_BOOL)
|
2023-09-09 22:03:28 +00:00
|
|
|
|| type_is(NODE_IDENT))
|
|
|
|
{
|
|
|
|
return consume();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_logger.log<syntax_error>(LOG_ERROR,
|
|
|
|
loc(),
|
|
|
|
std::string()
|
|
|
|
+ "unexpected token '"
|
2023-09-10 06:06:34 +00:00
|
|
|
+ NodeTypeStr[current()->type()]
|
|
|
|
+ "' ('"
|
2023-09-09 22:03:28 +00:00
|
|
|
+ current()->repr()
|
2023-09-10 06:06:34 +00:00
|
|
|
+ "')");
|
2023-09-09 22:03:28 +00:00
|
|
|
|
|
|
|
abort();
|
2023-09-09 13:09:43 +00:00
|
|
|
}
|
|
|
|
}
|