diff options
author | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
---|---|---|
committer | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
commit | b9c1b51e45b845debb76d8658edabca70ca56079 (patch) | |
tree | dfcb5a13ef2b014202340f47036da383eaee74aa /lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp | |
parent | d5aa73376966339caad04013510626ec2e42c760 (diff) | |
download | llvm-b9c1b51e45b845debb76d8658edabca70ca56079.zip llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.gz llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.bz2 |
*** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style. This kind of mass change has
*** two obvious implications:
Firstly, merging this particular commit into a downstream fork may be a huge
effort. Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit. The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):
find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;
The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.
Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit. There are alternatives available that will attempt
to look through this change and find the appropriate prior commit. YMMV.
llvm-svn: 280751
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 0f136f7..327b9df 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()); } |