@@ -964,6 +964,65 @@ class NoExceptExpr extends Expr, @noexceptexpr {
964964 }
965965}
966966
967+ /**
968+ * A C++17 fold expression.
969+ */
970+ class FoldExpr extends Expr , @foldexpr {
971+ override string toString ( ) {
972+ exists ( string op |
973+ op = this .getOperatorString ( ) and
974+ if this .isUnaryFold ( )
975+ then
976+ if this .isLeftFold ( )
977+ then result = "( ... " + op + " pack )"
978+ else result = "( pack " + op + " ... )"
979+ else
980+ if this .isLeftFold ( )
981+ then result = "( init " + op + " ... " + op + " pack )"
982+ else result = "( pack " + op + " ... " + op + " init )"
983+ )
984+ }
985+
986+ /** Gets the binary operator used in this fold expression, as a string. */
987+ string getOperatorString ( ) { fold ( underlyingElement ( this ) , result , _) }
988+
989+ /** Holds if this is a left-fold expression. */
990+ predicate isLeftFold ( ) { fold ( underlyingElement ( this ) , _, true ) }
991+
992+ /** Holds if this is a right-fold expression. */
993+ predicate isRightFold ( ) { fold ( underlyingElement ( this ) , _, false ) }
994+
995+ /** Holds if this is a unary fold expression. */
996+ predicate isUnaryFold ( ) { getNumChild ( ) = 1 }
997+
998+ /** Holds if this is a binary fold expression. */
999+ predicate isBinaryFold ( ) { getNumChild ( ) = 2 }
1000+
1001+ /**
1002+ * Gets the child expression containing the unexpanded parameter pack.
1003+ */
1004+ Expr getPackExpr ( ) {
1005+ this .isUnaryFold ( ) and
1006+ result = getChild ( 0 )
1007+ or
1008+ this .isBinaryFold ( ) and
1009+ if this .isRightFold ( ) then result = getChild ( 0 ) else result = getChild ( 1 )
1010+ }
1011+
1012+ /**
1013+ * If this is a binary fold, gets the expression representing the initial value.
1014+ */
1015+ Expr getInitExpr ( ) {
1016+ this .isBinaryFold ( ) and
1017+ if this .isRightFold ( ) then result = getChild ( 1 ) else result = getChild ( 0 )
1018+ }
1019+
1020+ /**
1021+ * Holds if this is a binary fold with a child expression representing the initial value.
1022+ */
1023+ predicate hasInitExpr ( ) { exists ( this .getInitExpr ( ) ) }
1024+ }
1025+
9671026/**
9681027 * Holds if `child` is the `n`th child of `parent` in an alternative syntax
9691028 * tree that has `Conversion`s as part of the tree.
0 commit comments