public void AssignBinary_CustomMethod() { var p = Expression.Parameter(typeof(byte)); var m = typeof(AssignBinaryTests).GetMethod(nameof(ByteOp), BindingFlags.NonPublic | BindingFlags.Static); var f = Expression.Lambda <Func <byte, byte> >(CSharpExpression.AddAssign(p, Expression.Constant((byte)1, typeof(byte)), m), p).Compile(); Assert.AreEqual((byte)40, f(41)); }
public void AssignBinary_MutableStruct_Index() { var p = Expression.Parameter(typeof(MutableStruct <int>)); var f = Expression.MakeIndex(p, p.Type.GetProperty("Item"), new[] { Expression.Constant(0) }); var a = CSharpExpression.AddAssign(f, Expression.Constant(1)); var b = Expression.Call(typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }), Expression.Convert(a, typeof(object)), Expression.Convert(f, typeof(object))); var l = Expression.Lambda <Func <MutableStruct <int>, string> >(b, p); var c = l.Compile(); var m = new MutableStruct <int>(); var r = c(m); Assert.AreEqual("11", r); }
public void AssignBinary_Factory_String_ArgumentChecking() { var s = Expression.Parameter(typeof(string)); AssertEx.Throws <ArgumentException>(() => CSharpExpression.SubtractAssign(s, Expression.Default(typeof(string)))); AssertEx.Throws <ArgumentException>(() => CSharpExpression.SubtractAssign(s, Expression.Default(typeof(object)))); // the following are valid Assert.IsNotNull(CSharpExpression.AddAssign(s, Expression.Default(typeof(string)))); Assert.IsNotNull(CSharpExpression.AddAssign(s, Expression.Default(typeof(int)))); Assert.IsNotNull(CSharpExpression.AddAssign(s, Expression.Default(typeof(object)))); Assert.IsNotNull(CSharpExpression.AddAssignChecked(s, Expression.Default(typeof(string)))); Assert.IsNotNull(CSharpExpression.AddAssignChecked(s, Expression.Default(typeof(int)))); Assert.IsNotNull(CSharpExpression.AddAssignChecked(s, Expression.Default(typeof(object)))); }
public void AssignBinary_Parameter_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 x = Expression.Parameter(t); var y = Expression.Parameter(t); var val = Expression.Convert(Expression.Constant(41), t); var one = Expression.Convert(Expression.Constant(1), t); return (Expression.Block( new[] { x, y }, Expression.Assign(x, val), Expression.Assign(y, CSharpExpression.AddAssign(x, Expression.Block(log("V"), one))), Expression.Invoke(append, Expression.Call(x, toString)), Expression.Invoke(append, Expression.Call(y, toString)) )); }, new LogAndResult <object> { Log = { "V", exp, exp } }); } }
public void AssignBinary_CustomConverts() { var p = Expression.Parameter(typeof(byte)); // (byte lhs) => (int)(lhs * 2) var x = Expression.Parameter(typeof(byte)); var c = Expression.Lambda(Expression.Multiply(Expression.Convert(x, typeof(int)), Expression.Constant(2)), x); // (int res) => (byte)(res / 3) var y = Expression.Parameter(typeof(int)); var d = Expression.Lambda(Expression.Convert(Expression.Divide(y, Expression.Constant(3)), typeof(byte)), y); // (int lhs) => lhs + 1 var f = Expression.Lambda <Func <byte, byte> >(CSharpExpression.AddAssign(p, Expression.Constant(1, typeof(int)), null, d, c), p).Compile(); Assert.AreEqual((byte)7, f(10)); }
public void ArrayAccess_CompoundAssign_Int32() { var xs = Expression.Parameter(typeof(int[])); var i = Expression.Parameter(typeof(int)); var res = Expression.Lambda <Func <int[], int, int> >(CSharpExpression.AddAssign(CSharpExpression.ArrayAccess(xs, i), Expression.Constant(1)), 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 ArrayAccess_CompoundAssign_SideEffects() { AssertCompile((log, append) => { var array = Expression.Block(log("A"), Expression.Constant(new[] { 42 })); var index = Expression.Block(log("I"), Expression.Constant(0)); var val = Expression.Block(log("V"), Expression.Constant(43)); return(CSharpExpression.AddAssign(CSharpExpression.ArrayAccess(array, index), val)); }, new LogAndResult <object> { Log = { "A", "I", "V" } }); AssertCompile((log, append) => { var array = Expression.Block(log("A"), Expression.Constant(new[] { 42 })); var index = Expression.Block(log("I"), Expression.Constant(new Index(0))); var val = Expression.Block(log("V"), Expression.Constant(43)); return(CSharpExpression.AddAssign(CSharpExpression.ArrayAccess(array, index), val)); }, new LogAndResult <object> { Log = { "A", "I", "V" } }); AssertCompile((log, append) => { var array = Expression.Block(log("A"), Expression.Constant(new[, ] { { 42 } })); var index1 = Expression.Block(log("I1"), Expression.Constant(0)); var index2 = Expression.Block(log("I2"), Expression.Constant(0)); var val = Expression.Block(log("V"), Expression.Constant(43)); return(CSharpExpression.AddAssign(CSharpExpression.ArrayAccess(array, index1, index2), val)); }, new LogAndResult <object> { Log = { "A", "I1", "I2", "V" } }); }
public void AssignBinary_Factory_Delegate_ArgumentChecking() { // NB: LINQ checks this one AssertEx.Throws <InvalidOperationException>(() => CSharpExpression.AddAssignChecked(Expression.Parameter(typeof(Delegate)), Expression.Default(typeof(Delegate)))); // NB: Our library checks this one (TODO: should we make the exceptions consistent?) AssertEx.Throws <ArgumentException>(() => CSharpExpression.SubtractAssignChecked(Expression.Parameter(typeof(MulticastDelegate)), Expression.Default(typeof(MulticastDelegate)))); var d = Expression.Parameter(typeof(Action <string>)); AssertEx.Throws <ArgumentException>(() => CSharpExpression.AddAssignChecked(d, Expression.Default(typeof(Action)))); AssertEx.Throws <ArgumentException>(() => CSharpExpression.SubtractAssign(d, Expression.Default(typeof(Action <int>)))); AssertEx.Throws <ArgumentException>(() => CSharpExpression.DivideAssign(d, Expression.Default(typeof(Action <string>)))); // the following are valid Assert.IsNotNull(CSharpExpression.AddAssign(d, Expression.Default(typeof(Action <string>)))); Assert.IsNotNull(CSharpExpression.AddAssign(d, Expression.Default(typeof(Action <object>)))); Assert.IsNotNull(CSharpExpression.AddAssignChecked(d, Expression.Default(typeof(Action <string>)))); Assert.IsNotNull(CSharpExpression.AddAssignChecked(d, Expression.Default(typeof(Action <object>)))); Assert.IsNotNull(CSharpExpression.SubtractAssign(d, Expression.Default(typeof(Action <string>)))); Assert.IsNotNull(CSharpExpression.SubtractAssign(d, Expression.Default(typeof(Action <object>)))); Assert.IsNotNull(CSharpExpression.SubtractAssignChecked(d, Expression.Default(typeof(Action <string>)))); Assert.IsNotNull(CSharpExpression.SubtractAssignChecked(d, Expression.Default(typeof(Action <object>)))); }
public void AssignBinary_Factory_AddAssign() { 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.AddAssign(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.AddAssign(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.AddAssign(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.AddAssign(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 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 }