public void AssignBinary_Index_Compile() { foreach (var t in new[] { typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float), typeof(double), typeof(decimal), }) { var toString = t.GetMethod("ToString", Array.Empty <Type>()); var exp = "42"; if (t == typeof(char)) { exp = ((char)42).ToString(); } AssertCompile((log, append) => { var y = Expression.Parameter(t); var val = Expression.Convert(Expression.Constant(41), t); var one = Expression.Convert(Expression.Constant(1), t); var list = typeof(List <>).MakeGenericType(t); var ctor = list.GetConstructor(new[] { typeof(IEnumerable <>).MakeGenericType(t) }); var item = list.GetProperty("Item"); var index = CSharpExpression.Index( Expression.Block( log("L"), Expression.New(ctor, Expression.NewArrayInit(t, Expression.Default(t), val)) ), item, CSharpExpression.Bind( item.GetIndexParameters()[0], Expression.Block( log("I"), Expression.Constant(1) ) ) ); return (Expression.Block( new[] { y }, Expression.Assign(y, CSharpExpression.AddAssign(index, Expression.Block(log("V"), one))), Expression.Invoke(append, Expression.Call(y, toString)) )); }, new LogAndResult <object> { Log = { "L", "I", "V", exp } }); } // TODO: tests with multiple indexer parameters out of order }
private static IEnumerable <Expression> GetLhs() { yield return(Expression.Parameter(typeof(int))); yield return(Expression.Field(Expression.Parameter(typeof(StrongBox <int>)), "Value")); yield return(Expression.MakeIndex(Expression.Parameter(typeof(List <int>)), typeof(List <int>).GetProperty("Item"), new[] { Expression.Constant(0) })); yield return(Expression.ArrayAccess(Expression.Parameter(typeof(int[])), Expression.Constant(0))); yield return(CSharpExpression.Index(Expression.Parameter(typeof(List <int>)), typeof(List <int>).GetProperty("Item"), CSharpExpression.Bind(typeof(List <int>).GetProperty("Item").GetIndexParameters()[0], Expression.Constant(0)))); }
public void ShadowEliminator_NoShadow() { var v1 = Expression.Parameter(typeof(int)); var v2 = Expression.Parameter(typeof(int)); var e1 = Expression.Parameter(typeof(Exception)); var e2 = Expression.Parameter(typeof(Exception)); var d1 = Expression.Parameter(typeof(IDisposable)); var d2 = Expression.Parameter(typeof(IDisposable)); var r1 = Expression.Default(typeof(IDisposable)); var c1 = Expression.Parameter(typeof(int[])); var c2 = Expression.Parameter(typeof(int[])); var i1 = Expression.Default(typeof(int)); var b1 = Expression.Default(typeof(bool)); var l1 = Expression.Label(); var l2 = Expression.Label(); var x1 = Expression.Constant(1); var x2 = Expression.Constant(2); var es = new Expression[] { Expression.Block(new[] { v1 }, Expression.Block(new[] { v2 }, Expression.Add(v1, v2))), Expression.Lambda(Expression.Lambda(Expression.Add(v1, v2), v2), v1), Expression.TryCatch(Expression.Empty(), Expression.Catch(e1, Expression.TryCatch(Expression.Empty(), Expression.Catch(e2, Expression.Empty())))), Expression.TryCatch(Expression.Empty(), Expression.Catch(typeof(Exception), Expression.TryCatch(Expression.Empty(), Expression.Catch(typeof(Exception), Expression.Empty())))), CSharpExpression.Using(d1, r1, CSharpExpression.Using(d2, r1, Expression.Empty())), CSharpExpression.Using(r1, CSharpExpression.Using(r1, Expression.Empty())), CSharpExpression.ForEach(v1, c1, CSharpExpression.ForEach(v2, c2, Expression.Empty())), CSharpExpression.For(new[] { Expression.Assign(v1, i1) }, b1, null, CSharpExpression.For(new[] { Expression.Assign(v2, i1) }, b1, null, Expression.Empty())), CSharpExpression.Switch(x1, l1, new[] { v1 }, new[] { CSharpExpression.SwitchCase(new[] { 1 }, CSharpExpression.Switch(x2, l2, new[] { v2 }, new[] { CSharpExpression.SwitchCase(new[] { 2 }, Expression.Add(v1, v2)) })) }), CSharpExpression.Block(new[] { v1 }, new Expression[] { CSharpExpression.Block(new[] { v2 }, new Expression[] { Expression.Add(v1, v2) }, l1) }, l2), }; foreach (var e in es) { Assert.AreSame(e, ShadowEliminator.Eliminate(e)); } }
public void ShadowEliminator_Shadow_Switch() { var v = Expression.Constant(1); var l = Expression.Label(); var x = Expression.Parameter(typeof(int)); var e = CSharpExpression.Switch(v, l, new[] { x }, new[] { CSharpExpression.SwitchCase(new[] { 1 }, CSharpExpression.Switch(x, l, new[] { x }, new[] { CSharpExpression.SwitchCase(new[] { 2 }, x) })) }); var r = (SwitchCSharpStatement)ShadowEliminator.Eliminate(e); var v1 = r.Variables[0]; var e1 = (SwitchCSharpStatement)r.Cases[0].Statements[0]; var vi = e1.SwitchValue; // not in inner scope var v2 = e1.Variables[0]; var e2 = e1.Cases[0].Statements[0]; Assert.AreSame(v1, vi); // not in inner scope Assert.AreSame(v2, e2); Assert.AreNotSame(v1, v2); }
public void ArrayAccess_ByRef_CSharpNodes_Int() { var xs = Expression.Parameter(typeof(int[])); var i = Expression.Parameter(typeof(int)); var inc = typeof(Interlocked).GetMethod(nameof(Interlocked.Increment), new[] { typeof(int).MakeByRefType() }); MethodCallCSharpExpression mce = CSharpExpression.Call(inc, new Expression[] { CSharpExpression.ArrayAccess(xs, i) }); var res = Expression.Lambda <Func <int[], int, int> >(mce, xs, i); var f = res.Compile(); var vals = new int[] { 41 }; int val = f(vals, 0); Assert.AreEqual(42, val); Assert.AreEqual(42, vals[0]); }
public static IEnumerable <object[]> ExpressionData() { var expressions = new Expression[] { // Add CSharpExpression.ParseFunc <int>("unchecked(2 + 2)"), CSharpExpression.ParseFunc <string>("\"\" + \"a\""), CSharpExpression.ParseFunc <string>("\"\" + \"\""), CSharpExpression.ParseFunc <string>("\"a\" + \"b\""), CSharpExpression.ParseFunc <string>("\"a\" + \"b\"+ \"c\""), CSharpExpression.ParseFunc <string>("\"\" + \"\"+ \"\""), CSharpExpression.ParseFunc <string>("\"\" + \"\"+ \"\""), CSharpExpression.ParseFunc <string>("\"\" + \"a\"+ \"\""), CSharpExpression.ParseFunc <string>("\"\\r\" + \"\\n\""), CSharpExpression.ParseFunc <string>("\"\\\\\" + \"\\\\\""), CSharpExpression.ParseFunc <string>("\"\\\\\" + \"\\\\\\\\\""), CSharpExpression.ParseFunc <string>("\"a\\r\" + \"\\nb\""), CSharpExpression.ParseFunc <string>("\"\\x038\" + \"\\u0112\"+ \"\\112\""), CSharpExpression.ParseFunc <string>("\"a\" + 1"), CSharpExpression.ParseFunc <string>("1 + \"a\""), CSharpExpression.ParseFunc <string>("\"1\" + 'a'"), CSharpExpression.ParseFunc <string>("\"1\" + '\t'"), // AddChecked CSharpExpression.ParseFunc <int>("checked(2 + 2)"), CSharpExpression.ParseFunc <int>("checked((SByte)2 + (SByte)2)"), // And CSharpExpression.ParseFunc <int>("(SByte)2 & (SByte)2"), // AndAlso CSharpExpression.ParseFunc <bool>("true && true"), // ArrayLength (Expression <Func <int[], int> >)(arg1 => arg1.Length), // ArrayIndex (Expression <Func <int[], int> >)(arg1 => arg1[0]), // Call CSharpExpression.ParseFunc <double>("Math.Max(1.0, 2.0)"), CSharpExpression.ParseFunc <double>("Math.Pow(3,4)"), CSharpExpression.ParseFunc <double>("System.Math.Pow(5,6)"), CSharpExpression.ParseFunc <double>("Math.Pow(7.0f, 8.0)"), CSharpExpression.ParseFunc <double>("Math.Pow(9.0, y: 10.0)"), CSharpExpression.ParseFunc <double>("Math.Pow(y: 11.0, x: 12.0)"), CSharpExpression.ParseFunc <string>("default(Math)?.ToString()"), CSharpExpression.ParseFunc <string>("Math.E?.ToString()"), CSharpExpression.ParseFunc <int[], string>("arg1?[0].ToString()?[0]?.ToString().Trim()"), // Coalesce CSharpExpression.ParseFunc <int?>("null ?? 2"), // Conditional CSharpExpression.ParseFunc <int>("1 > 2 ? 1 : 2"), CSharpExpression.ParseFunc <int>("true ? 1 : 2"), CSharpExpression.ParseFunc <int>("false ? 1 : 2"), CSharpExpression.ParseFunc <int>("true ? (false ? 3 : 4) : (true ? 5 : 6)"), // Constant CSharpExpression.ParseFunc <int>("10"), CSharpExpression.ParseFunc <int>("-11"), CSharpExpression.ParseFunc <uint>("12U"), CSharpExpression.ParseFunc <long>("13L"), CSharpExpression.ParseFunc <ulong>("14UL"), CSharpExpression.ParseFunc <uint>("15u"), CSharpExpression.ParseFunc <long>("16l"), CSharpExpression.ParseFunc <ulong>("17uL"), CSharpExpression.ParseFunc <ulong>("18Ul"), CSharpExpression.ParseFunc <long>("-19l"), CSharpExpression.ParseFunc <double>("20D"), CSharpExpression.ParseFunc <double>("21d"), CSharpExpression.ParseFunc <double>("22.01d"), CSharpExpression.ParseFunc <double>("-23.01d"), CSharpExpression.ParseFunc <float>("24f"), CSharpExpression.ParseFunc <float>("25F"), CSharpExpression.ParseFunc <float>("26.01F"), CSharpExpression.ParseFunc <float>("-27.01F"), CSharpExpression.ParseFunc <string>("\"a\""), CSharpExpression.ParseFunc <char>("'b'"), CSharpExpression.ParseFunc <bool>("true"), CSharpExpression.ParseFunc <bool>("false"), CSharpExpression.ParseFunc <object>("null"), CSharpExpression.ParseFunc <Type>("typeof(Int32)"), CSharpExpression.ParseFunc <Type>("typeof(short)"), CSharpExpression.ParseFunc <Type>("typeof(Math)"), // Convert CSharpExpression.ParseFunc <byte>("unchecked((byte)(2147483647 * 2))"), // ConvertChecked CSharpExpression.ParseFunc <byte>("checked((byte)(4 * 2))"), // Divide CSharpExpression.ParseFunc <int>("2 / 2"), CSharpExpression.ParseFunc <int>("(SByte)2 / (SByte)2"), // Equal CSharpExpression.ParseFunc <bool>("2 == 2"), CSharpExpression.ParseFunc <bool>("(SByte)2 == (SByte)2"), // ExclusiveOr CSharpExpression.ParseFunc <int>("2 ^ 2"), // GreaterThan CSharpExpression.ParseFunc <bool>("2 > 2"), CSharpExpression.ParseFunc <bool>("(SByte)2 > (SByte)2"), // GreaterThanOrEqual CSharpExpression.ParseFunc <bool>("2 >= 2"), CSharpExpression.ParseFunc <bool>("(SByte)2 >= (SByte)2"), // Invoke CSharpExpression.ParseFunc <Func <int, int>, int>("arg1(2)", arg1Name: "arg1"), // Lambda CSharpExpression.ParseFunc <Func <Type, object, bool> >("new Func<Type, object, bool>((t, c) => t != null)", TypeResolver), // LeftShift CSharpExpression.ParseFunc <int>("(SByte)2 << 2"), CSharpExpression.ParseFunc <int>("2 << 2"), // LessThan CSharpExpression.ParseFunc <bool>("(SByte)2 < (SByte)2"), CSharpExpression.ParseFunc <bool>("2 < 2"), // LessThanOrEqual CSharpExpression.ParseFunc <bool>("(SByte)2 <= (SByte)2"), CSharpExpression.ParseFunc <bool>("2 <= 2"), // TODO ListInit //(Expression<Func<List<int>>>)(() => new List<int> { 1, 2, 3, 4 }), // MemberAccess CSharpExpression.ParseFunc <object>("ExecutorTests.TestGenericClass<int>.Field", TypeResolver), CSharpExpression.ParseFunc <object>("ExecutorTests.TestGenericClass<int>.Property", TypeResolver), CSharpExpression.ParseFunc <object>("new GameDevWare.Dynamic.Expressions.Tests.ExecutorTests.TestGenericClass<int>.TestSubClass<int,int>().Field1", TypeResolver), CSharpExpression.ParseFunc <object>("new GameDevWare.Dynamic.Expressions.Tests.ExecutorTests.TestGenericClass<int>.TestSubClass<int,int>().Property1", TypeResolver), CSharpExpression.ParseFunc <double>("Math.E"), // TODO MemberInit //(Expression<Func<ExecutorTests.TestClass>>)(() => new ExecutorTests.TestClass //{ // IntField = 25, // IntProperty = 10, // TestClassField = new ExecutorTests.TestClass { { 1, 2 } }, // ListField = { 2, 3 }, // ListProperty = { 4, 5 } //}), // Modulo CSharpExpression.ParseFunc <int>("5 % 2"), CSharpExpression.ParseFunc <int>("(SByte)5 % (SByte)2"), // Multiply CSharpExpression.ParseFunc <int>("checked(2 * 2)"), CSharpExpression.ParseFunc <int>("checked((SByte)2 * (SByte)2)"), // MultiplyChecked CSharpExpression.ParseFunc <int>("unchecked(2 * 2)"), CSharpExpression.ParseFunc <int>("unchecked((SByte)2 * (SByte)2)"), // NegateChecked CSharpExpression.ParseFunc <int>("checked(-(101))"), // Negate CSharpExpression.ParseFunc <int>("unchecked(-(100))"), // UnaryPlus CSharpExpression.ParseFunc <int>("+(1)"), // New CSharpExpression.ParseFunc <object>("new ExecutorTests.TestGenericClass<int>()", TypeResolver), CSharpExpression.ParseFunc <object>("new GameDevWare.Dynamic.Expressions.Tests.ExecutorTests.TestGenericClass<int>.TestSubClass<int,int>()", TypeResolver), CSharpExpression.ParseFunc <object>("new GameDevWare.Dynamic.Expressions.Tests.ExecutorTests.TestGenericClass<int>.TestSubClass<int,int>()", TypeResolver), // TODO NewArrayInit //(Expression<Func<int[]>>)(() => new int[] { 1, 2, 3, 4 }), // NewArrayBounds (Expression <Func <int[]> >)(() => new int[8]), // Not CSharpExpression.ParseFunc <bool>("!true"), CSharpExpression.ParseFunc <bool>("!false"), // NotEqual CSharpExpression.ParseFunc <bool>("2 != 2"), CSharpExpression.ParseFunc <bool>("(SByte)2 != (SByte)2"), // Or CSharpExpression.ParseFunc <int>("(SByte)2 | (SByte)2"), CSharpExpression.ParseFunc <int>("2 | 2"), // OrElse CSharpExpression.ParseFunc <bool>("true || false"), // Parameter CSharpExpression.ParseFunc <int, int>("arg1", arg1Name: "arg1"), // Power CSharpExpression.ParseFunc <int>("2 ** 2"), CSharpExpression.ParseFunc <sbyte>("(SByte)2 ** (SByte)2"), CSharpExpression.ParseFunc <float>("2f ** 2f"), CSharpExpression.ParseFunc <double>("2d ** 2d"), // Quote // TODO Quote //(Expression<Func<Expression<Func<int>>>>)(() => (() => 1)), // RightShift CSharpExpression.ParseFunc <int>("(SByte)2 >> 2"), CSharpExpression.ParseFunc <int>("2 >> 2"), // Subtract CSharpExpression.ParseFunc <int>("unchecked((SByte)2 - (SByte)2)"), CSharpExpression.ParseFunc <int>("unchecked(2 - 2)"), CSharpExpression.ParseFunc <int>("unchecked(-(SByte)127 - (SByte)10)"), // SubtractChecked CSharpExpression.ParseFunc <int>("checked((SByte)2 - (SByte)2)"), CSharpExpression.ParseFunc <int>("checked(2 - 2)"), CSharpExpression.ParseFunc <int>("checked(-(SByte)127 - (SByte)10)"), // TypeAs CSharpExpression.ParseFunc <string>("'a' as String"), CSharpExpression.ParseFunc <string>("\"a\" as System.String"), CSharpExpression.ParseFunc <string>("1 as string"), // TypeIs CSharpExpression.ParseFunc <bool>("1 is Int32"), CSharpExpression.ParseFunc <bool>("1 is Int16"), // Default CSharpExpression.ParseFunc <int>("default(System.Int32)"), CSharpExpression.ParseFunc <string>("default(String)"), // Index CSharpExpression.ParseFunc <int[], int>("arg1[0]", arg1Name: "arg1"), CSharpExpression.ParseFunc <int[], int?>("(default(int[]))?[0]", arg1Name: "arg1"), // OnesComplement CSharpExpression.ParseFunc <int>("checked(~1203)"), // Other CSharpExpression.ParseFunc <int>("2 * 2 + 3"), CSharpExpression.ParseFunc <int>("2 + 2 * 3"), CSharpExpression.ParseFunc <int>("2 + 2 * 3"), CSharpExpression.ParseFunc <int>("2 + 4 / 2"), CSharpExpression.ParseFunc <int>("2 * (2 + 3) << 1 - 1"), CSharpExpression.ParseFunc <int>("2 * (2 + 3) << 1 + 1 ^ 7"), CSharpExpression.ParseFunc <int>("2 * (2 + 3) << 1 + 1 & 7 | 25 ^ 10"), CSharpExpression.ParseFunc <double>("(2 * (2 + 3) << 1 - 1 & 7 | 25 ^ 10) + System.Int32.Parse(\"10\")"), CSharpExpression.ParseFunc <double>("(2 * (2 + 3) << 1 - 1 & 7 | 25 ^ 10) + System.Int32.Parse(\"10\") + Math.Pow(100, 1)"), CSharpExpression.ParseFunc <double>("(2 * (2 + 3) << 1 - 1 & 7 | 25 ^ 10) + System.Int32.Parse(\"10\") + Math.Pow(100, 1) + Math.E"), CSharpExpression.ParseFunc <double>("10 * (1 / (double)(1 * 1))"), CSharpExpression.ParseFunc <double>("10 * (1 / (double)(1 * 1))"), CSharpExpression.ParseFunc <int>("1 != 1 || 1 == 1 ? 1 : 2"), CSharpExpression.ParseFunc <int>("1 < 2 && 3 >= 2 ? 1 : 2"), CSharpExpression.ParseFunc <int>("unchecked(2147483647 + 2)"), CSharpExpression.ParseFunc <int>("unchecked(-2147483646 - 10)"), CSharpExpression.ParseFunc <int>("unchecked(2147483647 * 2)"), CSharpExpression.ParseFunc <int>("unchecked((int)(Byte)-1000)"), CSharpExpression.ParseFunc <decimal>("unchecked((Decimal)(Byte)-1000)"), CSharpExpression.ParseFunc <object>("new ExecutorTests.TestGenericClass<int>().InstanceMethod(10)", TypeResolver), CSharpExpression.ParseFunc <object>("new ExecutorTests.TestGenericClass<int>().InstanceGenericMethod<int>(11)", TypeResolver), CSharpExpression.ParseFunc <object>("ExecutorTests.TestGenericClass<int>.StaticGenericMethod<int>(12)", TypeResolver), CSharpExpression.ParseFunc <object>("ExecutorTests.TestGenericClass<int>.StaticMethod()", TypeResolver), CSharpExpression.ParseFunc <object>("new GameDevWare.Dynamic.Expressions.Tests.ExecutorTests.TestGenericClass<int>.TestSubClass<int,int>().InstanceMethod1()", TypeResolver), CSharpExpression.ParseFunc <object>("new GameDevWare.Dynamic.Expressions.Tests.ExecutorTests.TestGenericClass<int>.TestSubClass<int,int>().InstanceGenericMethod1<int>(1,2,3,4)", TypeResolver), CSharpExpression.ParseFunc <object>("GameDevWare.Dynamic.Expressions.Tests.ExecutorTests.TestGenericClass<int>.TestSubClass<int,int>.StaticGenericMethod1<int>(13)", TypeResolver), CSharpExpression.ParseFunc <object>("GameDevWare.Dynamic.Expressions.Tests.ExecutorTests.TestGenericClass<int>.TestSubClass<int,int>.StaticMethod1(14)", TypeResolver), }; return(from expression in expressions let arguments = GetLambdaArguments((LambdaExpression)expression) select new object[] { expression } ); }
[Ignore] // BUG: Lowered form of ArrayAccess produces a Block which doesn't get passed by ref correctly. public void ArrayAccess_ByRef() { var xs = Expression.Parameter(typeof(int[])); var i = Expression.Parameter(typeof(Index)); var inc = typeof(Interlocked).GetMethod(nameof(Interlocked.Increment), new[] { typeof(int).MakeByRefType() }); var res = Expression.Lambda <Func <int[], Index, int> >(Expression.Call(inc, CSharpExpression.ArrayAccess(xs, i)), xs, i); var f = res.Compile(); var vals = new int[] { 41 }; int val = f(vals, 0); Assert.AreEqual(42, val); Assert.AreEqual(42, vals[0]); // // BUG: Lowering of ArrayAccess results in a BlockExpression (a "comma"), but Expression.Call does not account for taking // a reference to the final expression. Instead, we end up with a reference to a temporary (and not even a write-back // because Block is read-only). // // To fix this, we'd need to rewrite the MethodCallExpression (or other expressions that support by-ref parameters) by // lifting the lowered form of ArrayAccess up. E.g. // // Interlocked.Exchange(ref xs[i]) // // becomes // // Interlocked.Exchange(ref { // var __arr = xs; // var __idx = i; // __arr[__idx] // }) // // without such a fix, but should be rearranged by spilling all arguments to the MethodCallExpression to locals in a // new surrounding block, e.g. // // { // var __arr = xs; // var __idx = i; // Interlocked.Exchange(__arr[__idx]) // } // // To achieve this, we need a reducible node higher up, which would require us to venture into CSharpExpression.Lambda // when this library is referenced, such that the top-level C# lambda can be reduced into a regular LambdaExpression, // while performing rewrites as the one shown above. We already do so for async lambdas, but this may be a compatibility // concern for synchronous lambdas (also, the type is different). // // An alternative would be to properly support ref locals in BlockExpression. // }
public void ForEach_Update() { var variable = Expression.Parameter(typeof(int)); var collection = Expression.Constant(new int[] { 2, 3, 5 }); var body = Expression.Empty(); var breakLabel = Expression.Label(); var continueLabel = Expression.Label(); var x = Expression.Parameter(variable.Type); var conversion = Expression.Lambda(x, x); var res = CSharpExpression.ForEach(variable, collection, body, breakLabel, continueLabel, conversion); Assert.AreSame(res, res.Update(res.BreakLabel, res.ContinueLabel, res.Variable, res.Collection, res.Conversion, res.Body)); var newVariable = Expression.Parameter(typeof(int)); var newCollection = Expression.Constant(new int[] { 2, 3, 5 }); var newBody = Expression.Empty(); var newBreakLabel = Expression.Label(); var newContinueLabel = Expression.Label(); var newConversion = Expression.Lambda(x, x); var upd1 = res.Update(newBreakLabel, res.ContinueLabel, res.Variable, res.Collection, res.Conversion, res.Body); var upd2 = res.Update(res.BreakLabel, newContinueLabel, res.Variable, res.Collection, res.Conversion, res.Body); var upd3 = res.Update(res.BreakLabel, res.ContinueLabel, newVariable, res.Collection, res.Conversion, res.Body); var upd4 = res.Update(res.BreakLabel, res.ContinueLabel, res.Variable, newCollection, res.Conversion, res.Body); var upd5 = res.Update(res.BreakLabel, res.ContinueLabel, res.Variable, res.Collection, newConversion, res.Body); var upd6 = res.Update(res.BreakLabel, res.ContinueLabel, res.Variable, res.Collection, res.Conversion, newBody); Assert.AreSame(newBreakLabel, upd1.BreakLabel); Assert.AreSame(res.ContinueLabel, upd1.ContinueLabel); Assert.AreSame(res.Variable, upd1.Variable); Assert.AreSame(res.Collection, upd1.Collection); Assert.AreSame(res.Conversion, upd1.Conversion); Assert.AreSame(res.Body, upd1.Body); Assert.AreSame(res.BreakLabel, upd2.BreakLabel); Assert.AreSame(newContinueLabel, upd2.ContinueLabel); Assert.AreSame(res.Variable, upd2.Variable); Assert.AreSame(res.Collection, upd2.Collection); Assert.AreSame(res.Conversion, upd2.Conversion); Assert.AreSame(res.Body, upd2.Body); Assert.AreSame(res.BreakLabel, upd3.BreakLabel); Assert.AreSame(res.ContinueLabel, upd3.ContinueLabel); Assert.AreSame(newVariable, upd3.Variable); Assert.AreSame(res.Collection, upd3.Collection); Assert.AreSame(res.Conversion, upd3.Conversion); Assert.AreSame(res.Body, upd3.Body); Assert.AreSame(res.BreakLabel, upd4.BreakLabel); Assert.AreSame(res.ContinueLabel, upd4.ContinueLabel); Assert.AreSame(res.Variable, upd4.Variable); Assert.AreSame(newCollection, upd4.Collection); Assert.AreSame(res.Conversion, upd4.Conversion); Assert.AreSame(res.Body, upd4.Body); Assert.AreSame(res.BreakLabel, upd5.BreakLabel); Assert.AreSame(res.ContinueLabel, upd5.ContinueLabel); Assert.AreSame(res.Variable, upd5.Variable); Assert.AreSame(res.Collection, upd5.Collection); Assert.AreSame(newConversion, upd5.Conversion); Assert.AreSame(res.Body, upd5.Body); Assert.AreSame(res.BreakLabel, upd6.BreakLabel); Assert.AreSame(res.ContinueLabel, upd6.ContinueLabel); Assert.AreSame(res.Variable, upd6.Variable); Assert.AreSame(res.Collection, upd6.Collection); Assert.AreSame(res.Conversion, upd6.Conversion); Assert.AreSame(newBody, upd6.Body); }
public void ArrayAccess_Read_FromEnd() { var xs = Expression.Parameter(typeof(string[])); var i = Expression.Parameter(typeof(int)); var res = Expression.Lambda <Func <string[], int, string> >(CSharpExpression.ArrayAccess(xs, CSharpExpression.FromEndIndex(i)), xs, i); var f = res.Compile(); var vals = new string[] { "bar", "foo", "qux" }; Assert.AreEqual(vals[0], f(vals, 3)); Assert.AreEqual(vals[1], f(vals, 2)); Assert.AreEqual(vals[2], f(vals, 1)); }
public void ArrayAccess_Assign_FromEnd() { var xs = Expression.Parameter(typeof(string[])); var i = Expression.Parameter(typeof(int)); var s = Expression.Parameter(typeof(string)); var res = Expression.Lambda <Func <string[], int, string, string> >(CSharpExpression.Assign(CSharpExpression.ArrayAccess(xs, CSharpExpression.FromEndIndex(i)), s), xs, i, s); var f = res.Compile(); var vals = new string[] { "bar", "foo", "qux" }; for (int j = 1; j <= vals.Length; j++) { var k = Index.FromEnd(j); var newVal = vals[k].ToUpper(); var assignRes = f(vals, j, newVal); Assert.AreEqual(newVal, assignRes); Assert.AreEqual(newVal, vals[k]); } }
public void ArrayAccess_UnaryAssign_Pre_SystemIndex() { var xs = Expression.Parameter(typeof(int[])); var i = Expression.Parameter(typeof(Index)); var res = Expression.Lambda <Func <int[], Index, int> >(CSharpExpression.PreIncrementAssign(CSharpExpression.ArrayAccess(xs, i)), xs, i); var f = res.Compile(); var vals = new int[] { 2, 3, 5, 7 }; for (int j = 0; j < vals.Length; j++) { var newVal = vals[j] + 1; var assignRes = f(vals, new Index(j)); Assert.AreEqual(newVal, assignRes); Assert.AreEqual(newVal, vals[j]); } for (int j = 1; j <= vals.Length; j++) { var k = new Index(j, fromEnd: true); var newVal = vals[k] + 1; var assignRes = f(vals, k); Assert.AreEqual(newVal, assignRes); Assert.AreEqual(newVal, vals[k]); } }
public void ArrayAccess_Assign_SystemIndex() { var xs = Expression.Parameter(typeof(string[])); var i = Expression.Parameter(typeof(Index)); var s = Expression.Parameter(typeof(string)); var res = Expression.Lambda <Func <string[], Index, string, string> >(CSharpExpression.Assign(CSharpExpression.ArrayAccess(xs, i), s), xs, i, s); var f = res.Compile(); var vals = new string[] { "bar", "foo", "qux" }; for (int j = 0; j < vals.Length; j++) { var newVal = vals[j].ToUpper(); var assignRes = f(vals, new Index(j), newVal); Assert.AreEqual(newVal, assignRes); Assert.AreEqual(newVal, vals[j]); } for (int j = 1; j <= vals.Length; j++) { var k = new Index(j, fromEnd: true); var newVal = vals[k].ToLower(); var assignRes = f(vals, k, newVal); Assert.AreEqual(newVal, assignRes); Assert.AreEqual(newVal, vals[k]); } }
public void ArrayAccess_UnaryAssign_Pre_Int32() { var xs = Expression.Parameter(typeof(int[])); var i = Expression.Parameter(typeof(int)); var res = Expression.Lambda <Func <int[], int, int> >(CSharpExpression.PreIncrementAssign(CSharpExpression.ArrayAccess(xs, i)), xs, i); var f = res.Compile(); var vals = new int[] { 2, 3, 5, 7 }; for (int j = 0; j < vals.Length; j++) { var newVal = vals[j] + 1; var assignRes = f(vals, j); Assert.AreEqual(newVal, assignRes); Assert.AreEqual(newVal, vals[j]); } }
public void AssignBinary_Factory_MakeBinaryAssign() { foreach (var l in GetLhs()) { var r = Expression.Constant(2); var m = MethodInfoOf(() => Op(0, 0)); var x = Expression.Parameter(typeof(int)); var cf = Expression.Lambda(x, x); var cl = Expression.Lambda(x, x); foreach (var n in new[] { CSharpExpressionType.Assign, CSharpExpressionType.AddAssign, CSharpExpressionType.AndAssign, CSharpExpressionType.DivideAssign, CSharpExpressionType.ExclusiveOrAssign, CSharpExpressionType.LeftShiftAssign, CSharpExpressionType.ModuloAssign, CSharpExpressionType.MultiplyAssign, CSharpExpressionType.OrAssign, CSharpExpressionType.RightShiftAssign, CSharpExpressionType.SubtractAssign, CSharpExpressionType.AddAssignChecked, CSharpExpressionType.MultiplyAssignChecked, CSharpExpressionType.SubtractAssignChecked, }) { var a1 = CSharpExpression.MakeBinaryAssign(n, l, r, m, cf, cl); Assert.AreEqual(n, a1.CSharpNodeType); Assert.AreSame(l, a1.Left); Assert.AreSame(r, a1.Right); Assert.AreEqual(typeof(int), a1.Type); Assert.IsFalse(a1.IsLiftedToNull); Assert.IsFalse(a1.IsLifted); if (n == CSharpExpressionType.Assign) { Assert.IsNull(a1.Method); Assert.IsNull(a1.LeftConversion); Assert.IsNull(a1.FinalConversion); } else { Assert.AreSame(m, a1.Method); Assert.AreSame(cl, a1.LeftConversion); Assert.AreSame(cf, a1.FinalConversion); } var a2 = CSharpExpression.MakeBinaryAssign(n, l, r, m, null, null); Assert.AreEqual(n, a2.CSharpNodeType); Assert.AreSame(l, a2.Left); Assert.AreSame(r, a2.Right); Assert.AreEqual(typeof(int), a2.Type); Assert.IsFalse(a2.IsLiftedToNull); Assert.IsFalse(a2.IsLifted); Assert.IsNull(a2.LeftConversion); Assert.IsNull(a2.FinalConversion); if (n == CSharpExpressionType.Assign) { Assert.IsNull(a2.Method); } else { Assert.AreSame(m, a2.Method); } var a3 = CSharpExpression.MakeBinaryAssign(n, l, r, null, null, null); Assert.AreEqual(n, a3.CSharpNodeType); Assert.AreSame(l, a3.Left); Assert.AreSame(r, a3.Right); Assert.AreEqual(typeof(int), a3.Type); Assert.IsFalse(a3.IsLiftedToNull); Assert.IsFalse(a3.IsLifted); Assert.IsNull(a3.Method); Assert.IsNull(a3.LeftConversion); Assert.IsNull(a3.FinalConversion); } } }
public void ArrayAccess_ByRef_CSharpNodes_SystemIndex() { // // NB: Unlike the test case above, this works because we can reduce CSharpExpression variants of MethodCall, New, and Invoke // while properly accounting for by-ref passing of ArrayAccess. // // The corresponding changes to the Roslyn compiler account for by-ref passing of ArrayAccess nodes that involve an Index // operand, causing calls to be made to CSharpExpression.* factories for Call, New, and Invoke. E.g. // // Interlocked.Exchange(ref xs[i]) // // where i is of type Index, becomes // // CSharpExpression.Call(xchg, CSharpExpression.ArrayAccess(...)) // // rather than // // Expression.Call(xchg, CSharpExpression.ArrayAccess(...)) // // This triggers custom reduction logic in the C# variants of Call, New, and Invoke nodes. // // However, this does not fix the previous test case where one explicitly uses Expression.Call. For this to be fixed, we // either need: // // 1. Guaranteed custom reduction at a higher node (e.g. lambda). // 2. Changes to ref semantics in System.Linq.Expressions, e.g. allowing to peek into a comma node. // 3. Changes to Reduce logic in System.Linq.Expressions, e.g. custom logic for lval reduction versus rval reduction. // 4. Push down Index/Range support to IndexExpression and piggyback on its by-ref support. // var xs = Expression.Parameter(typeof(int[])); var i = Expression.Parameter(typeof(Index)); var inc = typeof(Interlocked).GetMethod(nameof(Interlocked.Increment), new[] { typeof(int).MakeByRefType() }); MethodCallCSharpExpression mce = CSharpExpression.Call(inc, new Expression[] { CSharpExpression.ArrayAccess(xs, i) }); var res = Expression.Lambda <Func <int[], Index, int> >(mce, xs, i); var f = res.Compile(); var vals = new int[] { 41 }; int val = f(vals, 0); Assert.AreEqual(42, val); Assert.AreEqual(42, vals[0]); }
public void AssignBinary_Factory_MultiplyAssignChecked() { var a = Expression.Parameter(typeof(int)); var b = Expression.Constant(1); var x = Expression.Parameter(typeof(int)); var dl = Expression.Lambda(x, x); var df = Expression.Lambda(x, x); foreach (var l in GetLhs()) { var r = Expression.Constant(2); var m = MethodInfoOf(() => Op(0, 0)); var cl = Expression.Lambda(x, x); var cf = Expression.Lambda(x, x); var a1 = CSharpExpression.MultiplyAssignChecked(l, r); Assert.AreSame(l, a1.Left); Assert.AreSame(r, a1.Right); Assert.IsNull(a1.Method); Assert.IsNull(a1.LeftConversion); Assert.IsNull(a1.FinalConversion); var a2 = CSharpExpression.MultiplyAssignChecked(l, r, m); Assert.AreSame(l, a2.Left); Assert.AreSame(r, a2.Right); Assert.AreSame(m, a2.Method); Assert.IsNull(a2.LeftConversion); Assert.IsNull(a2.FinalConversion); var a3 = CSharpExpression.MultiplyAssignChecked(l, r, m, cf); Assert.AreSame(l, a3.Left); Assert.AreSame(r, a3.Right); Assert.AreSame(m, a3.Method); Assert.AreSame(cf, a3.FinalConversion); Assert.IsNull(a3.LeftConversion); var a4 = CSharpExpression.MultiplyAssignChecked(l, r, m, cf, cl); Assert.AreSame(l, a4.Left); Assert.AreSame(r, a4.Right); Assert.AreSame(m, a4.Method); Assert.AreSame(cf, a4.FinalConversion); Assert.AreSame(cl, a4.LeftConversion); var a5 = a4.Update(l, cl, r, cf); Assert.AreSame(a5, a4); var a6 = a4.Update(a, cl, r, cf); Assert.AreSame(a, a6.Left); Assert.AreSame(r, a6.Right); Assert.AreSame(m, a6.Method); Assert.AreSame(cf, a6.FinalConversion); Assert.AreSame(cl, a6.LeftConversion); var a7 = a4.Update(l, dl, r, cf); Assert.AreSame(l, a7.Left); Assert.AreSame(r, a7.Right); Assert.AreSame(m, a7.Method); Assert.AreSame(dl, a7.LeftConversion); Assert.AreSame(cf, a7.FinalConversion); var a8 = a4.Update(l, cl, b, cf); Assert.AreSame(l, a8.Left); Assert.AreSame(b, a8.Right); Assert.AreSame(m, a8.Method); Assert.AreSame(cl, a8.LeftConversion); Assert.AreSame(cf, a8.FinalConversion); var a9 = a4.Update(l, cl, r, df); Assert.AreSame(l, a9.Left); Assert.AreSame(r, a9.Right); Assert.AreSame(m, a9.Method); Assert.AreSame(cl, a9.LeftConversion); Assert.AreSame(df, a9.FinalConversion); } }
public void ForEach_Properties() { var variable = Expression.Parameter(typeof(int)); var collection = Expression.Constant(new int[] { 2, 3, 5 }); var body = Expression.Empty(); var breakLabel = Expression.Label(); var continueLabel = Expression.Label(); var x = Expression.Parameter(variable.Type); var conversion = Expression.Lambda(x, x); { var res = CSharpExpression.ForEach(variable, collection, body); Assert.AreEqual(CSharpExpressionType.ForEach, res.CSharpNodeType); Assert.AreEqual(typeof(void), res.Type); Assert.AreSame(variable, res.Variable); Assert.AreSame(collection, res.Collection); Assert.AreSame(body, res.Body); Assert.IsNull(res.BreakLabel); Assert.IsNull(res.ContinueLabel); Assert.IsNull(res.Conversion); } { var res = CSharpExpression.ForEach(variable, collection, body, breakLabel); Assert.AreEqual(CSharpExpressionType.ForEach, res.CSharpNodeType); Assert.AreEqual(typeof(void), res.Type); Assert.AreSame(variable, res.Variable); Assert.AreSame(collection, res.Collection); Assert.AreSame(body, res.Body); Assert.AreSame(breakLabel, res.BreakLabel); Assert.IsNull(res.ContinueLabel); Assert.IsNull(res.Conversion); } { var res = CSharpExpression.ForEach(variable, collection, body, breakLabel, continueLabel); Assert.AreEqual(CSharpExpressionType.ForEach, res.CSharpNodeType); Assert.AreEqual(typeof(void), res.Type); Assert.AreSame(variable, res.Variable); Assert.AreSame(collection, res.Collection); Assert.AreSame(body, res.Body); Assert.AreSame(breakLabel, res.BreakLabel); Assert.AreSame(continueLabel, res.ContinueLabel); Assert.IsNull(res.Conversion); } { var res = CSharpExpression.ForEach(variable, collection, body, breakLabel, continueLabel, conversion); Assert.AreEqual(CSharpExpressionType.ForEach, res.CSharpNodeType); Assert.AreEqual(typeof(void), res.Type); Assert.AreSame(variable, res.Variable); Assert.AreSame(collection, res.Collection); Assert.AreSame(body, res.Body); Assert.AreSame(breakLabel, res.BreakLabel); Assert.AreSame(continueLabel, res.ContinueLabel); Assert.AreSame(conversion, res.Conversion); } }