//===----------- SyntaxParsingContext.h -==============----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #ifndef SWIFT_SYNTAX_PARSING_CONTEXT_H #define SWIFT_SYNTAX_PARSING_CONTEXT_H #include "swift/Basic/SourceLoc.h" #include "swift/Syntax/Syntax.h" #include "swift/Syntax/TokenSyntax.h" namespace swift { class SourceLoc; class SourceFile; class Token; namespace syntax { struct RawTokenSyntax; struct RawSyntax; enum class SyntaxKind; enum class SyntaxContextKind { Decl, Stmt, Expr, Type, Pattern, }; /// Indicates what action should be performed on the destruction of /// SyntaxParsingContext enum class AccumulationMode { // Coerece the result to one of ContextKind. // E.g. for ContextKind::Expr, passthroug if the result is CallExpr, whereas // for non Exprs. CoerceKind, // Construct a result Syntax with specified SyntaxKind. CreateSyntax, // Pass through all parts to the parent context. Transparent, // Discard all parts in the context. Discard, // Construct SourceFile syntax to the specified SF. Root, // Invalid. NotSet, }; /// RAII object which receive RawSyntax parts. On destruction, this constructs /// a specified syntax node from received parts and propagate it to the parent /// context. /// /// e.g. /// parseExprParen() { /// SyntaxParsingContext LocalCtxt(SyntaxKind::ParenExpr, SyntaxContext); /// consumeToken(tok::l_paren) // In consumeToken(), a RawTokenSyntax is /// // added to the context. /// parseExpr(); // On returning from parseExpr(), a Expr Syntax node is /// // created and added to the context. /// consumeToken(tok::r_paren) /// // Now the context holds { '(' Expr ')' }. /// // From these parts, it creates ParenExpr node and add it to the parent. /// } class SyntaxParsingContext { // Parent context. Only the root context has nullptr. SyntaxParsingContext *Parent; // Reference to the SyntaxParsingContext *&CtxtHolder; // Collected parts. std::vector> Parts; // Operation on destruction. AccumulationMode Mode = AccumulationMode::NotSet; // Additional info depending on \c Mode. union { // For AccumulationMode::CreateSyntax; desired syntax node kind. SyntaxKind SynKind; // For AccumulationMode::CoerceKind; desired syntax node category. SyntaxContextKind CtxtKind; // For AccumulationMode::Root; the parsing source file. SourceFile *SF; }; // If false, context does nothing. bool Enabled; public: /// Construct root context. SyntaxParsingContext(SyntaxParsingContext *&CtxtHolder, SourceFile &SF); /// Designated constructor for child context. SyntaxParsingContext(SyntaxParsingContext *&CtxtHolder) : Parent(CtxtHolder), CtxtHolder(CtxtHolder), Enabled(Parent->isEnabled()) { assert(CtxtHolder->isTopOfContextStack() && "SyntaxParsingContext cannot have multiple children"); CtxtHolder = this; } SyntaxParsingContext(SyntaxParsingContext *&CtxtHolder, SyntaxContextKind Kind) : SyntaxParsingContext(CtxtHolder) { setCoerceKind(Kind); } SyntaxParsingContext(SyntaxParsingContext *&CtxtHolder, SyntaxKind Kind) : SyntaxParsingContext(CtxtHolder) { setCreateSyntax(Kind); } ~SyntaxParsingContext(); void disable() { Enabled = false; } bool isEnabled() const { return Enabled; } bool isRoot() const { return !Parent; } bool isTopOfContextStack() const { return this == CtxtHolder; } SyntaxParsingContext *getRoot(); /// Add RawSyntax to the parts. void addRawSyntax(RC Raw); /// Add Token with Trivia to the parts. void addToken(Token &Tok, Trivia &LeadingTrivia, Trivia &TrailingTrivia); /// Add Syntax to the parts. void addSyntax(Syntax Node); RC popBack() { auto Raw = std::move(Parts.back()); Parts.pop_back(); return Raw; } template llvm::Optional popIf() { if (auto Node = make(Parts.back()).getAs()) { Parts.pop_back(); return Node; } return None; } TokenSyntax popToken() { assert(Parts.back()->Kind == SyntaxKind::Token); return make(popBack()); } /// Create a syntax node using the tail \c N elements of collected parts and /// replace those parts with the single result. void createNodeInPlace(SyntaxKind Kind, size_t N); /// Create a node using the tail of the collected parts. The number of parts /// is automatically determined from \c Kind. Node: limited number of \c Kind /// are supported. See the implementation. void createNodeInPlace(SyntaxKind Kind); /// On destruction, construct a specified kind of RawSyntax node consuming the /// collected parts, then append it to the parent context. void setCreateSyntax(SyntaxKind Kind) { Mode = AccumulationMode::CreateSyntax; SynKind = Kind; } /// On destruction, if the parts size is 1 and it's kind of \c Kind, just /// append it to the parent context. Otherwise, create Unknown{Kind} node from /// the collected parts. void setCoerceKind(SyntaxContextKind Kind) { Mode = AccumulationMode::CoerceKind; CtxtKind = Kind; } /// Move the collected parts to the tail of parent context. void setTransparent() { Mode = AccumulationMode::Transparent; } /// Discard collected parts on this context. void setDiscard() { Mode = AccumulationMode::Discard; } }; } // namespace syntax } // namespace swift #endif // SWIFT_SYNTAX_PARSING_CONTEXT_H