Raphael Isemann b90f81ed82 Fix memory leaks in GoParser
Summary: The GoParser is leaking memory in the tests due to not freeing allocated nodes when encountering some parsing errors. With this patch all GoParser tests are passing with enabled memory sanitizers/ubsan.

Reviewers: labath, davide

Reviewed By: labath

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D42409

llvm-svn: 323197
2018-01-23 13:50:46 +00:00

887 lines
22 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 "Plugins/ExpressionParser/Go/GoAST.h"
#include "lldb/Utility/Status.h"
#include "llvm/ADT/SmallString.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_last_tok(GoLexer::TOK_INVALID),
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) {
delete type;
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()) {
std::unique_ptr<GoASTExpr> owner(t);
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);
owner.release();
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(Status &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());
}