Beispiel #1
0
        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
        }
Beispiel #2
0
        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))));
        }
Beispiel #3
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));
            }
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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 }
                   );
        }
Beispiel #7
0
        [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.
            //
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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));
        }
Beispiel #10
0
        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]);
            }
        }
Beispiel #11
0
        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]);
            }
        }
Beispiel #12
0
        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]);
            }
        }
Beispiel #13
0
        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]);
            }
        }
Beispiel #14
0
        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);
                }
            }
        }
Beispiel #15
0
        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);
            }
        }
Beispiel #17
0
        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);
            }
        }