diff options
Diffstat (limited to 'lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp')
-rw-r--r-- | lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp | 1717 |
1 files changed, 781 insertions, 936 deletions
diff --git a/lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp b/lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp index 0f136f7e61d..327b9df43db 100644 --- a/lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp @@ -11,1025 +11,870 @@ #include "GoParser.h" +#include "Plugins/ExpressionParser/Go/GoAST.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 { +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; +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; +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; - } +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; + default: + break; + } + GoASTExpr *expr = Expression(); + if (expr == nullptr) 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(); + 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; -} - -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(); + 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); } - // 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 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 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 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 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)); + 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(); } - if ((tok = match(GoLexer::KEYWORD_FALLTHROUGH))) - return FinishStmt(new GoASTBranchStmt(nullptr, tok->m_type)); - - return nullptr; + 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; } -GoASTIdent * -GoParser::Identifier() -{ - if (auto *tok = match(GoLexer::TOK_IDENTIFIER)) - return new GoASTIdent(*tok); +GoASTExpr *GoParser::PrimaryExpr() { + GoASTExpr *l; + GoASTExpr *r; + (l = Conversion()) || (l = Operand()); + if (!l) return nullptr; -} - -GoASTExpr * -GoParser::MoreExpressionList() -{ - if (match(GoLexer::OP_COMMA)) - { - auto *e = Expression(); - if (!e) - return syntaxerror(); - return e; - } + 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); } -GoASTIdent * -GoParser::MoreIdentifierList() -{ - if (match(GoLexer::OP_COMMA)) - { - auto *i = Identifier(); - if (!i) - return syntaxerror(); - return i; - } +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::Expression() -{ - Rule r("Expression", this); - if (GoASTExpr *ret = OrExpr()) - return ret; +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; } -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(); - } +GoASTCompositeLit *GoParser::LiteralValue() { + if (!match(GoLexer::OP_LBRACE)) 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(); - } + 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::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(); - } +GoASTExpr *GoParser::Element() { + GoASTExpr *key; + if (!((key = Expression()) || (key = LiteralValue()))) 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) + 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; - while ((r = Selector(l)) || (r = IndexOrSlice(l)) || (r = TypeAssertion(l)) || (r = Arguments(l))) - { - l = r; + return new GoASTTypeAssertExpr(e, t); } - return l; + return syntaxerror(); + } + return r.error(); } -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; +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); } - // MethodExpr should be handled by Selector - if (GoASTExpr *e = CompositeLit()) - return e; - if (GoASTExpr *n = Name()) - return n; - return FunctionLit(); -} + if (match(GoLexer::OP_DOTS)) + call->SetEllipsis(true); -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); -} + // Eat trailing comma + match(GoLexer::OP_COMMA); -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)) + 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(); - return block.release(); -} - -GoASTExpr * -GoParser::CompositeLit() -{ - Rule r("CompositeLit", this); - GoASTExpr *type; - (type = StructType()) || (type = ArrayOrSliceType(true)) || (type = MapType()) || (type = Name()); - if (!type) + match(GoLexer::OP_COMMA); + if (!mustMatch(GoLexer::OP_RPAREN)) return r.error(); - GoASTCompositeLit *lit = LiteralValue(); - if (!lit) - return r.error(); - lit->SetType(type); - return lit; + 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; + } } -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; +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 (!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(); + 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::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::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()); } -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(); -} +GoASTField *GoParser::FieldDecl() { + std::unique_ptr<GoASTField> f(new GoASTField); + GoASTExpr *t = FieldNamesAndType(f.get()); + if (!t) + t = AnonymousFieldType(); + if (!t) + return nullptr; -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(); + if (auto *tok = match(GoLexer::LIT_STRING)) + f->SetTag(new GoASTBasicLit(*tok)); + if (!Semicolon()) + return syntaxerror(); + return f.release(); } -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(); - } +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::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::AnonymousFieldType() { + bool pointer = match(GoLexer::OP_STAR); + GoASTExpr *t = Type(); + if (!t) + return nullptr; + if (pointer) + return new GoASTStarExpr(t); + return t; } -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::FunctionType() { + if (!match(GoLexer::KEYWORD_FUNC)) + return nullptr; + return Signature(); } -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); +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 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()); + } + return new GoASTFuncType(params, result); } -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); +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::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; +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 (!mustMatch(GoLexer::OP_RPAREN)) - return nullptr; - return l.release(); -} - -GoASTField * -GoParser::ParamDecl() -{ - std::unique_ptr<GoASTField> field(new GoASTField); - GoASTIdent *id = Identifier(); + if (!Semicolon()) + return syntaxerror(); + auto *f = new GoASTField; 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(); - } + f->AddNames(id.release()); + f->SetType(type); + methods->AddList(f); + } + if (!mustMatch(GoLexer::OP_RBRACE)) return nullptr; + return new GoASTInterfaceType(methods.release()); } -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(); - } +GoASTExpr *GoParser::MapType() { + if (!(match(GoLexer::KEYWORD_MAP) && mustMatch(GoLexer::OP_LBRACK))) 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; - } + 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::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); - } +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(); } -llvm::StringRef -GoParser::CopyString(llvm::StringRef s) -{ - return m_strings.insert(std::make_pair(s, 'x')).first->getKey(); +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); } -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()); +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()); } |