Skip to content

[SyntaxParse] Refactor parsing facilities #27046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Sep 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions include/swift/Parse/ASTGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@ class ASTGen {

static SourceLoc advanceLocBegin(const SourceLoc &Loc,
const syntax::Syntax &Node);
static SourceLoc advanceLocEnd(const SourceLoc &Loc,
const syntax::TokenSyntax &Token);
static SourceLoc advanceLocAfter(const SourceLoc &Loc,
const syntax::Syntax &Node);

static MagicIdentifierLiteralExpr::Kind getMagicIdentifierLiteralKind(tok Kind);

Expand Down
28 changes: 25 additions & 3 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,25 @@ class Parser {
/// plain Tok.is(T1) check).
bool skipUntilTokenOrEndOfLine(tok T1);

void ignoreToken();
void ignoreToken(tok Kind) {
assert(Tok.is(Kind));
ignoreToken();
}
bool ignoreIf(tok Kind) {
if (!Tok.is(Kind))
return false;
ignoreToken();
return true;
}
void ignoreSingle();
void ignoreUntil(tok Kind);

/// Ignore tokens until a token that starts with '>', and return true it if
/// found. Applies heuristics that are suitable when trying to find the end
/// of a list of generic parameters, generic arguments.
bool ignoreUntilGreaterInTypeList();

/// If the parser is generating only a syntax tree, try loading the current
/// node from a previously generated syntax tree.
/// Returns \c true if the node has been loaded and inserted into the current
Expand Down Expand Up @@ -1153,10 +1172,13 @@ class Parser {

using TypeASTResult = ParserResult<TypeRepr>;
using TypeResult = ParsedSyntaxResult<ParsedTypeSyntax>;
using TypeErrorResult = ParsedSyntaxResult<ParsedUnknownTypeSyntax>;

LayoutConstraint parseLayoutConstraint(Identifier LayoutConstraintID);

TypeResult parseTypeSyntax();
TypeResult parseTypeSyntax(Diag<> MessageID, bool HandleCodeCompletion = true,
bool IsSILFuncDecl = false);

TypeASTResult parseType();
TypeASTResult parseType(Diag<> MessageID, bool HandleCodeCompletion = true,
bool IsSILFuncDecl = false);
Expand All @@ -1183,8 +1205,8 @@ class Parser {
TypeResult parseOptionalType(ParsedTypeSyntax Base);
TypeResult parseImplicitlyUnwrappedOptionalType(ParsedTypeSyntax Base);

TypeErrorResult parseTypeArray(ParsedTypeSyntax Base, SourceLoc BaseLoc);
TypeErrorResult parseOldStyleProtocolComposition();
TypeResult parseTypeArray(ParsedTypeSyntax Base, SourceLoc BaseLoc);
TypeResult parseOldStyleProtocolComposition();

bool isOptionalToken(const Token &T) const;
ParsedTokenSyntax consumeOptionalTokenSyntax();
Expand Down
222 changes: 55 additions & 167 deletions include/swift/Parse/SyntaxParserResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,215 +30,103 @@ template <typename ParsedSyntaxNode> class ParsedSyntaxResult {
friend class ParsedSyntaxResult;

private:
// todo [gsoc]: use some kind of a proper sum type
llvm::Optional<ParsedSyntaxNode> SuccessNode;
llvm::Optional<llvm::SmallVector<ParsedSyntax, 0>> ErrorNodes;
llvm::Optional<llvm::SmallVector<ParsedSyntax, 0>> CodeCompletionNodes;

ResultDataKind DK;
ParsedRawSyntaxNode Raw;
ParserStatus Status;

public:
explicit ParsedSyntaxResult(ParsedSyntaxNode Node)
: SuccessNode(Node), DK(ResultDataKind::Success) {}

ParsedSyntaxResult(ArrayRef<ParsedSyntax> Nodes,
ResultDataKind Kind)
: DK(Kind) {
switch (DK) {
case ResultDataKind::Error:
ErrorNodes.emplace(Nodes.begin(), Nodes.end());
break;
case ResultDataKind::CodeCompletion:
CodeCompletionNodes.emplace(Nodes.begin(), Nodes.end());
break;
default:
llvm_unreachable("success cannot contain multiple nodes");
}
}
explicit ParsedSyntaxResult() : Raw(), Status() { setIsError(); }

ParsedSyntaxResult(const ParsedSyntaxResult &Other) {
DK = Other.DK;

switch (DK) {
case ResultDataKind::Success:
SuccessNode = Other.SuccessNode;
break;
case ResultDataKind::Error:
ErrorNodes = Other.ErrorNodes;
break;
case ResultDataKind::CodeCompletion:
CodeCompletionNodes = Other.CodeCompletionNodes;
break;
}
ParsedSyntaxResult(ParserStatus Status) : Raw(), Status(Status) {
assert(Status.isError());
}

explicit ParsedSyntaxResult(ParsedRawSyntaxNode Raw)
: Raw(Raw), Status() {}

explicit ParsedSyntaxResult(ParsedSyntaxNode Node)
: ParsedSyntaxResult(Node.getRaw()) {}

template <typename OtherParsedSyntaxNode,
typename Enable = typename std::enable_if<std::is_base_of<
ParsedSyntaxNode, OtherParsedSyntaxNode>::value>::type>
ParsedSyntaxResult(ParsedSyntaxResult<OtherParsedSyntaxNode> Other) {
DK = Other.DK;

switch (DK) {
case ResultDataKind::Success:
SuccessNode = *Other.SuccessNode;
break;
case ResultDataKind::Error:
ErrorNodes = *Other.ErrorNodes;
break;
case ResultDataKind::CodeCompletion:
CodeCompletionNodes = *Other.CodeCompletionNodes;
break;
}
ParsedSyntaxResult(ParsedSyntaxResult<OtherParsedSyntaxNode> other) {
Raw = other.Raw;
Status = other.Status;
}

bool isSuccess() const {
return DK == ResultDataKind::Success;
return Status.isSuccess();
}

bool isError() const {
return DK == ResultDataKind::Error;
return Status.isError();
}
void setIsError() {
Status.setIsParseError();
}

bool isCodeCompletion() const {
return DK == ResultDataKind::CodeCompletion;
bool hasCodeCompletion() const {
return Status.hasCodeCompletion();
}
void setHasCodeCompletion() {
Status.setHasCodeCompletion();
}

ParsedSyntaxNode getResult() const {
assert(isSuccess() && "unsuccessful parse doesn't have any result");
return *SuccessNode;
ParsedSyntaxNode get() const {
assert(!isNull());
return ParsedSyntaxNode(Raw);
}
Optional<ParsedSyntaxNode> getOrNull() const {
if (isNull())
return None;
return get();
}

ArrayRef<ParsedSyntax> getUnknownNodes() const {
assert(!isSuccess() && "successful parse doesn't contain unknown nodes");
switch (DK) {
case ResultDataKind::Error:
return *ErrorNodes;
case ResultDataKind::CodeCompletion:
return *CodeCompletionNodes;
default:
llvm_unreachable("cannot get here");
}
bool isNull() const {
return Raw.isNull();
}

ParserStatus getStatus() const {
ParserStatus S;
if (isError())
S.setIsParseError();
if (isCodeCompletion())
S.setHasCodeCompletion();
return S;
return Status;
}
};

template <typename ParsedSyntaxNode>
static ParsedSyntaxResult<ParsedSyntaxNode>
makeParsedSuccess(ParsedSyntaxNode Node) {
return ParsedSyntaxResult<ParsedSyntaxNode>(Node);
makeParsedResult(ParsedSyntaxNode node) {
return ParsedSyntaxResult<ParsedSyntaxNode>(node);
}

template <typename ParsedSyntaxNode>
static ParsedSyntaxResult<ParsedSyntaxNode>
makeParsedError(ArrayRef<ParsedSyntax> Nodes) {
return ParsedSyntaxResult<ParsedSyntaxNode>(Nodes, ResultDataKind::Error);
makeParsedError(ParsedSyntaxNode node) {
auto result = ParsedSyntaxResult<ParsedSyntaxNode>(node);
result.setIsError();
return result;
}

template <typename ParsedSyntaxNode>
static ParsedSyntaxResult<ParsedSyntaxNode> makeParsedErrorEmpty() {
return ParsedSyntaxResult<ParsedSyntaxNode>({}, ResultDataKind::Error);
static ParsedSyntaxResult<ParsedSyntaxNode> makeParsedError() {
return ParsedSyntaxResult<ParsedSyntaxNode>();
}

template <typename ParsedSyntaxNode>
static ParsedSyntaxResult<ParsedSyntaxNode>
makeParsedCodeCompletion(ArrayRef<ParsedSyntax> Nodes) {
return ParsedSyntaxResult<ParsedSyntaxNode>(Nodes,
ResultDataKind::CodeCompletion);
makeParsedCodeCompletion(ParsedSyntaxNode node) {
auto result = ParsedSyntaxResult<ParsedSyntaxNode>(node);
result.setHasCodeCompletion();
return result;
}

template <typename ParsedSyntaxNode>
static ParsedSyntaxResult<ParsedSyntaxNode>
makeParsedResult(ArrayRef<ParsedSyntax> Nodes,
ParserStatus Status) {
return Status.hasCodeCompletion()
? makeParsedCodeCompletion<ParsedSyntaxNode>(Nodes)
: makeParsedError<ParsedSyntaxNode>(Nodes);
}

template <typename Syntax, typename AST> class SyntaxParserResult {
llvm::Optional<Syntax> SyntaxNode;
ParserResult<AST> ASTResult;

template <typename T, typename U> friend class SyntaxParserResult;

public:
SyntaxParserResult(std::nullptr_t = nullptr)
: SyntaxNode(None), ASTResult(nullptr) {}
SyntaxParserResult(ParserStatus Status)
: SyntaxNode(None), ASTResult(Status) {}
SyntaxParserResult(llvm::Optional<Syntax> SyntaxNode, AST *ASTNode)
: SyntaxNode(SyntaxNode), ASTResult(ASTNode) {}
SyntaxParserResult(ParserStatus Status, llvm::Optional<Syntax> SyntaxNode,
AST *ASTNode)
: SyntaxNode(SyntaxNode), ASTResult(makeParserResult(Status, ASTNode)) {}

/// Convert from a different but compatible parser result.
template <typename U, typename Enabler = typename std::enable_if<
std::is_base_of<AST, U>::value>::type>
SyntaxParserResult(SyntaxParserResult<Syntax, U> Other)
: SyntaxNode(Other.SyntaxNode), ASTResult(Other.ASTResult) {}


bool isNull() const { return ASTResult.isNull(); }
bool isNonNull() const { return ASTResult.isNonNull(); }
bool isParseError() const { return ASTResult.isParseError(); }
bool hasCodeCompletion() const { return ASTResult.hasCodeCompletion(); }

void setIsParseError() { return ASTResult.setIsParserError(); }
void setHasCodeCompletion() { return ASTResult.setHasCodeCompletion(); }

const ParserResult<AST> &getASTResult() { return ASTResult; }

AST *getAST() const { return ASTResult.get(); }

bool hasSyntax() const {
return SyntaxNode.hasValue();
}

Syntax getSyntax() const {
assert(SyntaxNode.hasValue() && "getSyntax from None value");
return *SyntaxNode;
}

SyntaxParserResult<Syntax, AST> &
operator=(SyntaxParserResult<Syntax, AST> R){
std::swap(*this, R);
return *this;
};
};

/// Create a successful parser result.
template <typename Syntax, typename AST>
static inline SyntaxParserResult<Syntax, AST>
makeSyntaxResult(llvm::Optional<Syntax> SyntaxNode, AST *ASTNode) {
return SyntaxParserResult<Syntax, AST>(SyntaxNode, ASTNode);
}

/// Create a result with the specified status.
template <typename Syntax, typename AST>
static inline SyntaxParserResult<Syntax, AST>
makeSyntaxResult(ParserStatus Status, llvm::Optional<Syntax> SyntaxNode,
AST *ASTNode) {
return SyntaxParserResult<Syntax, AST>(Status, SyntaxNode, ASTNode);
}

/// Create a result (null or non-null) with error and code completion bits set.
template <typename Syntax, typename AST>
static inline SyntaxParserResult<Syntax, AST>
makeSyntaxCodeCompletionResult(AST *Result = nullptr) {
SyntaxParserResult<Syntax, AST> SR;
if (Result)
SR = SyntaxParserResult<Syntax, AST>(None, Result);
SR.setHasCodeCompletion();
return SR;
makeParsedResult(ParsedSyntaxNode node, ParserStatus Status) {
auto result = ParsedSyntaxResult<ParsedSyntaxNode>(node);
if (Status.hasCodeCompletion())
result.setHasCodeCompletion();
else if (Status.isError())
result.setIsError();
return result;
}

} // namespace swift
Expand Down
Loading