//===-- 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 #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 ""; case GoLexer::TOK_IDENTIFIER: return "identifier"; case GoLexer::LIT_FLOAT: return "float"; case GoLexer::LIT_IMAGINARY: return "imaginary"; case GoLexer::LIT_INTEGER: return "integer"; case GoLexer::LIT_RUNE: return "rune"; case GoLexer::LIT_STRING: return "string"; default: return GoLexer::LookupToken(t); } } } // namespace class GoParser::Rule { public: Rule(llvm::StringRef name, GoParser *p) : m_name(name), m_parser(p), m_pos(p->m_pos) {} std::nullptr_t error() { if (!m_parser->m_failed) { // Set m_error in case this is the top level. if (m_parser->m_last_tok == GoLexer::TOK_INVALID) m_parser->m_error = m_parser->m_last; else m_parser->m_error = DescribeToken(m_parser->m_last_tok); // And set m_last in case it isn't. m_parser->m_last = m_name; m_parser->m_last_tok = GoLexer::TOK_INVALID; m_parser->m_pos = m_pos; } return nullptr; } private: llvm::StringRef m_name; GoParser *m_parser; size_t m_pos; }; GoParser::GoParser(const char *src) : m_lexer(src), m_pos(0), m_failed(false) {} GoASTStmt *GoParser::Statement() { Rule r("Statement", this); GoLexer::TokenType t = peek(); GoASTStmt *ret = nullptr; switch (t) { case GoLexer::TOK_EOF: case GoLexer::OP_SEMICOLON: case GoLexer::OP_RPAREN: case GoLexer::OP_RBRACE: case GoLexer::TOK_INVALID: return EmptyStmt(); case GoLexer::OP_LBRACE: return Block(); /* TODO: case GoLexer::KEYWORD_GO: return GoStmt(); case GoLexer::KEYWORD_RETURN: return ReturnStmt(); case GoLexer::KEYWORD_BREAK: case GoLexer::KEYWORD_CONTINUE: case GoLexer::KEYWORD_GOTO: case GoLexer::KEYWORD_FALLTHROUGH: return BranchStmt(); case GoLexer::KEYWORD_IF: return IfStmt(); case GoLexer::KEYWORD_SWITCH: return SwitchStmt(); case GoLexer::KEYWORD_SELECT: return SelectStmt(); case GoLexer::KEYWORD_FOR: return ForStmt(); case GoLexer::KEYWORD_DEFER: return DeferStmt(); case GoLexer::KEYWORD_CONST: case GoLexer::KEYWORD_TYPE: case GoLexer::KEYWORD_VAR: return DeclStmt(); case GoLexer::TOK_IDENTIFIER: if ((ret = LabeledStmt()) || (ret = ShortVarDecl())) { return ret; } */ default: break; } GoASTExpr *expr = Expression(); if (expr == nullptr) return r.error(); if (/*(ret = SendStmt(expr)) ||*/ (ret = IncDecStmt(expr)) || (ret = Assignment(expr)) || (ret = ExpressionStmt(expr))) { return ret; } delete expr; return r.error(); } GoASTStmt *GoParser::ExpressionStmt(GoASTExpr *e) { if (Semicolon()) return new GoASTExprStmt(e); return nullptr; } GoASTStmt *GoParser::IncDecStmt(GoASTExpr *e) { Rule r("IncDecStmt", this); if (match(GoLexer::OP_PLUS_PLUS)) return Semicolon() ? new GoASTIncDecStmt(e, GoLexer::OP_PLUS_PLUS) : r.error(); if (match(GoLexer::OP_MINUS_MINUS)) return Semicolon() ? new GoASTIncDecStmt(e, GoLexer::OP_MINUS_MINUS) : r.error(); return nullptr; } GoASTStmt *GoParser::Assignment(lldb_private::GoASTExpr *e) { Rule r("Assignment", this); std::vector> lhs; for (GoASTExpr *l = MoreExpressionList(); l; l = MoreExpressionList()) lhs.push_back(std::unique_ptr(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 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(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 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 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 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 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 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 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 block(new GoASTBlockStmt); for (auto *s = Statement(); s; s = Statement()) block->AddList(s); if (!match(GoLexer::OP_RBRACE)) return syntaxerror(); return block.release(); } GoASTExpr *GoParser::CompositeLit() { Rule r("CompositeLit", this); GoASTExpr *type; (type = StructType()) || (type = ArrayOrSliceType(true)) || (type = MapType()) || (type = Name()); if (!type) return r.error(); GoASTCompositeLit *lit = LiteralValue(); if (!lit) return r.error(); lit->SetType(type); return lit; } GoASTCompositeLit *GoParser::LiteralValue() { if (!match(GoLexer::OP_LBRACE)) return nullptr; std::unique_ptr 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 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 call(new GoASTCallExpr(false)); GoASTExpr *arg; // ( ExpressionList | Type [ "," ExpressionList ] ) for ((arg = Expression()) || (arg = Type()); arg; arg = MoreExpressionList()) { call->AddArgs(arg); } if (match(GoLexer::OP_DOTS)) call->SetEllipsis(true); // Eat trailing comma match(GoLexer::OP_COMMA); if (!mustMatch(GoLexer::OP_RPAREN)) return nullptr; call->SetFun(e); return call.release(); } return nullptr; } GoASTExpr *GoParser::Conversion() { Rule r("Conversion", this); if (GoASTExpr *t = Type2()) { if (match(GoLexer::OP_LPAREN)) { GoASTExpr *v = Expression(); if (!v) return syntaxerror(); match(GoLexer::OP_COMMA); if (!mustMatch(GoLexer::OP_RPAREN)) return r.error(); GoASTCallExpr *call = new GoASTCallExpr(false); call->SetFun(t); call->AddArgs(v); return call; } } return r.error(); } GoASTExpr *GoParser::Type2() { switch (peek()) { case GoLexer::OP_LBRACK: return ArrayOrSliceType(false); case GoLexer::KEYWORD_STRUCT: return StructType(); case GoLexer::KEYWORD_FUNC: return FunctionType(); case GoLexer::KEYWORD_INTERFACE: return InterfaceType(); case GoLexer::KEYWORD_MAP: return MapType(); case GoLexer::KEYWORD_CHAN: return ChanType2(); default: return nullptr; } } GoASTExpr *GoParser::ArrayOrSliceType(bool allowEllipsis) { Rule r("ArrayType", this); if (match(GoLexer::OP_LBRACK)) { std::unique_ptr 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 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 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 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 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 methods(new GoASTFieldList); while (true) { Rule r("MethodSpec", this); // ( identifier Signature | TypeName ) ; std::unique_ptr 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 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 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 = ""; else got = m_lexer.GetString(len); error.SetErrorStringWithFormat("Syntax error: expected %s before '%s'.", want.str().c_str(), got.str().c_str()); }