diff options
Diffstat (limited to 'source/Plugins/ExpressionParser/Go/GoParser.cpp')
-rw-r--r-- | source/Plugins/ExpressionParser/Go/GoParser.cpp | 1035 |
1 files changed, 1035 insertions, 0 deletions
diff --git a/source/Plugins/ExpressionParser/Go/GoParser.cpp b/source/Plugins/ExpressionParser/Go/GoParser.cpp new file mode 100644 index 0000000000000..0f136f7e61dc8 --- /dev/null +++ b/source/Plugins/ExpressionParser/Go/GoParser.cpp @@ -0,0 +1,1035 @@ +//===-- GoParser.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <vector> + +#include "GoParser.h" + +#include "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 + +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<std::unique_ptr<GoASTExpr>> lhs; + for (GoASTExpr *l = MoreExpressionList(); l; l = MoreExpressionList()) + lhs.push_back(std::unique_ptr<GoASTExpr>(l)); + switch (peek()) + { + case GoLexer::OP_EQ: + case GoLexer::OP_PLUS_EQ: + case GoLexer::OP_MINUS_EQ: + case GoLexer::OP_PIPE_EQ: + case GoLexer::OP_CARET_EQ: + case GoLexer::OP_STAR_EQ: + case GoLexer::OP_SLASH_EQ: + case GoLexer::OP_PERCENT_EQ: + case GoLexer::OP_LSHIFT_EQ: + case GoLexer::OP_RSHIFT_EQ: + case GoLexer::OP_AMP_EQ: + case GoLexer::OP_AMP_CARET_EQ: + break; + default: + return r.error(); + } + // We don't want to own e until we know this is an assignment. + std::unique_ptr<GoASTAssignStmt> stmt(new GoASTAssignStmt(false)); + stmt->AddLhs(e); + for (auto &l : lhs) + stmt->AddLhs(l.release()); + for (GoASTExpr *r = Expression(); r; r = MoreExpressionList()) + stmt->AddRhs(r); + if (!Semicolon() || stmt->NumRhs() == 0) + return new GoASTBadStmt; + return stmt.release(); +} + +GoASTStmt * +GoParser::EmptyStmt() +{ + if (match(GoLexer::TOK_EOF)) + return nullptr; + if (Semicolon()) + return new GoASTEmptyStmt; + return nullptr; +} + +GoASTStmt * +GoParser::GoStmt() +{ + if (match(GoLexer::KEYWORD_GO)) + { + if (GoASTCallExpr *e = llvm::dyn_cast_or_null<GoASTCallExpr>(Expression())) + { + return FinishStmt(new GoASTGoStmt(e)); + } + m_last = "call expression"; + m_failed = true; + return new GoASTBadStmt(); + } + return nullptr; +} + +GoASTStmt * +GoParser::ReturnStmt() +{ + if (match(GoLexer::KEYWORD_RETURN)) + { + std::unique_ptr<GoASTReturnStmt> r(new GoASTReturnStmt()); + for (GoASTExpr *e = Expression(); e; e = MoreExpressionList()) + r->AddResults(e); + return FinishStmt(r.release()); + } + return nullptr; +} + +GoASTStmt * +GoParser::BranchStmt() +{ + GoLexer::Token *tok; + if ((tok = match(GoLexer::KEYWORD_BREAK)) || (tok = match(GoLexer::KEYWORD_CONTINUE)) || + (tok = match(GoLexer::KEYWORD_GOTO))) + { + auto *e = Identifier(); + if (tok->m_type == GoLexer::KEYWORD_GOTO && !e) + return syntaxerror(); + return FinishStmt(new GoASTBranchStmt(e, tok->m_type)); + } + if ((tok = match(GoLexer::KEYWORD_FALLTHROUGH))) + return FinishStmt(new GoASTBranchStmt(nullptr, tok->m_type)); + + return nullptr; +} + +GoASTIdent * +GoParser::Identifier() +{ + if (auto *tok = match(GoLexer::TOK_IDENTIFIER)) + return new GoASTIdent(*tok); + return nullptr; +} + +GoASTExpr * +GoParser::MoreExpressionList() +{ + if (match(GoLexer::OP_COMMA)) + { + auto *e = Expression(); + if (!e) + return syntaxerror(); + return e; + } + return nullptr; +} + +GoASTIdent * +GoParser::MoreIdentifierList() +{ + if (match(GoLexer::OP_COMMA)) + { + auto *i = Identifier(); + if (!i) + return syntaxerror(); + return i; + } + return nullptr; +} + +GoASTExpr * +GoParser::Expression() +{ + Rule r("Expression", this); + if (GoASTExpr *ret = OrExpr()) + return ret; + return r.error(); +} + +GoASTExpr * +GoParser::UnaryExpr() +{ + switch (peek()) + { + case GoLexer::OP_PLUS: + case GoLexer::OP_MINUS: + case GoLexer::OP_BANG: + case GoLexer::OP_CARET: + case GoLexer::OP_STAR: + case GoLexer::OP_AMP: + case GoLexer::OP_LT_MINUS: + { + const GoLexer::Token t = next(); + if (GoASTExpr *e = UnaryExpr()) + { + if (t.m_type == GoLexer::OP_STAR) + return new GoASTStarExpr(e); + else + return new GoASTUnaryExpr(t.m_type, e); + } + return syntaxerror(); + } + default: + return PrimaryExpr(); + } +} + +GoASTExpr * +GoParser::OrExpr() +{ + std::unique_ptr<GoASTExpr> l(AndExpr()); + if (l) + { + while (match(GoLexer::OP_PIPE_PIPE)) + { + GoASTExpr *r = AndExpr(); + if (r) + l.reset(new GoASTBinaryExpr(l.release(), r, GoLexer::OP_PIPE_PIPE)); + else + return syntaxerror(); + } + return l.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::AndExpr() +{ + std::unique_ptr<GoASTExpr> l(RelExpr()); + if (l) + { + while (match(GoLexer::OP_AMP_AMP)) + { + GoASTExpr *r = RelExpr(); + if (r) + l.reset(new GoASTBinaryExpr(l.release(), r, GoLexer::OP_AMP_AMP)); + else + return syntaxerror(); + } + return l.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::RelExpr() +{ + std::unique_ptr<GoASTExpr> l(AddExpr()); + if (l) + { + for (GoLexer::Token *t; (t = match(GoLexer::OP_EQ_EQ)) || (t = match(GoLexer::OP_BANG_EQ)) || + (t = match(GoLexer::OP_LT)) || (t = match(GoLexer::OP_LT_EQ)) || + (t = match(GoLexer::OP_GT)) || (t = match(GoLexer::OP_GT_EQ));) + { + GoLexer::TokenType op = t->m_type; + GoASTExpr *r = AddExpr(); + if (r) + l.reset(new GoASTBinaryExpr(l.release(), r, op)); + else + return syntaxerror(); + } + return l.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::AddExpr() +{ + std::unique_ptr<GoASTExpr> l(MulExpr()); + if (l) + { + for (GoLexer::Token *t; (t = match(GoLexer::OP_PLUS)) || (t = match(GoLexer::OP_MINUS)) || + (t = match(GoLexer::OP_PIPE)) || (t = match(GoLexer::OP_CARET));) + { + GoLexer::TokenType op = t->m_type; + GoASTExpr *r = MulExpr(); + if (r) + l.reset(new GoASTBinaryExpr(l.release(), r, op)); + else + return syntaxerror(); + } + return l.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::MulExpr() +{ + std::unique_ptr<GoASTExpr> l(UnaryExpr()); + if (l) + { + for (GoLexer::Token *t; (t = match(GoLexer::OP_STAR)) || (t = match(GoLexer::OP_SLASH)) || + (t = match(GoLexer::OP_PERCENT)) || (t = match(GoLexer::OP_LSHIFT)) || + (t = match(GoLexer::OP_RSHIFT)) || (t = match(GoLexer::OP_AMP)) || + (t = match(GoLexer::OP_AMP_CARET));) + { + GoLexer::TokenType op = t->m_type; + GoASTExpr *r = UnaryExpr(); + if (r) + l.reset(new GoASTBinaryExpr(l.release(), r, op)); + else + return syntaxerror(); + } + return l.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::PrimaryExpr() +{ + GoASTExpr *l; + GoASTExpr *r; + (l = Conversion()) || (l = Operand()); + if (!l) + return nullptr; + while ((r = Selector(l)) || (r = IndexOrSlice(l)) || (r = TypeAssertion(l)) || (r = Arguments(l))) + { + l = r; + } + return l; +} + +GoASTExpr * +GoParser::Operand() +{ + GoLexer::Token *lit; + if ((lit = match(GoLexer::LIT_INTEGER)) || (lit = match(GoLexer::LIT_FLOAT)) || + (lit = match(GoLexer::LIT_IMAGINARY)) || (lit = match(GoLexer::LIT_RUNE)) || (lit = match(GoLexer::LIT_STRING))) + return new GoASTBasicLit(*lit); + if (match(GoLexer::OP_LPAREN)) + { + GoASTExpr *e; + if (!((e = Expression()) && match(GoLexer::OP_RPAREN))) + return syntaxerror(); + return e; + } + // MethodExpr should be handled by Selector + if (GoASTExpr *e = CompositeLit()) + return e; + if (GoASTExpr *n = Name()) + return n; + return FunctionLit(); +} + +GoASTExpr * +GoParser::FunctionLit() +{ + if (!match(GoLexer::KEYWORD_FUNC)) + return nullptr; + auto *sig = Signature(); + if (!sig) + return syntaxerror(); + auto *body = Block(); + if (!body) + { + delete sig; + return syntaxerror(); + } + return new GoASTFuncLit(sig, body); +} + +GoASTBlockStmt * +GoParser::Block() +{ + if (!match(GoLexer::OP_LBRACE)) + return nullptr; + std::unique_ptr<GoASTBlockStmt> block(new GoASTBlockStmt); + for (auto *s = Statement(); s; s = Statement()) + block->AddList(s); + if (!match(GoLexer::OP_RBRACE)) + return syntaxerror(); + return block.release(); +} + +GoASTExpr * +GoParser::CompositeLit() +{ + Rule r("CompositeLit", this); + GoASTExpr *type; + (type = StructType()) || (type = ArrayOrSliceType(true)) || (type = MapType()) || (type = Name()); + if (!type) + return r.error(); + GoASTCompositeLit *lit = LiteralValue(); + if (!lit) + return r.error(); + lit->SetType(type); + return lit; +} + +GoASTCompositeLit * +GoParser::LiteralValue() +{ + if (!match(GoLexer::OP_LBRACE)) + return nullptr; + std::unique_ptr<GoASTCompositeLit> lit(new GoASTCompositeLit); + for (GoASTExpr *e = Element(); e; e = Element()) + { + lit->AddElts(e); + if (!match(GoLexer::OP_COMMA)) + break; + } + if (!mustMatch(GoLexer::OP_RBRACE)) + return nullptr; + return lit.release(); +} + +GoASTExpr * +GoParser::Element() +{ + GoASTExpr *key; + if (!((key = Expression()) || (key = LiteralValue()))) + return nullptr; + if (!match(GoLexer::OP_COLON)) + return key; + GoASTExpr *value; + if ((value = Expression()) || (value = LiteralValue())) + return new GoASTKeyValueExpr(key, value); + delete key; + return syntaxerror(); +} + +GoASTExpr * +GoParser::Selector(GoASTExpr *e) +{ + Rule r("Selector", this); + if (match(GoLexer::OP_DOT)) + { + if (auto *name = Identifier()) + return new GoASTSelectorExpr(e, name); + } + return r.error(); +} + +GoASTExpr * +GoParser::IndexOrSlice(GoASTExpr *e) +{ + Rule r("IndexOrSlice", this); + if (match(GoLexer::OP_LBRACK)) + { + std::unique_ptr<GoASTExpr> i1(Expression()), i2, i3; + bool slice = false; + if (match(GoLexer::OP_COLON)) + { + slice = true; + i2.reset(Expression()); + if (i2 && match(GoLexer::OP_COLON)) + { + i3.reset(Expression()); + if (!i3) + return syntaxerror(); + } + } + if (!(slice || i1)) + return syntaxerror(); + if (!mustMatch(GoLexer::OP_RBRACK)) + return nullptr; + if (slice) + { + bool slice3 = i3.get(); + return new GoASTSliceExpr(e, i1.release(), i2.release(), i3.release(), slice3); + } + return new GoASTIndexExpr(e, i1.release()); + } + return r.error(); +} + +GoASTExpr * +GoParser::TypeAssertion(GoASTExpr *e) +{ + Rule r("TypeAssertion", this); + if (match(GoLexer::OP_DOT) && match(GoLexer::OP_LPAREN)) + { + if (auto *t = Type()) + { + if (!mustMatch(GoLexer::OP_RPAREN)) + return nullptr; + return new GoASTTypeAssertExpr(e, t); + } + return syntaxerror(); + } + return r.error(); +} + +GoASTExpr * +GoParser::Arguments(GoASTExpr *e) +{ + if (match(GoLexer::OP_LPAREN)) + { + std::unique_ptr<GoASTCallExpr> call(new GoASTCallExpr(false)); + GoASTExpr *arg; + // ( ExpressionList | Type [ "," ExpressionList ] ) + for ((arg = Expression()) || (arg = Type()); arg; arg = MoreExpressionList()) + { + call->AddArgs(arg); + } + if (match(GoLexer::OP_DOTS)) + call->SetEllipsis(true); + + // Eat trailing comma + match(GoLexer::OP_COMMA); + + if (!mustMatch(GoLexer::OP_RPAREN)) + return nullptr; + call->SetFun(e); + return call.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::Conversion() +{ + Rule r("Conversion", this); + if (GoASTExpr *t = Type2()) + { + 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<GoASTExpr> len; + if (allowEllipsis && match(GoLexer::OP_DOTS)) + { + len.reset(new GoASTEllipsis(nullptr)); + } + else + { + len.reset(Expression()); + } + + if (!match(GoLexer::OP_RBRACK)) + return r.error(); + GoASTExpr *elem = Type(); + if (!elem) + return syntaxerror(); + return new GoASTArrayType(len.release(), elem); + } + return r.error(); +} + +GoASTExpr * +GoParser::StructType() +{ + if (!(match(GoLexer::KEYWORD_STRUCT) && mustMatch(GoLexer::OP_LBRACE))) + return nullptr; + std::unique_ptr<GoASTFieldList> fields(new GoASTFieldList); + while (auto *field = FieldDecl()) + fields->AddList(field); + if (!mustMatch(GoLexer::OP_RBRACE)) + return nullptr; + return new GoASTStructType(fields.release()); +} + +GoASTField * +GoParser::FieldDecl() +{ + std::unique_ptr<GoASTField> f(new GoASTField); + GoASTExpr *t = FieldNamesAndType(f.get()); + if (!t) + t = AnonymousFieldType(); + if (!t) + return nullptr; + + if (auto *tok = match(GoLexer::LIT_STRING)) + f->SetTag(new GoASTBasicLit(*tok)); + if (!Semicolon()) + return syntaxerror(); + return f.release(); +} + +GoASTExpr * +GoParser::FieldNamesAndType(GoASTField *field) +{ + Rule r("FieldNames", this); + for (auto *id = Identifier(); id; id = MoreIdentifierList()) + field->AddNames(id); + if (m_failed) + return nullptr; + GoASTExpr *t = Type(); + if (t) + return t; + return r.error(); +} + +GoASTExpr * +GoParser::AnonymousFieldType() +{ + bool pointer = match(GoLexer::OP_STAR); + GoASTExpr *t = Type(); + if (!t) + return nullptr; + if (pointer) + return new GoASTStarExpr(t); + return t; +} + +GoASTExpr * +GoParser::FunctionType() +{ + if (!match(GoLexer::KEYWORD_FUNC)) + return nullptr; + return Signature(); +} + +GoASTFuncType * +GoParser::Signature() +{ + auto *params = Params(); + if (!params) + return syntaxerror(); + auto *result = Params(); + if (!result) + { + if (auto *t = Type()) + { + result = new GoASTFieldList; + auto *f = new GoASTField; + f->SetType(t); + result->AddList(f); + } + } + return new GoASTFuncType(params, result); +} + +GoASTFieldList * +GoParser::Params() +{ + if (!match(GoLexer::OP_LPAREN)) + return nullptr; + std::unique_ptr<GoASTFieldList> l(new GoASTFieldList); + while (GoASTField *p = ParamDecl()) + { + l->AddList(p); + if (!match(GoLexer::OP_COMMA)) + break; + } + if (!mustMatch(GoLexer::OP_RPAREN)) + return nullptr; + return l.release(); +} + +GoASTField * +GoParser::ParamDecl() +{ + std::unique_ptr<GoASTField> field(new GoASTField); + GoASTIdent *id = Identifier(); + if (id) + { + // Try `IdentifierList [ "..." ] Type`. + // If that fails, backtrack and try `[ "..." ] Type`. + Rule r("NamedParam", this); + for (; id; id = MoreIdentifierList()) + field->AddNames(id); + GoASTExpr *t = ParamType(); + if (t) + { + field->SetType(t); + return field.release(); + } + field.reset(new GoASTField); + r.error(); + } + GoASTExpr *t = ParamType(); + if (t) + { + field->SetType(t); + return field.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::ParamType() +{ + bool dots = match(GoLexer::OP_DOTS); + GoASTExpr *t = Type(); + if (!dots) + return t; + if (!t) + return syntaxerror(); + return new GoASTEllipsis(t); +} + +GoASTExpr * +GoParser::InterfaceType() +{ + if (!match(GoLexer::KEYWORD_INTERFACE) || !mustMatch(GoLexer::OP_LBRACE)) + return nullptr; + std::unique_ptr<GoASTFieldList> methods(new GoASTFieldList); + while (true) + { + Rule r("MethodSpec", this); + // ( identifier Signature | TypeName ) ; + std::unique_ptr<GoASTIdent> id(Identifier()); + if (!id) + break; + GoASTExpr *type = Signature(); + if (!type) + { + r.error(); + id.reset(); + type = Name(); + } + if (!Semicolon()) + return syntaxerror(); + auto *f = new GoASTField; + if (id) + f->AddNames(id.release()); + f->SetType(type); + methods->AddList(f); + } + if (!mustMatch(GoLexer::OP_RBRACE)) + return nullptr; + return new GoASTInterfaceType(methods.release()); +} + +GoASTExpr * +GoParser::MapType() +{ + if (!(match(GoLexer::KEYWORD_MAP) && mustMatch(GoLexer::OP_LBRACK))) + return nullptr; + std::unique_ptr<GoASTExpr> key(Type()); + if (!key) + return syntaxerror(); + if (!mustMatch(GoLexer::OP_RBRACK)) + return nullptr; + auto *elem = Type(); + if (!elem) + return syntaxerror(); + return new GoASTMapType(key.release(), elem); +} + +GoASTExpr * +GoParser::ChanType() +{ + Rule r("chan", this); + if (match(GoLexer::OP_LT_MINUS)) + { + if (match(GoLexer::KEYWORD_CHAN)) + { + auto *elem = Type(); + if (!elem) + return syntaxerror(); + return new GoASTChanType(GoASTNode::eChanRecv, elem); + } + return r.error(); + } + return ChanType2(); +} + +GoASTExpr * +GoParser::ChanType2() +{ + if (!match(GoLexer::KEYWORD_CHAN)) + return nullptr; + auto dir = GoASTNode::eChanBidir; + if (match(GoLexer::OP_LT_MINUS)) + dir = GoASTNode::eChanSend; + auto *elem = Type(); + if (!elem) + return syntaxerror(); + return new GoASTChanType(dir, elem); +} + +GoASTExpr * +GoParser::Type() +{ + if (GoASTExpr *t = Type2()) + return t; + if (GoASTExpr *t = Name()) + return t; + if (GoASTExpr *t = ChanType()) + return t; + if (match(GoLexer::OP_STAR)) + { + GoASTExpr *t = Type(); + if (!t) + return syntaxerror(); + return new GoASTStarExpr(t); + } + if (match(GoLexer::OP_LPAREN)) + { + std::unique_ptr<GoASTExpr> t(Type()); + if (!t || !match(GoLexer::OP_RPAREN)) + return syntaxerror(); + return t.release(); + } + return nullptr; +} + +bool +GoParser::Semicolon() +{ + if (match(GoLexer::OP_SEMICOLON)) + return true; + switch (peek()) + { + case GoLexer::OP_RPAREN: + case GoLexer::OP_RBRACE: + case GoLexer::TOK_EOF: + return true; + default: + return false; + } +} + +GoASTExpr * +GoParser::Name() +{ + if (auto *id = Identifier()) + { + if (GoASTExpr *qual = QualifiedIdent(id)) + return qual; + return id; + } + return nullptr; +} + +GoASTExpr * +GoParser::QualifiedIdent(lldb_private::GoASTIdent *p) +{ + Rule r("QualifiedIdent", this); + llvm::SmallString<32> path(p->GetName().m_value); + GoLexer::Token *next; + bool have_slashes = false; + // LLDB extension: support full/package/path.name + while (match(GoLexer::OP_SLASH) && (next = match(GoLexer::TOK_IDENTIFIER))) + { + have_slashes = true; + path.append("/"); + path.append(next->m_value); + } + if (match(GoLexer::OP_DOT)) + { + auto *name = Identifier(); + if (name) + { + if (have_slashes) + { + p->SetName(GoLexer::Token(GoLexer::TOK_IDENTIFIER, CopyString(path))); + } + return new GoASTSelectorExpr(p, name); + } + } + return r.error(); +} + +llvm::StringRef +GoParser::CopyString(llvm::StringRef s) +{ + return m_strings.insert(std::make_pair(s, 'x')).first->getKey(); +} + +void +GoParser::GetError(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()); +} |