1036 lines
25 KiB
C++
1036 lines
25 KiB
C++
//===-- GoParser.cpp ---------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include <vector>
|
|
|
|
#include "GoParser.h"
|
|
|
|
#include "lldb/Core/Error.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "Plugins/ExpressionParser/Go/GoAST.h"
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb;
|
|
|
|
namespace
|
|
{
|
|
llvm::StringRef
|
|
DescribeToken(GoLexer::TokenType t)
|
|
{
|
|
switch (t)
|
|
{
|
|
case GoLexer::TOK_EOF:
|
|
return "<eof>";
|
|
case GoLexer::TOK_IDENTIFIER:
|
|
return "identifier";
|
|
case GoLexer::LIT_FLOAT:
|
|
return "float";
|
|
case GoLexer::LIT_IMAGINARY:
|
|
return "imaginary";
|
|
case GoLexer::LIT_INTEGER:
|
|
return "integer";
|
|
case GoLexer::LIT_RUNE:
|
|
return "rune";
|
|
case GoLexer::LIT_STRING:
|
|
return "string";
|
|
default:
|
|
return GoLexer::LookupToken(t);
|
|
}
|
|
}
|
|
} // namespace
|
|
|
|
class GoParser::Rule
|
|
{
|
|
public:
|
|
Rule(llvm::StringRef name, GoParser *p) : m_name(name), m_parser(p), m_pos(p->m_pos) {}
|
|
|
|
std::nullptr_t
|
|
error()
|
|
{
|
|
if (!m_parser->m_failed)
|
|
{
|
|
// Set m_error in case this is the top level.
|
|
if (m_parser->m_last_tok == GoLexer::TOK_INVALID)
|
|
m_parser->m_error = m_parser->m_last;
|
|
else
|
|
m_parser->m_error = DescribeToken(m_parser->m_last_tok);
|
|
// And set m_last in case it isn't.
|
|
m_parser->m_last = m_name;
|
|
m_parser->m_last_tok = GoLexer::TOK_INVALID;
|
|
m_parser->m_pos = m_pos;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
private:
|
|
llvm::StringRef m_name;
|
|
GoParser *m_parser;
|
|
size_t m_pos;
|
|
};
|
|
|
|
GoParser::GoParser(const char *src) : m_lexer(src), m_pos(0), m_failed(false)
|
|
{
|
|
}
|
|
|
|
GoASTStmt *
|
|
GoParser::Statement()
|
|
{
|
|
Rule r("Statement", this);
|
|
GoLexer::TokenType t = peek();
|
|
GoASTStmt *ret = nullptr;
|
|
switch (t)
|
|
{
|
|
case GoLexer::TOK_EOF:
|
|
case GoLexer::OP_SEMICOLON:
|
|
case GoLexer::OP_RPAREN:
|
|
case GoLexer::OP_RBRACE:
|
|
case GoLexer::TOK_INVALID:
|
|
return EmptyStmt();
|
|
case GoLexer::OP_LBRACE:
|
|
return Block();
|
|
|
|
/* TODO:
|
|
case GoLexer::KEYWORD_GO:
|
|
return GoStmt();
|
|
case GoLexer::KEYWORD_RETURN:
|
|
return ReturnStmt();
|
|
case GoLexer::KEYWORD_BREAK:
|
|
case GoLexer::KEYWORD_CONTINUE:
|
|
case GoLexer::KEYWORD_GOTO:
|
|
case GoLexer::KEYWORD_FALLTHROUGH:
|
|
return BranchStmt();
|
|
case GoLexer::KEYWORD_IF:
|
|
return IfStmt();
|
|
case GoLexer::KEYWORD_SWITCH:
|
|
return SwitchStmt();
|
|
case GoLexer::KEYWORD_SELECT:
|
|
return SelectStmt();
|
|
case GoLexer::KEYWORD_FOR:
|
|
return ForStmt();
|
|
case GoLexer::KEYWORD_DEFER:
|
|
return DeferStmt();
|
|
case GoLexer::KEYWORD_CONST:
|
|
case GoLexer::KEYWORD_TYPE:
|
|
case GoLexer::KEYWORD_VAR:
|
|
return DeclStmt();
|
|
case GoLexer::TOK_IDENTIFIER:
|
|
if ((ret = LabeledStmt()) ||
|
|
(ret = ShortVarDecl()))
|
|
{
|
|
return ret;
|
|
}
|
|
*/
|
|
default:
|
|
break;
|
|
}
|
|
GoASTExpr *expr = Expression();
|
|
if (expr == nullptr)
|
|
return r.error();
|
|
if (/*(ret = SendStmt(expr)) ||*/
|
|
(ret = IncDecStmt(expr)) || (ret = Assignment(expr)) || (ret = ExpressionStmt(expr)))
|
|
{
|
|
return ret;
|
|
}
|
|
delete expr;
|
|
return r.error();
|
|
}
|
|
|
|
GoASTStmt *
|
|
GoParser::ExpressionStmt(GoASTExpr *e)
|
|
{
|
|
if (Semicolon())
|
|
return new GoASTExprStmt(e);
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTStmt *
|
|
GoParser::IncDecStmt(GoASTExpr *e)
|
|
{
|
|
Rule r("IncDecStmt", this);
|
|
if (match(GoLexer::OP_PLUS_PLUS))
|
|
return Semicolon() ? new GoASTIncDecStmt(e, GoLexer::OP_PLUS_PLUS) : r.error();
|
|
if (match(GoLexer::OP_MINUS_MINUS))
|
|
return Semicolon() ? new GoASTIncDecStmt(e, GoLexer::OP_MINUS_MINUS) : r.error();
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTStmt *
|
|
GoParser::Assignment(lldb_private::GoASTExpr *e)
|
|
{
|
|
Rule r("Assignment", this);
|
|
std::vector<std::unique_ptr<GoASTExpr>> lhs;
|
|
for (GoASTExpr *l = MoreExpressionList(); l; l = MoreExpressionList())
|
|
lhs.push_back(std::unique_ptr<GoASTExpr>(l));
|
|
switch (peek())
|
|
{
|
|
case GoLexer::OP_EQ:
|
|
case GoLexer::OP_PLUS_EQ:
|
|
case GoLexer::OP_MINUS_EQ:
|
|
case GoLexer::OP_PIPE_EQ:
|
|
case GoLexer::OP_CARET_EQ:
|
|
case GoLexer::OP_STAR_EQ:
|
|
case GoLexer::OP_SLASH_EQ:
|
|
case GoLexer::OP_PERCENT_EQ:
|
|
case GoLexer::OP_LSHIFT_EQ:
|
|
case GoLexer::OP_RSHIFT_EQ:
|
|
case GoLexer::OP_AMP_EQ:
|
|
case GoLexer::OP_AMP_CARET_EQ:
|
|
break;
|
|
default:
|
|
return r.error();
|
|
}
|
|
// We don't want to own e until we know this is an assignment.
|
|
std::unique_ptr<GoASTAssignStmt> stmt(new GoASTAssignStmt(false));
|
|
stmt->AddLhs(e);
|
|
for (auto &l : lhs)
|
|
stmt->AddLhs(l.release());
|
|
for (GoASTExpr *r = Expression(); r; r = MoreExpressionList())
|
|
stmt->AddRhs(r);
|
|
if (!Semicolon() || stmt->NumRhs() == 0)
|
|
return new GoASTBadStmt;
|
|
return stmt.release();
|
|
}
|
|
|
|
GoASTStmt *
|
|
GoParser::EmptyStmt()
|
|
{
|
|
if (match(GoLexer::TOK_EOF))
|
|
return nullptr;
|
|
if (Semicolon())
|
|
return new GoASTEmptyStmt;
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTStmt *
|
|
GoParser::GoStmt()
|
|
{
|
|
if (match(GoLexer::KEYWORD_GO))
|
|
{
|
|
if (GoASTCallExpr *e = llvm::dyn_cast_or_null<GoASTCallExpr>(Expression()))
|
|
{
|
|
return FinishStmt(new GoASTGoStmt(e));
|
|
}
|
|
m_last = "call expression";
|
|
m_failed = true;
|
|
return new GoASTBadStmt();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTStmt *
|
|
GoParser::ReturnStmt()
|
|
{
|
|
if (match(GoLexer::KEYWORD_RETURN))
|
|
{
|
|
std::unique_ptr<GoASTReturnStmt> r(new GoASTReturnStmt());
|
|
for (GoASTExpr *e = Expression(); e; e = MoreExpressionList())
|
|
r->AddResults(e);
|
|
return FinishStmt(r.release());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTStmt *
|
|
GoParser::BranchStmt()
|
|
{
|
|
GoLexer::Token *tok;
|
|
if ((tok = match(GoLexer::KEYWORD_BREAK)) || (tok = match(GoLexer::KEYWORD_CONTINUE)) ||
|
|
(tok = match(GoLexer::KEYWORD_GOTO)))
|
|
{
|
|
auto *e = Identifier();
|
|
if (tok->m_type == GoLexer::KEYWORD_GOTO && !e)
|
|
return syntaxerror();
|
|
return FinishStmt(new GoASTBranchStmt(e, tok->m_type));
|
|
}
|
|
if ((tok = match(GoLexer::KEYWORD_FALLTHROUGH)))
|
|
return FinishStmt(new GoASTBranchStmt(nullptr, tok->m_type));
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTIdent *
|
|
GoParser::Identifier()
|
|
{
|
|
if (auto *tok = match(GoLexer::TOK_IDENTIFIER))
|
|
return new GoASTIdent(*tok);
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::MoreExpressionList()
|
|
{
|
|
if (match(GoLexer::OP_COMMA))
|
|
{
|
|
auto *e = Expression();
|
|
if (!e)
|
|
return syntaxerror();
|
|
return e;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTIdent *
|
|
GoParser::MoreIdentifierList()
|
|
{
|
|
if (match(GoLexer::OP_COMMA))
|
|
{
|
|
auto *i = Identifier();
|
|
if (!i)
|
|
return syntaxerror();
|
|
return i;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::Expression()
|
|
{
|
|
Rule r("Expression", this);
|
|
if (GoASTExpr *ret = OrExpr())
|
|
return ret;
|
|
return r.error();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::UnaryExpr()
|
|
{
|
|
switch (peek())
|
|
{
|
|
case GoLexer::OP_PLUS:
|
|
case GoLexer::OP_MINUS:
|
|
case GoLexer::OP_BANG:
|
|
case GoLexer::OP_CARET:
|
|
case GoLexer::OP_STAR:
|
|
case GoLexer::OP_AMP:
|
|
case GoLexer::OP_LT_MINUS:
|
|
{
|
|
const GoLexer::Token t = next();
|
|
if (GoASTExpr *e = UnaryExpr())
|
|
{
|
|
if (t.m_type == GoLexer::OP_STAR)
|
|
return new GoASTStarExpr(e);
|
|
else
|
|
return new GoASTUnaryExpr(t.m_type, e);
|
|
}
|
|
return syntaxerror();
|
|
}
|
|
default:
|
|
return PrimaryExpr();
|
|
}
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::OrExpr()
|
|
{
|
|
std::unique_ptr<GoASTExpr> l(AndExpr());
|
|
if (l)
|
|
{
|
|
while (match(GoLexer::OP_PIPE_PIPE))
|
|
{
|
|
GoASTExpr *r = AndExpr();
|
|
if (r)
|
|
l.reset(new GoASTBinaryExpr(l.release(), r, GoLexer::OP_PIPE_PIPE));
|
|
else
|
|
return syntaxerror();
|
|
}
|
|
return l.release();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::AndExpr()
|
|
{
|
|
std::unique_ptr<GoASTExpr> l(RelExpr());
|
|
if (l)
|
|
{
|
|
while (match(GoLexer::OP_AMP_AMP))
|
|
{
|
|
GoASTExpr *r = RelExpr();
|
|
if (r)
|
|
l.reset(new GoASTBinaryExpr(l.release(), r, GoLexer::OP_AMP_AMP));
|
|
else
|
|
return syntaxerror();
|
|
}
|
|
return l.release();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::RelExpr()
|
|
{
|
|
std::unique_ptr<GoASTExpr> l(AddExpr());
|
|
if (l)
|
|
{
|
|
for (GoLexer::Token *t; (t = match(GoLexer::OP_EQ_EQ)) || (t = match(GoLexer::OP_BANG_EQ)) ||
|
|
(t = match(GoLexer::OP_LT)) || (t = match(GoLexer::OP_LT_EQ)) ||
|
|
(t = match(GoLexer::OP_GT)) || (t = match(GoLexer::OP_GT_EQ));)
|
|
{
|
|
GoLexer::TokenType op = t->m_type;
|
|
GoASTExpr *r = AddExpr();
|
|
if (r)
|
|
l.reset(new GoASTBinaryExpr(l.release(), r, op));
|
|
else
|
|
return syntaxerror();
|
|
}
|
|
return l.release();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::AddExpr()
|
|
{
|
|
std::unique_ptr<GoASTExpr> l(MulExpr());
|
|
if (l)
|
|
{
|
|
for (GoLexer::Token *t; (t = match(GoLexer::OP_PLUS)) || (t = match(GoLexer::OP_MINUS)) ||
|
|
(t = match(GoLexer::OP_PIPE)) || (t = match(GoLexer::OP_CARET));)
|
|
{
|
|
GoLexer::TokenType op = t->m_type;
|
|
GoASTExpr *r = MulExpr();
|
|
if (r)
|
|
l.reset(new GoASTBinaryExpr(l.release(), r, op));
|
|
else
|
|
return syntaxerror();
|
|
}
|
|
return l.release();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::MulExpr()
|
|
{
|
|
std::unique_ptr<GoASTExpr> l(UnaryExpr());
|
|
if (l)
|
|
{
|
|
for (GoLexer::Token *t; (t = match(GoLexer::OP_STAR)) || (t = match(GoLexer::OP_SLASH)) ||
|
|
(t = match(GoLexer::OP_PERCENT)) || (t = match(GoLexer::OP_LSHIFT)) ||
|
|
(t = match(GoLexer::OP_RSHIFT)) || (t = match(GoLexer::OP_AMP)) ||
|
|
(t = match(GoLexer::OP_AMP_CARET));)
|
|
{
|
|
GoLexer::TokenType op = t->m_type;
|
|
GoASTExpr *r = UnaryExpr();
|
|
if (r)
|
|
l.reset(new GoASTBinaryExpr(l.release(), r, op));
|
|
else
|
|
return syntaxerror();
|
|
}
|
|
return l.release();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::PrimaryExpr()
|
|
{
|
|
GoASTExpr *l;
|
|
GoASTExpr *r;
|
|
(l = Conversion()) || (l = Operand());
|
|
if (!l)
|
|
return nullptr;
|
|
while ((r = Selector(l)) || (r = IndexOrSlice(l)) || (r = TypeAssertion(l)) || (r = Arguments(l)))
|
|
{
|
|
l = r;
|
|
}
|
|
return l;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::Operand()
|
|
{
|
|
GoLexer::Token *lit;
|
|
if ((lit = match(GoLexer::LIT_INTEGER)) || (lit = match(GoLexer::LIT_FLOAT)) ||
|
|
(lit = match(GoLexer::LIT_IMAGINARY)) || (lit = match(GoLexer::LIT_RUNE)) || (lit = match(GoLexer::LIT_STRING)))
|
|
return new GoASTBasicLit(*lit);
|
|
if (match(GoLexer::OP_LPAREN))
|
|
{
|
|
GoASTExpr *e;
|
|
if (!((e = Expression()) && match(GoLexer::OP_RPAREN)))
|
|
return syntaxerror();
|
|
return e;
|
|
}
|
|
// MethodExpr should be handled by Selector
|
|
if (GoASTExpr *e = CompositeLit())
|
|
return e;
|
|
if (GoASTExpr *n = Name())
|
|
return n;
|
|
return FunctionLit();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::FunctionLit()
|
|
{
|
|
if (!match(GoLexer::KEYWORD_FUNC))
|
|
return nullptr;
|
|
auto *sig = Signature();
|
|
if (!sig)
|
|
return syntaxerror();
|
|
auto *body = Block();
|
|
if (!body)
|
|
{
|
|
delete sig;
|
|
return syntaxerror();
|
|
}
|
|
return new GoASTFuncLit(sig, body);
|
|
}
|
|
|
|
GoASTBlockStmt *
|
|
GoParser::Block()
|
|
{
|
|
if (!match(GoLexer::OP_LBRACE))
|
|
return nullptr;
|
|
std::unique_ptr<GoASTBlockStmt> block(new GoASTBlockStmt);
|
|
for (auto *s = Statement(); s; s = Statement())
|
|
block->AddList(s);
|
|
if (!match(GoLexer::OP_RBRACE))
|
|
return syntaxerror();
|
|
return block.release();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::CompositeLit()
|
|
{
|
|
Rule r("CompositeLit", this);
|
|
GoASTExpr *type;
|
|
(type = StructType()) || (type = ArrayOrSliceType(true)) || (type = MapType()) || (type = Name());
|
|
if (!type)
|
|
return r.error();
|
|
GoASTCompositeLit *lit = LiteralValue();
|
|
if (!lit)
|
|
return r.error();
|
|
lit->SetType(type);
|
|
return lit;
|
|
}
|
|
|
|
GoASTCompositeLit *
|
|
GoParser::LiteralValue()
|
|
{
|
|
if (!match(GoLexer::OP_LBRACE))
|
|
return nullptr;
|
|
std::unique_ptr<GoASTCompositeLit> lit(new GoASTCompositeLit);
|
|
for (GoASTExpr *e = Element(); e; e = Element())
|
|
{
|
|
lit->AddElts(e);
|
|
if (!match(GoLexer::OP_COMMA))
|
|
break;
|
|
}
|
|
if (!mustMatch(GoLexer::OP_RBRACE))
|
|
return nullptr;
|
|
return lit.release();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::Element()
|
|
{
|
|
GoASTExpr *key;
|
|
if (!((key = Expression()) || (key = LiteralValue())))
|
|
return nullptr;
|
|
if (!match(GoLexer::OP_COLON))
|
|
return key;
|
|
GoASTExpr *value;
|
|
if ((value = Expression()) || (value = LiteralValue()))
|
|
return new GoASTKeyValueExpr(key, value);
|
|
delete key;
|
|
return syntaxerror();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::Selector(GoASTExpr *e)
|
|
{
|
|
Rule r("Selector", this);
|
|
if (match(GoLexer::OP_DOT))
|
|
{
|
|
if (auto *name = Identifier())
|
|
return new GoASTSelectorExpr(e, name);
|
|
}
|
|
return r.error();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::IndexOrSlice(GoASTExpr *e)
|
|
{
|
|
Rule r("IndexOrSlice", this);
|
|
if (match(GoLexer::OP_LBRACK))
|
|
{
|
|
std::unique_ptr<GoASTExpr> i1(Expression()), i2, i3;
|
|
bool slice = false;
|
|
if (match(GoLexer::OP_COLON))
|
|
{
|
|
slice = true;
|
|
i2.reset(Expression());
|
|
if (i2 && match(GoLexer::OP_COLON))
|
|
{
|
|
i3.reset(Expression());
|
|
if (!i3)
|
|
return syntaxerror();
|
|
}
|
|
}
|
|
if (!(slice || i1))
|
|
return syntaxerror();
|
|
if (!mustMatch(GoLexer::OP_RBRACK))
|
|
return nullptr;
|
|
if (slice)
|
|
{
|
|
bool slice3 = i3.get();
|
|
return new GoASTSliceExpr(e, i1.release(), i2.release(), i3.release(), slice3);
|
|
}
|
|
return new GoASTIndexExpr(e, i1.release());
|
|
}
|
|
return r.error();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::TypeAssertion(GoASTExpr *e)
|
|
{
|
|
Rule r("TypeAssertion", this);
|
|
if (match(GoLexer::OP_DOT) && match(GoLexer::OP_LPAREN))
|
|
{
|
|
if (auto *t = Type())
|
|
{
|
|
if (!mustMatch(GoLexer::OP_RPAREN))
|
|
return nullptr;
|
|
return new GoASTTypeAssertExpr(e, t);
|
|
}
|
|
return syntaxerror();
|
|
}
|
|
return r.error();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::Arguments(GoASTExpr *e)
|
|
{
|
|
if (match(GoLexer::OP_LPAREN))
|
|
{
|
|
std::unique_ptr<GoASTCallExpr> call(new GoASTCallExpr(false));
|
|
GoASTExpr *arg;
|
|
// ( ExpressionList | Type [ "," ExpressionList ] )
|
|
for ((arg = Expression()) || (arg = Type()); arg; arg = MoreExpressionList())
|
|
{
|
|
call->AddArgs(arg);
|
|
}
|
|
if (match(GoLexer::OP_DOTS))
|
|
call->SetEllipsis(true);
|
|
|
|
// Eat trailing comma
|
|
match(GoLexer::OP_COMMA);
|
|
|
|
if (!mustMatch(GoLexer::OP_RPAREN))
|
|
return nullptr;
|
|
call->SetFun(e);
|
|
return call.release();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::Conversion()
|
|
{
|
|
Rule r("Conversion", this);
|
|
if (GoASTExpr *t = Type2())
|
|
{
|
|
if (match(GoLexer::OP_LPAREN))
|
|
{
|
|
GoASTExpr *v = Expression();
|
|
if (!v)
|
|
return syntaxerror();
|
|
match(GoLexer::OP_COMMA);
|
|
if (!mustMatch(GoLexer::OP_RPAREN))
|
|
return r.error();
|
|
GoASTCallExpr *call = new GoASTCallExpr(false);
|
|
call->SetFun(t);
|
|
call->AddArgs(v);
|
|
return call;
|
|
}
|
|
}
|
|
return r.error();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::Type2()
|
|
{
|
|
switch (peek())
|
|
{
|
|
case GoLexer::OP_LBRACK:
|
|
return ArrayOrSliceType(false);
|
|
case GoLexer::KEYWORD_STRUCT:
|
|
return StructType();
|
|
case GoLexer::KEYWORD_FUNC:
|
|
return FunctionType();
|
|
case GoLexer::KEYWORD_INTERFACE:
|
|
return InterfaceType();
|
|
case GoLexer::KEYWORD_MAP:
|
|
return MapType();
|
|
case GoLexer::KEYWORD_CHAN:
|
|
return ChanType2();
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::ArrayOrSliceType(bool allowEllipsis)
|
|
{
|
|
Rule r("ArrayType", this);
|
|
if (match(GoLexer::OP_LBRACK))
|
|
{
|
|
std::unique_ptr<GoASTExpr> len;
|
|
if (allowEllipsis && match(GoLexer::OP_DOTS))
|
|
{
|
|
len.reset(new GoASTEllipsis(nullptr));
|
|
}
|
|
else
|
|
{
|
|
len.reset(Expression());
|
|
}
|
|
|
|
if (!match(GoLexer::OP_RBRACK))
|
|
return r.error();
|
|
GoASTExpr *elem = Type();
|
|
if (!elem)
|
|
return syntaxerror();
|
|
return new GoASTArrayType(len.release(), elem);
|
|
}
|
|
return r.error();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::StructType()
|
|
{
|
|
if (!(match(GoLexer::KEYWORD_STRUCT) && mustMatch(GoLexer::OP_LBRACE)))
|
|
return nullptr;
|
|
std::unique_ptr<GoASTFieldList> fields(new GoASTFieldList);
|
|
while (auto *field = FieldDecl())
|
|
fields->AddList(field);
|
|
if (!mustMatch(GoLexer::OP_RBRACE))
|
|
return nullptr;
|
|
return new GoASTStructType(fields.release());
|
|
}
|
|
|
|
GoASTField *
|
|
GoParser::FieldDecl()
|
|
{
|
|
std::unique_ptr<GoASTField> f(new GoASTField);
|
|
GoASTExpr *t = FieldNamesAndType(f.get());
|
|
if (!t)
|
|
t = AnonymousFieldType();
|
|
if (!t)
|
|
return nullptr;
|
|
|
|
if (auto *tok = match(GoLexer::LIT_STRING))
|
|
f->SetTag(new GoASTBasicLit(*tok));
|
|
if (!Semicolon())
|
|
return syntaxerror();
|
|
return f.release();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::FieldNamesAndType(GoASTField *field)
|
|
{
|
|
Rule r("FieldNames", this);
|
|
for (auto *id = Identifier(); id; id = MoreIdentifierList())
|
|
field->AddNames(id);
|
|
if (m_failed)
|
|
return nullptr;
|
|
GoASTExpr *t = Type();
|
|
if (t)
|
|
return t;
|
|
return r.error();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::AnonymousFieldType()
|
|
{
|
|
bool pointer = match(GoLexer::OP_STAR);
|
|
GoASTExpr *t = Type();
|
|
if (!t)
|
|
return nullptr;
|
|
if (pointer)
|
|
return new GoASTStarExpr(t);
|
|
return t;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::FunctionType()
|
|
{
|
|
if (!match(GoLexer::KEYWORD_FUNC))
|
|
return nullptr;
|
|
return Signature();
|
|
}
|
|
|
|
GoASTFuncType *
|
|
GoParser::Signature()
|
|
{
|
|
auto *params = Params();
|
|
if (!params)
|
|
return syntaxerror();
|
|
auto *result = Params();
|
|
if (!result)
|
|
{
|
|
if (auto *t = Type())
|
|
{
|
|
result = new GoASTFieldList;
|
|
auto *f = new GoASTField;
|
|
f->SetType(t);
|
|
result->AddList(f);
|
|
}
|
|
}
|
|
return new GoASTFuncType(params, result);
|
|
}
|
|
|
|
GoASTFieldList *
|
|
GoParser::Params()
|
|
{
|
|
if (!match(GoLexer::OP_LPAREN))
|
|
return nullptr;
|
|
std::unique_ptr<GoASTFieldList> l(new GoASTFieldList);
|
|
while (GoASTField *p = ParamDecl())
|
|
{
|
|
l->AddList(p);
|
|
if (!match(GoLexer::OP_COMMA))
|
|
break;
|
|
}
|
|
if (!mustMatch(GoLexer::OP_RPAREN))
|
|
return nullptr;
|
|
return l.release();
|
|
}
|
|
|
|
GoASTField *
|
|
GoParser::ParamDecl()
|
|
{
|
|
std::unique_ptr<GoASTField> field(new GoASTField);
|
|
GoASTIdent *id = Identifier();
|
|
if (id)
|
|
{
|
|
// Try `IdentifierList [ "..." ] Type`.
|
|
// If that fails, backtrack and try `[ "..." ] Type`.
|
|
Rule r("NamedParam", this);
|
|
for (; id; id = MoreIdentifierList())
|
|
field->AddNames(id);
|
|
GoASTExpr *t = ParamType();
|
|
if (t)
|
|
{
|
|
field->SetType(t);
|
|
return field.release();
|
|
}
|
|
field.reset(new GoASTField);
|
|
r.error();
|
|
}
|
|
GoASTExpr *t = ParamType();
|
|
if (t)
|
|
{
|
|
field->SetType(t);
|
|
return field.release();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::ParamType()
|
|
{
|
|
bool dots = match(GoLexer::OP_DOTS);
|
|
GoASTExpr *t = Type();
|
|
if (!dots)
|
|
return t;
|
|
if (!t)
|
|
return syntaxerror();
|
|
return new GoASTEllipsis(t);
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::InterfaceType()
|
|
{
|
|
if (!match(GoLexer::KEYWORD_INTERFACE) || !mustMatch(GoLexer::OP_LBRACE))
|
|
return nullptr;
|
|
std::unique_ptr<GoASTFieldList> methods(new GoASTFieldList);
|
|
while (true)
|
|
{
|
|
Rule r("MethodSpec", this);
|
|
// ( identifier Signature | TypeName ) ;
|
|
std::unique_ptr<GoASTIdent> id(Identifier());
|
|
if (!id)
|
|
break;
|
|
GoASTExpr *type = Signature();
|
|
if (!type)
|
|
{
|
|
r.error();
|
|
id.reset();
|
|
type = Name();
|
|
}
|
|
if (!Semicolon())
|
|
return syntaxerror();
|
|
auto *f = new GoASTField;
|
|
if (id)
|
|
f->AddNames(id.release());
|
|
f->SetType(type);
|
|
methods->AddList(f);
|
|
}
|
|
if (!mustMatch(GoLexer::OP_RBRACE))
|
|
return nullptr;
|
|
return new GoASTInterfaceType(methods.release());
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::MapType()
|
|
{
|
|
if (!(match(GoLexer::KEYWORD_MAP) && mustMatch(GoLexer::OP_LBRACK)))
|
|
return nullptr;
|
|
std::unique_ptr<GoASTExpr> key(Type());
|
|
if (!key)
|
|
return syntaxerror();
|
|
if (!mustMatch(GoLexer::OP_RBRACK))
|
|
return nullptr;
|
|
auto *elem = Type();
|
|
if (!elem)
|
|
return syntaxerror();
|
|
return new GoASTMapType(key.release(), elem);
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::ChanType()
|
|
{
|
|
Rule r("chan", this);
|
|
if (match(GoLexer::OP_LT_MINUS))
|
|
{
|
|
if (match(GoLexer::KEYWORD_CHAN))
|
|
{
|
|
auto *elem = Type();
|
|
if (!elem)
|
|
return syntaxerror();
|
|
return new GoASTChanType(GoASTNode::eChanRecv, elem);
|
|
}
|
|
return r.error();
|
|
}
|
|
return ChanType2();
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::ChanType2()
|
|
{
|
|
if (!match(GoLexer::KEYWORD_CHAN))
|
|
return nullptr;
|
|
auto dir = GoASTNode::eChanBidir;
|
|
if (match(GoLexer::OP_LT_MINUS))
|
|
dir = GoASTNode::eChanSend;
|
|
auto *elem = Type();
|
|
if (!elem)
|
|
return syntaxerror();
|
|
return new GoASTChanType(dir, elem);
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::Type()
|
|
{
|
|
if (GoASTExpr *t = Type2())
|
|
return t;
|
|
if (GoASTExpr *t = Name())
|
|
return t;
|
|
if (GoASTExpr *t = ChanType())
|
|
return t;
|
|
if (match(GoLexer::OP_STAR))
|
|
{
|
|
GoASTExpr *t = Type();
|
|
if (!t)
|
|
return syntaxerror();
|
|
return new GoASTStarExpr(t);
|
|
}
|
|
if (match(GoLexer::OP_LPAREN))
|
|
{
|
|
std::unique_ptr<GoASTExpr> t(Type());
|
|
if (!t || !match(GoLexer::OP_RPAREN))
|
|
return syntaxerror();
|
|
return t.release();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool
|
|
GoParser::Semicolon()
|
|
{
|
|
if (match(GoLexer::OP_SEMICOLON))
|
|
return true;
|
|
switch (peek())
|
|
{
|
|
case GoLexer::OP_RPAREN:
|
|
case GoLexer::OP_RBRACE:
|
|
case GoLexer::TOK_EOF:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::Name()
|
|
{
|
|
if (auto *id = Identifier())
|
|
{
|
|
if (GoASTExpr *qual = QualifiedIdent(id))
|
|
return qual;
|
|
return id;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
GoASTExpr *
|
|
GoParser::QualifiedIdent(lldb_private::GoASTIdent *p)
|
|
{
|
|
Rule r("QualifiedIdent", this);
|
|
llvm::SmallString<32> path(p->GetName().m_value);
|
|
GoLexer::Token *next;
|
|
bool have_slashes = false;
|
|
// LLDB extension: support full/package/path.name
|
|
while (match(GoLexer::OP_SLASH) && (next = match(GoLexer::TOK_IDENTIFIER)))
|
|
{
|
|
have_slashes = true;
|
|
path.append("/");
|
|
path.append(next->m_value);
|
|
}
|
|
if (match(GoLexer::OP_DOT))
|
|
{
|
|
auto *name = Identifier();
|
|
if (name)
|
|
{
|
|
if (have_slashes)
|
|
{
|
|
p->SetName(GoLexer::Token(GoLexer::TOK_IDENTIFIER, CopyString(path)));
|
|
}
|
|
return new GoASTSelectorExpr(p, name);
|
|
}
|
|
}
|
|
return r.error();
|
|
}
|
|
|
|
llvm::StringRef
|
|
GoParser::CopyString(llvm::StringRef s)
|
|
{
|
|
return m_strings.insert(std::make_pair(s, 'x')).first->getKey();
|
|
}
|
|
|
|
void
|
|
GoParser::GetError(Error &error)
|
|
{
|
|
llvm::StringRef want;
|
|
if (m_failed)
|
|
want = m_last_tok == GoLexer::TOK_INVALID ? DescribeToken(m_last_tok) : m_last;
|
|
else
|
|
want = m_error;
|
|
size_t len = m_lexer.BytesRemaining();
|
|
if (len > 10)
|
|
len = 10;
|
|
llvm::StringRef got;
|
|
if (len == 0)
|
|
got = "<eof>";
|
|
else
|
|
got = m_lexer.GetString(len);
|
|
error.SetErrorStringWithFormat("Syntax error: expected %s before '%s'.", want.str().c_str(), got.str().c_str());
|
|
}
|