Пример #1
0
        public void SyntaxTrie_Unchanged5()
        {
            Expression <Action> f = () => Foo(x => x, x => x, x => x, x => x);
            var g = AlphaRenamer.EliminateNameConflicts(f);

            var eq = new ExpressionEqualityComparer();

            Assert.IsTrue(eq.Equals(f, g));
            Assert.AreSame(f, g);
        }
Пример #2
0
        public void SyntaxTrie_Unchanged4()
        {
            Expression <Func <int, Func <int, int> > > f = x => y => y;
            var g = AlphaRenamer.EliminateNameConflicts(f.Body);

            var eq = new ExpressionEqualityComparer();

            Assert.IsTrue(eq.Equals(f.Body, g));
            Assert.AreSame(f.Body, g);
        }
Пример #3
0
        public void SyntaxTrie_Rename4()
        {
            var x = Expression.Parameter(typeof(int));
            var y = Expression.Parameter(typeof(int));
            var z = Expression.Parameter(typeof(int));

            var f = Expression.Lambda(Expression.Lambda(Expression.Lambda(z, z), y), x);
            var g = AlphaRenamer.EliminateNameConflicts(f);

            Assert.AreEqual("Param_0 => Param_1 => Param_2 => Param_2", f.ToString());
            Assert.AreEqual("Param_0 => Param_1 => Param_2 => Param_2", g.ToString());
        }
Пример #4
0
        public void SyntaxTrie_Rename3()
        {
            var x = Expression.Parameter(typeof(int), "x");
            var y = Expression.Parameter(typeof(int), "x0");
            var z = Expression.Parameter(typeof(int), "x");

            var f = Expression.Lambda(Expression.Lambda(Expression.Lambda(z, z), y), x);
            var g = AlphaRenamer.EliminateNameConflicts(f);

            Assert.AreEqual("x => x0 => x => x", f.ToString());
            Assert.AreEqual("x => x0 => x1 => x1", g.ToString());
        }
Пример #5
0
        public void SyntaxTrie_Rename1()
        {
            var x = Expression.Parameter(typeof(int), "x");
            var y = Expression.Parameter(typeof(int), "x");

            var f = Expression.Lambda <Func <int, Func <int, int> > >(Expression.Lambda(y, y), x);
            var g = (Expression <Func <int, Func <int, int> > >)AlphaRenamer.EliminateNameConflicts(f);

            Assert.AreEqual(2, f.Compile()(1)(2));
            Assert.AreEqual(2, g.Compile()(1)(2));

            Assert.AreEqual("x => x => x", f.ToString());
            Assert.AreEqual("x => x0 => x0", g.ToString());
        }
Пример #6
0
 public void SyntaxTrie_ArgumentChecking()
 {
     AssertEx.ThrowsException <ArgumentNullException>(() => AlphaRenamer.EliminateNameConflicts(expression: null), ex => Assert.AreEqual("expression", ex.ParamName));
 }
Пример #7
0
        public new Expression <TDelegate> Reduce()
        {
            var originalParameters        = Parameters;
            var lambdaWithParametersTwice = Expression.Lambda(Expression.Lambda(Body, originalParameters), originalParameters); // NB: Trick to rename parameters in body and retain original ones at the top.

            var alphaRenamedOuterLambda = new AlphaRenamer().VisitAndConvert(lambdaWithParametersTwice, nameof(Reduce));
            var alphaRenamedInnerLambda = (LambdaExpression)alphaRenamedOuterLambda.Body;
            var clonedParameters        = alphaRenamedInnerLambda.Parameters;

            var alphaRenamedBody = alphaRenamedInnerLambda.Body;

            var bodyWithTry = Expression.TryFinally(alphaRenamedBody, Expression.Empty());                                              // NB: Simplifies the jump table generation.

            var analyzer = new IteratorBodyAnalyzer(new ReadOnlyCollection <ParameterExpression>(Array.Empty <ParameterExpression>())); // NB: Could pass parameters later if we do data flow analysis.

            analyzer.Visit(bodyWithTry);

            var yieldReturnInfo  = new Dictionary <YieldReturnCSharpExpression, (int state, LabelTarget resumeLabel)>();
            var tryStatementInfo = new Dictionary <TryExpression, (LabelTarget label, List <(int state, LabelTarget label)> branches)>();

            int stateIndex    = 1;
            int tryLabelIndex = 1;

            foreach (var yield in analyzer.YieldReturns)
            {
                if (!IteratorInfo.ElementType.IsAssignableFrom(yield.Node.Value.Type))
                {
                    throw new InvalidOperationException("Type of value in yield return node is not assignable to iterator element type.");
                }

                var stateId = stateIndex++;
                yieldReturnInfo.Add(yield.Node, (stateId, Expression.Label("__State" + stateId)));

                foreach (var @try in yield.TryStatements)
                {
                    if (!tryStatementInfo.TryGetValue(@try, out var data))
                    {
                        var tryId    = tryLabelIndex++;
                        var branches = new List <(int, LabelTarget)>();
                        tryStatementInfo.Add(@try, (Expression.Label("__Try" + tryId), branches));
                    }
                }
            }

            foreach (var yield in analyzer.YieldReturns)
            {
                var(state, resumeLabel) = yieldReturnInfo[yield.Node];

                var targetLabel = resumeLabel;

                for (var i = yield.TryStatements.Length - 1; i >= 0; i--)
                {
                    var @try = yield.TryStatements[i];
                    var(label, branches) = tryStatementInfo[@try];

                    branches.Add((state, targetLabel));

                    targetLabel = label;
                }
            }

            var localsToHoist = new HashSet <ParameterExpression>(analyzer.YieldReturns.SelectMany(y => y.Variables));

            var stateVariable            = Expression.Parameter(typeof(int), "state");
            var shouldBreakVariable      = Expression.Parameter(typeof(bool), "shouldBreak");
            var nextStateOutVariable     = Expression.Parameter(typeof(int).MakeByRefType(), "nextState");
            var hasNextOutVariable       = Expression.Parameter(typeof(bool).MakeByRefType(), "hasNext");
            var shouldRunFinallyVariable = Expression.Parameter(typeof(bool), "__shouldRunFinally");
            var resultTemporaryVariable  = Expression.Parameter(IteratorInfo.ElementType, "__result");

            var assignNextStateNone = Expression.Assign(nextStateOutVariable, Expression.Constant(-1));
            var assignHasNextFalse  = Expression.Assign(hasNextOutVariable, Expression.Constant(false));

            var yieldBreakLabel = Expression.Label("__YieldBreak");
            var returnLabel     = Expression.Label(IteratorInfo.ElementType, "__Return");

            var rewriter = new IteratorBodyRewriter(stateVariable, shouldBreakVariable, nextStateOutVariable, hasNextOutVariable, shouldRunFinallyVariable, resultTemporaryVariable, yieldBreakLabel, returnLabel, yieldReturnInfo, tryStatementInfo, localsToHoist);

            var rewrittenIteratorBody = rewriter.Visit(bodyWithTry);

            var body =
                Expression.Block(
                    IteratorInfo.ElementType,
                    new[] { shouldRunFinallyVariable, resultTemporaryVariable },
                    Expression.Assign(shouldRunFinallyVariable, Expression.Constant(true)),
                    rewrittenIteratorBody,
                    Expression.Label(yieldBreakLabel),
                    assignNextStateNone,
                    assignHasNextFalse,
                    Expression.Label(returnLabel, Expression.Default(IteratorInfo.ElementType))
                    );

            var tryGetNextLambda = Expression.Lambda(typeof(TryGetNext <>).MakeGenericType(IteratorInfo.ElementType), body, stateVariable, shouldBreakVariable, nextStateOutVariable, hasNextOutVariable);

            var tryGetNextLambdaFactory =
                Expression.Lambda(
                    Expression.Block(
                        clonedParameters.Concat(localsToHoist),
                        clonedParameters.Zip(originalParameters, (c, o) => Expression.Assign(c, o)).Concat(new Expression[]
            {
                tryGetNextLambda
            })
                        )
                    );

            // Func<TryGetNext<T>> factory = () =>
            // {
            //     var p1' = p1;
            //     var p2' = p2;
            //     var h1 = default;
            //     var h2 = default;
            //     return (a, b, c, d) => ...;
            // };
            // ((p1, p2) => new TIterator(factory))(p1, p2, default, default);

            var runtimeIteratorBuilderType = GetRuntimeIteratorBuilderType(IteratorInfo.BuilderType);
            var runtimeIteratorBuilderCtor = runtimeIteratorBuilderType.GetConstructors().Single();

            var result =
                Expression.Lambda <TDelegate>(
                    Expression.New(runtimeIteratorBuilderCtor, tryGetNextLambdaFactory),
                    originalParameters
                    );

            return(result);
        }