| //===-- 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()); |
| } |