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); }
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); }
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()); }
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()); }
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()); }
public void SyntaxTrie_ArgumentChecking() { AssertEx.ThrowsException <ArgumentNullException>(() => AlphaRenamer.EliminateNameConflicts(expression: null), ex => Assert.AreEqual("expression", ex.ParamName)); }
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); }