//===--- ExprSyntax.h - Swift Expression Syntax Interface -------*- 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 // //===----------------------------------------------------------------------===// // // This file defines the interface for expression-specific syntax nodes, // such as // //===----------------------------------------------------------------------===// #ifndef SWIFT_SYNTAX_EXPRSYNTAX_H #define SWIFT_SYNTAX_EXPRSYNTAX_H #include "swift/Syntax/RawSyntax.h" #include "swift/Syntax/References.h" #include "swift/Syntax/Syntax.h" #include "swift/Syntax/SyntaxData.h" #include "swift/Syntax/SyntaxCollection.h" #include "swift/Syntax/SyntaxCollectionData.h" #include "swift/Syntax/TokenSyntax.h" #include "swift/Syntax/UnknownSyntax.h" using llvm::Optional; namespace swift { namespace syntax { class GenericArgumentClauseSyntax; class GenericArgumentClauseSyntaxData; class ExprSyntaxData : public SyntaxData { protected: ExprSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0) : SyntaxData(Raw, Parent, IndexInParent) { assert(Raw->isExpr()); } public: static RC make(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); static RC makeBlank(); static bool classof(const SyntaxData *S) { return S->isExpr(); } }; class ExprSyntax : public Syntax { friend class FunctionParameterSyntax; public: using DataType = ExprSyntaxData; ExprSyntax(const RC Root, const ExprSyntaxData *Data); static bool classof(const Syntax *S) { return S->isExpr(); } }; #pragma mark - unknown-expression Data class UnknownExprSyntaxData : public UnknownSyntaxData { UnknownExprSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); public: static RC make(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); static bool classof(const SyntaxData *S) { return S->getKind() == SyntaxKind::UnknownExpr; } }; #pragma mark - unknown-expression API class UnknownExprSyntax : public UnknownSyntax { friend class SyntaxData; friend class UnknownExprSyntaxData; friend class LegacyASTTransformer; using DataType = UnknownExprSyntaxData; public: UnknownExprSyntax(const RC Root, const UnknownExprSyntaxData *Data); static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::UnknownExpr; } }; #pragma mark - integer-literal-expression Data class IntegerLiteralExprSyntaxData : public ExprSyntaxData { friend struct SyntaxFactory; friend class SyntaxData; IntegerLiteralExprSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); static RC make(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); static RC makeBlank(); public: static bool classof(const SyntaxData *S) { return S->getKind() == SyntaxKind::IntegerLiteralExpr; } }; #pragma mark - integer-literal-expression API class IntegerLiteralExprSyntax : public ExprSyntax { using DataType = IntegerLiteralExprSyntaxData; friend struct SyntaxFactory; friend class SyntaxData; friend class IntegerLiteralExprSyntaxData; IntegerLiteralExprSyntax(const RC Root, const IntegerLiteralExprSyntaxData *Data); enum class Cursor : CursorIndex { Sign, Digits }; public: /// Get the '+' or '-' associated with this integer literal expression. RC getSign() const; /// Return a new IntegerLiteralExprSyntax with the given '+' or '-' sign. IntegerLiteralExprSyntax withSign(RC NewSign) const; /// Return the string of digits comprising the number part of the integer /// literal expression. RC getDigits() const; /// Return a new IntegerLiteralExprSyntax with the given string of digits. IntegerLiteralExprSyntax withDigits(RC NewDigits) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::IntegerLiteralExpr; } }; #pragma mark - symbolic-reference Data class SymbolicReferenceExprSyntaxData : public ExprSyntaxData { friend class SymbolicReferenceExprSyntax; friend class SyntaxData; friend struct SyntaxFactory; RC CachedGenericArgClause; SymbolicReferenceExprSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); static RC make(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); static RC makeBlank(); public: static bool classof(const SyntaxData *S) { return S->getKind() == SyntaxKind::SymbolicReferenceExpr; } }; #pragma mark - symbolic-reference API /// symbolic-reference-expression -> identifier generic-argument-clause? /// /// This is shown as primary-expression -> identifier generic-argument-clause? /// in the grammar. It can be just an identifier referring to some /// declaration, or it could perhaps be a constructor call to `Array`. class SymbolicReferenceExprSyntax : public ExprSyntax { using DataType = SymbolicReferenceExprSyntaxData; friend struct SyntaxFactory; friend class SyntaxData; friend class Syntax; friend class SymbolicReferenceExprSyntaxData; enum class Cursor : CursorIndex { Identifier, GenericArgumentClause }; SymbolicReferenceExprSyntax(const RC Root, const DataType *Data); public: /// Get the identifier for the symbol to which this expression refers. RC getIdentifier() const; /// Return a new `SymbolicReferenceExprSyntax` with the given identifier. SymbolicReferenceExprSyntax withIdentifier(RC NewIdentifier) const; /// Return the generic arguments this symbolic reference has, if it has one. llvm::Optional getGenericArgumentClause() const; /// Return a new `SymbolicReferenceExprSyntax` with the given generic /// arguments. SymbolicReferenceExprSyntax withGenericArgumentClause(GenericArgumentClauseSyntax NewGenericArgs) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::SymbolicReferenceExpr; } }; #pragma mark - function-call-argument Data class FunctionCallArgumentSyntaxData : public SyntaxData { friend struct SyntaxFactory; friend class FunctionCallArgumentSyntax; friend class SyntaxData; RC CachedExpression; FunctionCallArgumentSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); static RC make(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); static RC makeBlank(); public: static bool classof(const SyntaxData *S) { return S->getKind() == SyntaxKind::FunctionCallArgument; } }; #pragma mark - function-call-argument API /// function-call-argument -> label? ':'? (expression | operator) ','? class FunctionCallArgumentSyntax : public Syntax { using DataType = FunctionCallArgumentSyntaxData; friend struct SyntaxFactory; friend class SyntaxData; friend class Syntax; friend class FunctionCallArgumentSyntaxData; friend class FunctionCallArgumentListSyntax; friend class SyntaxCollectionData; friend class SyntaxCollection; enum class Cursor { Label, Colon, Expression, Comma, }; FunctionCallArgumentSyntax(const RC Root, const DataType *Data); public: /// Return the label identifier for this argument, if it has one. RC getLabel() const; /// Return a new `FunctionCallArgumentSyntax` with the given label. FunctionCallArgumentSyntax withLabel(RC NewLabel) const; /// Get the colon ':' token in between the label and argument, /// if there is one. RC getColonToken() const; /// Return a new `FunctionCallArgumentSyntax` with the given colon ':' token. FunctionCallArgumentSyntax withColonToken(RC NewColon) const; /// Returns the expression of the argument. llvm::Optional getExpression() const; /// Return a new `FunctionCallArgumentSyntax` with the given expression /// argument. FunctionCallArgumentSyntax withExpression(ExprSyntax NewExpression) const; /// Get the comma ',' token immediately following this argument, if there /// is one. RC getTrailingComma() const; /// Return a new `FunctionCallArgumentSyntax` with the given comma attached /// to the end of the argument. FunctionCallArgumentSyntax withTrailingComma(RC NewTrailingComma) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::FunctionCallArgument; } }; #pragma mark - function-call-argument-list Data using FunctionCallArgumentListSyntaxData = SyntaxCollectionData; #pragma mark - function-call-argument-list API /// function-call-argument-list -> function-call-argument /// function-call-argument-list? class FunctionCallArgumentListSyntax : public SyntaxCollection { friend struct SyntaxFactory; friend class FunctionCallExprSyntax; friend class Syntax; friend class SyntaxData; using DataType = FunctionCallArgumentListSyntaxData; FunctionCallArgumentListSyntax(const RC Root, const DataType *Data); public: static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::FunctionCallArgumentList; } }; #pragma mark - function-call-expression Data class FunctionCallExprSyntaxData : public ExprSyntaxData { friend struct SyntaxFactory; friend class FunctionCallExprSyntax; friend class FunctionCallExprSyntaxBuilder; friend class SyntaxData; RC CachedCalledExpression; RC CachedArgumentList; FunctionCallExprSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); static RC make(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); static RC makeBlank(); public: static bool classof(const SyntaxData *S) { return S->getKind() == SyntaxKind::FunctionCallExpr; } }; #pragma mark - function-call-expression API class FunctionCallExprSyntax : public ExprSyntax { using DataType = FunctionCallExprSyntaxData; friend struct SyntaxFactory; friend class FunctionCallExprSyntaxData; friend class FunctionCallExprSyntaxBuilder; friend class Syntax; friend class SyntaxData; enum class Cursor: CursorIndex { CalledExpression, LeftParen, ArgumentList, RightParen, }; FunctionCallExprSyntax(const RC Root, const DataType *Data); public: /// Get the base expression getting called. ExprSyntax getCalledExpression() const; /// Return a new `FunctionCallExprSyntax` with the given base expression /// to be called. FunctionCallExprSyntax withCalledExpression(ExprSyntax NewBaseExpression) const; /// Return the left parenthesis '(' token in this call. RC getLeftParen() const; /// Return a new `FunctionCallExprSyntax` with the given left parenthesis '(' /// token. FunctionCallExprSyntax withLeftParen(RC NewLeftParen) const; /// Get the list of arguments in this call expression. FunctionCallArgumentListSyntax getArgumentList() const; /// Return a new `FunctionCallExprSyntax` with the given argument list. FunctionCallExprSyntax withArgumentList(FunctionCallArgumentListSyntax NewArgumentList) const; /// Return the right parenthesis ')' token in this call. RC getRightParen() const; /// Return a new `FunctionCallExprSyntax` with the given right parenthesis ')' /// token. FunctionCallExprSyntax withRightParen(RC NewLeftParen) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::FunctionCallExpr; } }; #pragma mark - function-call-argument-list-builder class FunctionCallExprSyntaxBuilder { RawSyntax::LayoutList CallLayout; RawSyntax::LayoutList ListLayout; public: /// Start the builder with all elements marked as missing or empty. FunctionCallExprSyntaxBuilder(); /// Use the given expression as the call target. FunctionCallExprSyntaxBuilder & useCalledExpression(ExprSyntax CalledExpression); /// Use the given left parenthesis '(' token in the function call. FunctionCallExprSyntaxBuilder &useLeftParen(RC LeftParen); /// Add an additional argument to the layout. FunctionCallExprSyntaxBuilder & appendArgument(FunctionCallArgumentSyntax AdditionalArgument); /// Use the given right parenthesis ')' token in the function call. FunctionCallExprSyntaxBuilder &useRightParen(RC RightParen); /// Return a `FunctionCallExprSyntax` with the arguments added so far. FunctionCallExprSyntax build() const; }; } // end namespace syntax } // end namespace swift #endif // SWIFT_SYNTAX_EXPRSYNTAX_H