Esempio n. 1
0
        private void DuplicateAndCheck(Expr original, IExprBuilder builder)
        {
            var duplicator = GetDuplicator(builder);
            var copy       = (Expr)duplicator.Visit(original);

            // Check they are structually equal
            Assert.IsTrue(original.Equals(copy));

            // Check the roots are different instances
            Assert.AreNotSame(original, copy);

            // Verify the nodes are disjoint, allow constants to be shared though
            var c           = new DuplicationVerifier(/*ignoreDuplicateConstants=*/ true, /*ignoreDuplicateSymbolics=*/ false);
            var sharedNodes = c.CheckDuplication(original, copy);

            Assert.AreEqual(0, sharedNodes.Count);

            // Verify all nodes are immutable
            var iv = new ImmutableExprVerifier();

            iv.Visit(copy);
            Assert.AreEqual(0, iv.NonImmutableNodes.Count);

            // Type check both Expr
            var TC = new TypecheckingContext(this);

            original.Typecheck(TC);
            copy.Typecheck(TC);
        }
Esempio n. 2
0
 public MapExecutionStateVariablesDuplicator(ExecutionState e, IExprBuilder builder) : base(builder)
 {
     this.State              = e;
     BoundVariables          = new HashSet <Variable>();
     preReplacementReMap     = new Dictionary <Variable, Variable>();
     this.ReplaceGlobalsOnly = false;
 }
Esempio n. 3
0
        public override IExpr Build(BuildContext ctx, IExprBuilder initiator, Func <IExpr> next)
        {
            if (ctx.Token is ParenthesisToken openT && openT.IsOpen)
            {
                ctx.NextIndex();

                IExpr            innerExpr;
                ParenthesisToken closeT;
                while (true)
                {
                    innerExpr = next();
                    ThrowIfExprIsNull(innerExpr, ctx.Token);

                    if (ctx.Token is ParenthesisToken token && !token.IsOpen)
                    {
                        closeT = token;
                        break;
                    }

                    ctx.PushExpr(innerExpr);
                }

                ctx.NextIndex();

                return(new GroupExpr(Env)
                {
                    OpenToken = openT, CloseToken = closeT, InnerExpr = innerExpr,
                });
            }

            return(null);
        }
Esempio n. 4
0
        public override IExpr Build(BuildContext ctx, IExprBuilder initiator, Func <IExpr> next)
        {
            if (ctx.Token is NegationToken t)
            {
                ctx.NextIndex();

                var nextExpr = next();
                ThrowIfExprIsNull(nextExpr, t);

                if (nextExpr is ICanBeNegated expr)
                {
                    if (!Helpers.TypesMatch(expr.ReturnType, Enums.Type.Bool))
                    {
                        throw new CodeBuildEx(t.IdxS, expr.IdxE,
                                              string.Format(tr.operator__0__cannot_be_applied_to_operands_of_type__1,
                                                            t,
                                                            expr.ReturnType
                                                            ));
                    }

                    return(new NegationExpr(Env)
                    {
                        Token = t, Expr = expr,
                    });
                }
            }

            return(null);
        }
        public override IExpr Build(BuildContext ctx, IExprBuilder initiator, Func <IExpr> next)
        {
            if (ctx.Token is ArithmeticSymbolToken t &&
                (t.Operation == ArithmeticOperation.Add || t.Operation == ArithmeticOperation.Subtract))
            {
                ctx.NextIndex();

                var nextExpr = next();
                ThrowIfExprIsNull(nextExpr, t);

                if (nextExpr is ICanBePrefixedWithPlusOrMinus expr)
                {
                    if (!Helpers.TypesMatch(expr.ReturnType, Enums.Type.Number))
                    {
                        throw new CodeBuildEx(t.IdxS, expr.IdxE,
                                              string.Format(tr.operator__0__cannot_be_applied_to_operands_of_type__1,
                                                            t,
                                                            expr.ReturnType
                                                            ));
                    }

                    return(new PlusOrMinusExpr(Env)
                    {
                        Token = t, Expr = expr,
                    });
                }
            }

            return(null);
        }
Esempio n. 6
0
            public Query WithNegatedQueryExpr(IExprBuilder builder)
            {
                var that = (Query)this.MemberwiseClone();

                that.QueryExpr = this.QueryExpr.GetNegatedConstraint(builder);
                return(that);
            }
Esempio n. 7
0
        public override IExpr Build(BuildContext ctx, IExprBuilder initiator, Func <IExpr> next)
        {
            if (ctx.Token is LiteralToken t)
            {
                var func = Env.GetFunc(t.String);
                if (func == null)
                {
                    throw new CodeBuildEx(t.IdxS, t.IdxE,
                                          string.Format(
                                              tr.the_name__0__does_not_exist_in_the_current_environment,
                                              t.String
                                              ));
                }

                ctx.NextIndex();

                var funcExpr = new FuncExpr(Env)
                {
                    Token = t, Func = func
                };

                ThrowIf(ctx.Token, token => !(ctx.Token is ParenthesisToken openT) || !openT.IsOpen);

                funcExpr.ArgsBlockOpenToken = (ParenthesisToken)ctx.Token;

                ctx.NextIndex();

                IExpr expr;
                while (true)
                {
                    expr = next();
                    ThrowIfExprIsNull(expr, ctx.Token);

                    if (ctx.Token is ParenthesisToken token && !token.IsOpen)
                    {
                        funcExpr.Args.Add(expr);
                        funcExpr.ArgsBlockCloseToken = token;
                        break;
                    }

                    if (ctx.Token is SeparatorToken)
                    {
                        funcExpr.Args.Add(expr);
                        ctx.NextIndex();
                        continue;
                    }

                    ctx.PushExpr(expr);
                }

                func.ValidateArgs(Env, funcExpr.Args);

                ctx.NextIndex();

                return(funcExpr);
            }

            return(null);
        }
Esempio n. 8
0
        public override IExpr Build(BuildContext ctx, IExprBuilder initiator, Func <IExpr> next)
        {
            //
            // `StringConcatExprBuilder` is an optimization for expressions that contains a `+` (plus),
            // and at least one operand of a `String` type.
            // String concatenations are also possible with objects of an `Any` type. Only that, those
            // expressions are built as `MathExpr` (since there is no way, rather than identifying type at the runtime).
            if (ctx.Token is ArithmeticSymbolToken t && t.Operation == Enums.ArithmeticOperation.Add)
            {
                if (initiator is StringConcatExprBuilder || ctx.BuiltExprs.Count == 0)
                {
                    return(null);
                }

                var prevExpr = ctx.LastExpr;
                if (prevExpr.ReturnType == Enums.Type.String)
                {
                    ctx.NextIndex();

                    var nextExpr = next();
                    ThrowIfExprIsNull(nextExpr, t);

                    ctx.PopExpr();

                    return(new StringConcatExpr(Env)
                    {
                        Token = t, A = prevExpr, B = nextExpr,
                    });
                }
                else
                {
                    if (!_applyOptimization) // try to find if B contains a string (has high computational cost)
                    {
                        var ctxCopy = ctx.CreateCopy();

                        ctx.NextIndex();

                        var nextExpr = next();
                        ThrowIfExprIsNull(nextExpr, t);

                        if (nextExpr.ReturnType == Enums.Type.String)
                        {
                            ctx.PopExpr();

                            return(new StringConcatExpr(Env)
                            {
                                Token = t, A = prevExpr, B = nextExpr,
                            });
                        }

                        ctx.RestoreFrom(ctxCopy);
                    }
                }
            }

            return(null);
        }
Esempio n. 9
0
        public void RemoveNoConstraintsBasedOnVars()
        {
            IConstraintManager CM      = new ConstraintManager();
            IExprBuilder       builder = GetBuilder();

            // Dummy Boogie variable
            var bv8TypeIdent = new TypedIdent(Token.NoToken, "bv8", Microsoft.Boogie.Type.GetBvType(8));
            var dummyVarBv   = new GlobalVariable(Token.NoToken, bv8TypeIdent);

            // dummyVar needs a programLocation, otherwise SymbolicVariable constructor raises an exception
            var progLoc = new ProgramLocation(dummyVarBv);

            dummyVarBv.SetMetadata <ProgramLocation>((int)Symbooglix.Annotation.AnnotationIndex.PROGRAM_LOCATION, progLoc);

            var s0 = new SymbolicVariable("s0", dummyVarBv).Expr;
            var s1 = new SymbolicVariable("s1", dummyVarBv).Expr;
            var s2 = new SymbolicVariable("s2", dummyVarBv).Expr;

            // Construct some constraints
            Expr c0 = builder.Eq(builder.BVAND(s0, s1), builder.ConstantBV(0, 8));
            Expr c1 = builder.Eq(s2, builder.ConstantBV(1, 8));

            CM.AddConstraint(c0, progLoc);
            CM.AddConstraint(c1, progLoc);

            var mockSolver      = new MockSolver();
            var indepenceSolver = new Symbooglix.Solver.ConstraintIndependenceSolver(mockSolver);

            Expr queryExpr = builder.Eq(builder.BVAND(s1, s2), builder.ConstantBV(0, 8));

            indepenceSolver.ComputeSatisfiability(new Solver.Query(CM, new Constraint(queryExpr)));

            // Check no constraints were removed
            Assert.AreEqual(2, mockSolver.Constraints.Count);
            Assert.AreSame(queryExpr, mockSolver.QueryExpr);

            bool c0Found = false;
            bool c1Found = false;

            foreach (var constraint in mockSolver.Constraints)
            {
                if (c0 == constraint.Condition)
                {
                    c0Found = true;
                }

                if (c1 == constraint.Condition)
                {
                    c1Found = true;
                }
            }

            Assert.IsTrue(c0Found);
            Assert.IsTrue(c1Found);
        }
Esempio n. 10
0
        public override IExpr Build(BuildContext ctx, IExprBuilder initiator, Func <IExpr> next)
        {
            if (ctx.Token is LogicalOperatorToken t)
            {
                if (initiator is LogicalExprBuilder || ctx.BuiltExprs.Count == 0)
                {
                    return(null);
                }

                var prevExpr = ctx.LastExpr;
                if (!Helpers.TypesMatch(prevExpr.ReturnType, Enums.Type.Bool))
                {
                    throw new CodeBuildEx(t.IdxS, t.IdxE,
                                          string.Format(tr.operator__0__cannot_be_applied_to_operands_of_type__1,
                                                        t,
                                                        prevExpr.ReturnType
                                                        ));
                }

                ctx.NextIndex();

                var hasB = false;

                IExpr nextExpr;
                while (true)
                {
                    nextExpr = next();

                    if (!hasB)
                    {
                        ThrowIfExprIsNull(nextExpr, t);
                    }

                    if (nextExpr == null)
                    {
                        break;
                    }

                    hasB = true;
                    ctx.PushExpr(nextExpr);
                }

                nextExpr = ctx.PopExpr(); // nextExpr

                ctx.PopExpr();            // prevExpr

                return(new LogicalExpr(Env)
                {
                    Token = t, A = prevExpr, B = nextExpr,
                });
            }

            return(null);
        }
Esempio n. 11
0
        public override IExpr Build(BuildContext ctx, IExprBuilder initiator, Func <IExpr> next)
        {
            if (ctx.Token is IConstantToken t)
            {
                ctx.NextIndex();

                return(ConstantExprFactory.Create(t, Env));
            }

            return(null);
        }
Esempio n. 12
0
        protected virtual IExpr Cycle(BuildContext ctx, IExprBuilder initiator = null)
        {
            for (var idx = 0; idx < Builders.Count; idx++)
            {
                var expr = Builders[idx].Build(ctx, initiator, () => Cycle(ctx, Builders[idx]));
                if (expr != null)
                {
                    return(expr);
                }
            }

            return(null);
        }
Esempio n. 13
0
        private Dictionary <int, Dictionary <BigInteger, LiteralExpr> > BitVectorCache; // FIXME: Should probably use concurrent dictionary for thread safety
        public ConstantCachingExprBuilder(IExprBuilder underlyingBuilder) : base(underlyingBuilder)
        {
            // It's not safe to cache expressions if the underlying builder does not give immutable LiteralExprs
            if (!UB.Immutable)
            {
                throw new ArgumentException("Underlying builder must build immutable expressions");
            }

            // Setup Caches
            this.CachedTrueExpr = UB.True;
            Debug.Assert(this.CachedTrueExpr.isBool && this.CachedTrueExpr.asBool);
            this.CachedFalseExpr = UB.False;
            Debug.Assert(this.CachedFalseExpr.isBool && !this.CachedFalseExpr.asBool);
            this.IntegerCache   = new Dictionary <BigInteger, LiteralExpr>();
            this.RealCache      = new Dictionary <BigDec, LiteralExpr>();
            this.BitVectorCache = new Dictionary <int, Dictionary <BigInteger, LiteralExpr> >();
        }
Esempio n. 14
0
        public Constraint GetNegatedConstraint(IExprBuilder builder)
        {
            var that = (Constraint)this.MemberwiseClone();

            // Optimisation:
            // We don't need to recompute (or copy) the set of used UF and variables
            // for that

            // Negate the Condition
            if (!Condition.Type.IsBool)
            {
                throw new ExprTypeCheckException("Cannot negate an expression that is not a bool");
            }

            that.Condition = builder.Not(this.Condition);
            return(that);
        }
Esempio n. 15
0
        public override IExpr Build(BuildContext ctx, IExprBuilder initiator, Func <IExpr> next)
        {
            if (ctx.Token is ArrayParenthesisToken openT && openT.IsOpen)
            {
                ctx.NextIndex();

                var arrayExpr = new ArrayExpr(Env)
                {
                    OpenToken = openT,
                };

                IExpr expr;
                while (true)
                {
                    expr = next();
                    ThrowIfExprIsNull(expr, ctx.Token);

                    if (ctx.Token is ArrayParenthesisToken token && !token.IsOpen)
                    {
                        arrayExpr.Elements.Add(expr);
                        arrayExpr.CloseToken = token;
                        break;
                    }

                    if (ctx.Token is SeparatorToken)
                    {
                        arrayExpr.Elements.Add(expr);
                        ctx.NextIndex();
                        continue;
                    }

                    ctx.PushExpr(expr);
                }

                ctx.NextIndex();

                arrayExpr.IdentifyExactReturnType();
                return(arrayExpr);
            }

            return(null);
        }
Esempio n. 16
0
        public override IExpr Build(BuildContext ctx, IExprBuilder initiator, Func <IExpr> next)
        {
            if (ctx.Token is ComparisonToken t)
            {
                if (initiator is ConditionalExprBuilder || ctx.BuiltExprs.Count == 0)
                {
                    return(null);
                }

                var prevExpr = ctx.LastExpr;

                ctx.NextIndex();

                var nextExpr = next();
                ThrowIfExprIsNull(nextExpr, t);

                if (!Helpers.TypesMatch(prevExpr.ReturnType, nextExpr.ReturnType))
                {
                    throw new CodeBuildEx(t.IdxS, t.IdxE,
                                          string.Format(tr.operator__0__cannot_be_applied_to_operands_of_type__1__and__2,
                                                        t,
                                                        prevExpr.ReturnType,
                                                        nextExpr.ReturnType
                                                        ));
                }

                ctx.PopExpr();

                return(new ConditionalExpr(Env)
                {
                    Token = t, A = prevExpr, B = nextExpr,
                });
            }

            return(null);
        }
Esempio n. 17
0
 public TypeSynonym()
 {
     builder = new SimpleExprBuilder(/*immutable=*/ true);
 }
Esempio n. 18
0
        public override IExpr Build(BuildContext ctx, IExprBuilder initiator, Func <IExpr> next)
        {
            if (ctx.Token is ArithmeticSymbolToken t)
            {
                if (initiator is MathExprBuilder || ctx.BuiltExprs.Count == 0)
                {
                    return(null);
                }

                var prevExpr = ctx.LastExpr;

                IMathExprSuperior superior = null;
                if (prevExpr is IMathExprSuperior)
                {
                    superior = (IMathExprSuperior)prevExpr;
                    prevExpr = superior.B;
                }

                if (!Helpers.TypesMatch(prevExpr.ReturnType, Enums.Type.Number))
                {
                    return(null);
                }

                ctx.NextIndex();

                var nextExpr = next();
                ThrowIfExprIsNull(nextExpr, t);

                if (!Helpers.TypesMatch(nextExpr.ReturnType, Enums.Type.Number))
                {
                    if (_applyStringConcatOptimization)
                    {
                        if (t.Operation == ArithmeticOperation.Add)
                        {
                            // `StringConcatExprBuilder` will only build an expr if A has a string return type
                            if (nextExpr.ReturnType == Enums.Type.String)
                            {
                                ctx.PopExpr();

                                return(new StringConcatExpr(Env)
                                {
                                    Token = t, A = prevExpr, B = nextExpr,
                                });
                            }
                        }
                    }

                    throw new CodeBuildEx(t.IdxS, t.IdxE,
                                          string.Format(tr.operator__0__cannot_be_applied_to_operands_of_type__1,
                                                        t,
                                                        nextExpr.ReturnType
                                                        ));
                }

                ctx.PopExpr();

                var mathExpr = new MathExpr(Env)
                {
                    Token = t, A = prevExpr, B = nextExpr
                };

                if (prevExpr is MathExpr prevMathExpr &&
                    Helpers.GetArithmeticOperationPriority(t.Operation) >
                    Helpers.GetArithmeticOperationPriority(prevMathExpr.Token.Operation)
                    )
                {
                    // rearrange expressions based on operation priority: e.g. "((1 + 1) * 10)" -> "(1 + (1 * 10))"
                    mathExpr.A     = prevMathExpr.B;
                    prevMathExpr.B = mathExpr;

                    // keep previous math expression as the principal one
                    mathExpr = prevMathExpr;
                }

                if (superior != null)
                {
                    superior.B = mathExpr;
                    return(superior);
                }
                else
                {
                    return(mathExpr);
                }
            }

            return(null);
        }
Esempio n. 19
0
 public Literal()
 {
     SymbooglixLibTests.SymbooglixTest.SetupDebug();
     Builder = new SimpleExprBuilder(/*immutable=*/ true);
 }
Esempio n. 20
0
            public IBranchSatisfiabilityResult CheckBranchSatisfiability(IConstraintManager constraints, Constraint trueExpr, IExprBuilder builder)
            {
                // Note: We implicitly assume that the constraints are satisfiable
                TryInterupt = false;
                IQueryResult falseBranchResult = null;
                IQueryResult trueBranchResult  = null;

                try
                {
                    Timer.Start();
                    // Fast path: trueExpr is constant
                    var trueExprAsLit = ExprUtil.AsLiteral(trueExpr.Condition);
                    if (trueExprAsLit != null)
                    {
                        if (!trueExprAsLit.isBool)
                        {
                            throw new ExprTypeCheckException("trueExpr must be of boolean type");
                        }

                        if (trueExprAsLit.asBool)
                        {
                            return(new SimpleBranchSatsifiabilityResult(Result.SAT, Result.UNSAT));
                        }
                        else
                        {
                            return(new SimpleBranchSatsifiabilityResult(Result.UNSAT, Result.SAT));
                        }
                    }

                    // Slow path: Invoke solver

                    // First see if it's possible for the false branch to be feasible
                    // ∃ X constraints(X) ∧ ¬ condition(X)
                    var query = new Solver.Query(constraints, trueExpr);
                    falseBranchResult = InternalComputeSatisfiability(query.WithNegatedQueryExpr(builder));
                    var falseBranch = falseBranchResult.Satisfiability;


                    var trueBranch = Result.UNKNOWN;
                    // Only invoke solver again if necessary
                    if (falseBranch == Result.UNSAT)
                    {
                        // This actually implies that
                        //
                        // ∀X : C(X) → Q(X)
                        // That is if the constraints are satisfiable then
                        // the query expr is always true. Because we've been
                        // checking constraints as we go we already know C(X) is satisfiable
                        trueBranch = Result.SAT;
                    }
                    else
                    {
                        if (TryInterupt)
                        {
                            // Don't do next solver call
                            Console.Error.WriteLine("WARNING: Tried to kill solver during CheckBranchSatisfiability()");
                            return(new SimpleBranchSatsifiabilityResult(Result.UNKNOWN, falseBranch));
                        }

                        // Now see if it's possible for execution to continue past the assertion
                        // ∃ X constraints(X) ∧ condition(X)
                        trueBranchResult = InternalComputeSatisfiability(query);
                        trueBranch       = trueBranchResult.Satisfiability;
                    }

                    return(new SimpleBranchSatsifiabilityResult(trueBranch, falseBranch));
                }
                finally
                {
                    Timer.Stop();
                    if (falseBranchResult != null)
                    {
                        UpdateStatistics(falseBranchResult);
                    }

                    if (trueBranchResult != null)
                    {
                        UpdateStatistics(trueBranchResult);
                    }
                }
            }
Esempio n. 21
0
 public BuilderDuplicator(IExprBuilder builder)
 {
     Debug.Assert(builder != null);
     Builder = builder;
 }
Esempio n. 22
0
 private BuilderDuplicator GetDuplicator(IExprBuilder builder)
 {
     return(new BuilderDuplicator(builder));
 }
Esempio n. 23
0
 public CallAssignsTo()
 {
     Builder = new SimpleExprBuilder(/*immutable=*/ true);
 }
Esempio n. 24
0
 public MathParserTest()
 {
     _basicExprBuilder = new ExprBuilder();
 }
Esempio n. 25
0
 private void Init()
 {
     p       = LoadProgramFrom("programs/SimpleCallSummary.bpl");
     e       = GetExecutor(p, new DFSStateScheduler(), GetSolver());
     Builder = new SimpleExprBuilder(/*immutable=*/ true);
 }
Esempio n. 26
0
        public void RemoveNoConstraintsBasedOnVarsAndFunctions()
        {
            IConstraintManager CM      = new ConstraintManager();
            IExprBuilder       builder = GetBuilder();

            // Dummy Boogie variable
            var bv8Type      = Microsoft.Boogie.Type.GetBvType(8);
            var bv8TypeIdent = new TypedIdent(Token.NoToken, "bv8", bv8Type);
            var dummyVarBv   = new GlobalVariable(Token.NoToken, bv8TypeIdent);

            // dummyVar needs a programLocation, otherwise SymbolicVariable constructor raises an exception
            var progLoc = new ProgramLocation(dummyVarBv);

            dummyVarBv.SetMetadata <ProgramLocation>((int)Symbooglix.Annotation.AnnotationIndex.PROGRAM_LOCATION, progLoc);

            var s0 = new SymbolicVariable("s0", dummyVarBv).Expr;
            var s1 = new SymbolicVariable("s1", dummyVarBv).Expr;
            var s2 = new SymbolicVariable("s2", dummyVarBv).Expr;

            // Construct some constraints
            Expr c0 = builder.Eq(builder.BVAND(s0, s1), builder.ConstantBV(0, 8));
            Expr c1 = builder.Eq(s2, builder.ConstantBV(1, 8));

            var FCB        = new FunctionCallBuilder();
            var foobarFunc = FCB.CreateUninterpretedFunctionCall("foobar", bv8Type, new List <Microsoft.Boogie.Type>()
            {
                bv8Type
            });
            // foobar(0bv8) == 0bv8
            Expr c2 = builder.Eq(builder.UFC(foobarFunc, builder.ConstantBV(0, 8)), builder.ConstantBV(0, 8));

            CM.AddConstraint(c0, progLoc);
            CM.AddConstraint(c1, progLoc);
            CM.AddConstraint(c2, progLoc);

            var mockSolver      = new MockSolver();
            var indepenceSolver = new Symbooglix.Solver.ConstraintIndependenceSolver(mockSolver);

            // The query expression uses the "foobar" function so we need to keep constraints on that function
            Expr queryExpr = builder.And(builder.Eq(builder.BVAND(s1, s2), builder.ConstantBV(0, 8)),
                                         builder.NotEq(builder.UFC(foobarFunc, s1), s1)
                                         );

            indepenceSolver.ComputeSatisfiability(new Solver.Query(CM, new Constraint(queryExpr)));

            // Check no constraints were removed
            Assert.AreEqual(3, mockSolver.Constraints.Count);
            Assert.AreSame(queryExpr, mockSolver.QueryExpr);

            bool c0Found = false;
            bool c1Found = false;
            bool c2Found = false;

            foreach (var constraint in mockSolver.Constraints)
            {
                if (c0 == constraint.Condition)
                {
                    c0Found = true;
                }

                if (c1 == constraint.Condition)
                {
                    c1Found = true;
                }

                if (c2 == constraint.Condition)
                {
                    c2Found = true;
                }
            }

            Assert.IsTrue(c0Found);
            Assert.IsTrue(c1Found);
            Assert.IsTrue(c2Found);
        }
Esempio n. 27
0
 public DecoratorExprBuilder(IExprBuilder underlyingBuilder)
 {
     UB = underlyingBuilder;
 }
Esempio n. 28
0
 public abstract IExpr Build(BuildContext ctx, IExprBuilder initiator, Func <IExpr> next);