public void BottomUpExpressionRewriter_ElementInit() { var log = new StringWriter(); var burs = new BottomUpExpressionRewriter <ArithExpr> { Leaves = { { (ConstantExpression c) => new Const((int)c.Value), c => c.Type == typeof(int), 1 }, }, Rules = { { (int x, int y) => new List <int> { x, 1, y, 2 }, (x, y) => new Add(new Const(3), new Mul(x, y)), 2 }, }, Log = log }; AssertCount(burs.Leaves, 1); AssertCount(burs.Rules, 1); AssertCount(burs.Fallbacks, 0); var e = ((Expression <Func <List <int> > >)(() => new List <int> { 3, 1, 4, 2 })).Body; var a = burs.Rewrite(e); Assert.AreEqual("Add(Const(3), Mul(Const(3), Const(4)))", a.ToString()); }
private static Func <bool, Action <Expression> > GetAsserter <T1, T2, R>(Expression <Func <T1, T2, R> > rule) { var log = new StringWriter(); var burs = new BottomUpExpressionRewriter <NumExpr> { Leaves = { { (Expression e) => Val.Zero, 1 }, }, Rules = { { rule, (x, y) => Val.One, 1 }, }, Log = log }; return(succeed => subject => { if (succeed) { var res = burs.Rewrite(subject); Assert.AreEqual("1", res.ToString()); } else { Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(subject)); } }); }
public void BottomUpExpressionRewriter_MemberBinding3() { var log = new StringWriter(); var burs = new BottomUpExpressionRewriter <NumExpr> { Leaves = { { (ConstantExpression c) => new Val((int)c.Value), c => c.Type == typeof(int), 1 }, }, Rules = { { (int x, int y, int z) => new Summer { Xs ={ x, y, z } }, (x, y, z) => new Plus(new Plus(x, y), z), 2 }, }, Log = log }; AssertCount(burs.Leaves, 1); AssertCount(burs.Rules, 1); AssertCount(burs.Fallbacks, 0); var e1 = ((Expression <Func <Summer> >)(() => new Summer { Xs = { 1, 2, 3 } })).Body; var a1 = burs.Rewrite(e1); Assert.AreEqual("Plus(Plus(1, 2), 3)", a1.ToString()); var e2 = ((Expression <Func <Summer> >)(() => new Summer { })).Body; Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(e2)); var e3 = ((Expression <Func <Summer> >)(() => new Summer { Xs = { 1, 2 } })).Body; Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(e3)); var e4 = ((Expression <Func <Summer> >)(() => new Summer { Xs = { 1, 2, 3, 4 } })).Body; Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(e4)); }
public void BottomUpExpressionRewriter_Simple3() { var log = new StringWriter(); var burs = new BottomUpExpressionRewriter <NumExpr> { Leaves = { { (DefaultExpression d) => Val.Zero, 1 }, { (ConstantExpression c) => new Val((int)c.Value), c => c.Type == typeof(int), 1}, }, Rules = { { () => 1, () => Val.One, 1 }, }, Log = log }; AssertCount(burs.Leaves, 2); AssertCount(burs.Rules, 1); AssertCount(burs.Fallbacks, 0); var e1 = Expression.Default(typeof(int)); var a1 = burs.Rewrite(e1); Assert.AreSame(Val.Zero, a1); Assert.AreEqual("0", a1.ToString()); var e2 = Expression.Constant(0, typeof(int)); var a2 = burs.Rewrite(e2); Assert.AreNotSame(Val.Zero, a2); Assert.AreEqual("0", a2.ToString()); var e3 = Expression.Constant(1, typeof(int)); var a3 = burs.Rewrite(e3); Assert.AreSame(Val.One, a3); Assert.AreEqual("1", a3.ToString()); var e4 = Expression.Constant(2, typeof(int)); var a4 = burs.Rewrite(e4); Assert.AreEqual("2", a4.ToString()); }
public void BottomUpExpressionRewriter_Simple4() { var log = new StringWriter(); var burs = new BottomUpExpressionRewriter <ArithExpr> { Leaves = { { (ConstantExpression c) => new Const((int)c.Value), c => c.Type == typeof(int), 1 }, }, Rules = { { (int x, int y) => x + y, (x, y) => new Add(x, y), 2 }, { (int x, int y) => x * y, (x, y) => new Mul(x, y), 3 }, }, Fallbacks = { { (Expression e) => new Lazy(e.Funcletize <int>()), 9 }, }, Log = log }; AssertCount(burs.Leaves, 1); AssertCount(burs.Rules, 2); AssertCount(burs.Fallbacks, 1); var e1 = Expression.Add( Expression.Multiply( Expression.Constant(1), Expression.Constant(2) ), Expression.Modulo( Expression.Constant(3), Expression.Constant(4) ) ); var a1 = burs.Rewrite(e1); Assert.AreEqual("Add(Mul(Const(1), Const(2)), Lazy(() => (3 % 4)))", a1.ToString()); }
public void BottomUpExpressionRewriter_MemberBinding2() { var log = new StringWriter(); var burs = new BottomUpExpressionRewriter <NumExpr> { Leaves = { { (ConstantExpression c) => new Val((int)c.Value), c => c.Type == typeof(int), 1 }, }, Rules = { { (int x, int y, int z) => new MullerAdder { M ={ x = x, Y = y },z = z }, (x, y, z) => new TimesPlus(x, y, z), 2 }, }, Log = log }; AssertCount(burs.Leaves, 1); AssertCount(burs.Rules, 1); AssertCount(burs.Fallbacks, 0); var e1 = ((Expression <Func <MullerAdder> >)(() => new MullerAdder { M = { x = 2, Y = 3 }, z = 4 })).Body; var a1 = burs.Rewrite(e1); Assert.AreEqual("TimesPlus(2, 3, 4)", a1.ToString()); var e2 = ((Expression <Func <MullerAdder> >)(() => new MullerAdder { z = 4, M = { x = 2, Y = 3 } })).Body; Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(e2)); var e3 = ((Expression <Func <MullerAdder> >)(() => new MullerAdder { M = { Y = 3, x = 2 }, z = 4 })).Body; Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(e3)); }
public static void BottomUpExpressionRewriter_MixedTypes() { var log = new StringWriter(); var burs = new BottomUpExpressionRewriter <ArithExpr> { Leaves = { { (ConstantExpression c) => new Const((int)c.Value), c => c.Type == typeof(int), 1 }, { (ConstantExpression c) => new Const(42), c => c.Type == typeof(long), 1 }, }, Rules = { { (int x, int y) => x + y, (x, y) => new Add(x, y), 3 }, { (long x, long y) => x + y, (x, y) => new Mul(x, y), 2 }, }, Log = log }; AssertCount(burs.Leaves, 2); AssertCount(burs.Rules, 2); var e1 = Expression.Add( Expression.Constant(1), Expression.Constant(2) ); var a1 = burs.Rewrite(e1); Assert.AreEqual("Add(Const(1), Const(2))", a1.ToString()); var e2 = Expression.Add( Expression.Constant(1L), Expression.Constant(2L) ); var a2 = burs.Rewrite(e2); Assert.AreEqual("Mul(Const(42), Const(42))", a2.ToString()); }
public void BottomUpExpressionRewriter_Simple1() { var log = new StringWriter(); var burs = new BottomUpExpressionRewriter <ArithExpr> { Leaves = { { (ConstantExpression c) => new Const((int)c.Value), c => c.Type == typeof(int), 1 }, }, Rules = { { (int x) => - x, (x) => new Neg(x), 1 }, { (int x) => Math.Abs(x), (x) => new Abs(x), 1 }, { (int x, int y) => x + y, (x, y) => new Add(x, y), 2}, { (int x, int y) => x * y, (x, y) => new Mul(x, y), 3}, }, Log = log }; AssertCount(burs.Leaves, 1); AssertCount(burs.Rules, 4); AssertCount(burs.Fallbacks, 0); var e1 = Expression.Add( Expression.Multiply( Expression.Constant(1), Expression.Call((MethodInfo)ReflectionHelpers.InfoOf((int x) => Math.Abs(x)), Expression.Constant(-2) ) ), Expression.Negate( Expression.Constant(3) ) ); var a1 = burs.Rewrite(e1); Assert.AreEqual("Add(Mul(Const(1), Abs(Const(-2))), Neg(Const(3)))", a1.ToString()); }
public void BottomUpExpressionRewriter_ArgumentChecks() { var burs = new BottomUpExpressionRewriter <ArithExpr>(); #pragma warning disable IDE0034 // Simplify 'default' expression (illustrative of method signature) AssertEx.ThrowsException <ArgumentNullException>(() => burs.Leaves.Add(default(Expression <Func <ConstantExpression, ArithExpr> >), 1), ex => Assert.AreEqual("convert", ex.ParamName)); AssertEx.ThrowsException <ArgumentOutOfRangeException>(() => burs.Leaves.Add((ConstantExpression ce) => new Const(1), -1), ex => Assert.AreEqual("cost", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Leaves.Add(default(Expression <Func <ConstantExpression, ArithExpr> >), _ => true, 1), ex => Assert.AreEqual("convert", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Leaves.Add((ConstantExpression ce) => new Const(1), default(Expression <Func <ConstantExpression, bool> >), 1), ex => Assert.AreEqual("predicate", ex.ParamName)); AssertEx.ThrowsException <ArgumentOutOfRangeException>(() => burs.Leaves.Add((ConstantExpression ce) => new Const(1), _ => true, -1), ex => Assert.AreEqual("cost", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Rules.Add(default(Expression <Func <int> >), () => new Const(1), 1), ex => Assert.AreEqual("pattern", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Rules.Add(default(Expression <Func <int, int> >), (x) => new Const(1), 1), ex => Assert.AreEqual("pattern", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Rules.Add(default(Expression <Func <int, int, int> >), (x, y) => new Const(1), 1), ex => Assert.AreEqual("pattern", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Rules.Add(default(Expression <Func <int, int, int, int> >), (x, y, z) => new Const(1), 1), ex => Assert.AreEqual("pattern", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Rules.Add(default(Expression <Func <int, int, int, int, int> >), (x, y, z, a) => new Const(1), 1), ex => Assert.AreEqual("pattern", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Rules.Add(() => 1, default(Expression <Func <ArithExpr> >), 1), ex => Assert.AreEqual("goal", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Rules.Add((int x) => x + 1, default(Expression <Func <ArithExpr, ArithExpr> >), 1), ex => Assert.AreEqual("goal", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Rules.Add((int x, int y) => x + y + 1, default(Expression <Func <ArithExpr, ArithExpr, ArithExpr> >), 1), ex => Assert.AreEqual("goal", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Rules.Add((int x, int y, int z) => x + y + z + 1, default(Expression <Func <ArithExpr, ArithExpr, ArithExpr, ArithExpr> >), 1), ex => Assert.AreEqual("goal", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Rules.Add((int x, int y, int z, int a) => x + y + z + a + 1, default(Expression <Func <ArithExpr, ArithExpr, ArithExpr, ArithExpr, ArithExpr> >), 1), ex => Assert.AreEqual("goal", ex.ParamName)); AssertEx.ThrowsException <ArgumentOutOfRangeException>(() => burs.Rules.Add(() => 1, () => new Const(1), -1), ex => Assert.AreEqual("cost", ex.ParamName)); AssertEx.ThrowsException <ArgumentOutOfRangeException>(() => burs.Rules.Add((int x) => x + 1, (x) => new Const(1), -1), ex => Assert.AreEqual("cost", ex.ParamName)); AssertEx.ThrowsException <ArgumentOutOfRangeException>(() => burs.Rules.Add((int x, int y) => x + y + 1, (x, y) => new Const(1), -1), ex => Assert.AreEqual("cost", ex.ParamName)); AssertEx.ThrowsException <ArgumentOutOfRangeException>(() => burs.Rules.Add((int x, int y, int z) => x + y + z + 1, (x, y, z) => new Const(1), -1), ex => Assert.AreEqual("cost", ex.ParamName)); AssertEx.ThrowsException <ArgumentOutOfRangeException>(() => burs.Rules.Add((int x, int y, int z, int a) => x + y + z + a + 1, (x, y, z, a) => new Const(1), -1), ex => Assert.AreEqual("cost", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Fallbacks.Add(default(Expression <Func <Expression, ArithExpr> >), 1), ex => Assert.AreEqual("convert", ex.ParamName)); AssertEx.ThrowsException <ArgumentOutOfRangeException>(() => burs.Fallbacks.Add((Expression e) => new Const(1), -1), ex => Assert.AreEqual("cost", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Fallbacks.Add(default(Expression <Func <Expression, ArithExpr> >), _ => true, 1), ex => Assert.AreEqual("convert", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Fallbacks.Add((Expression e) => new Const(1), default(Expression <Func <Expression, bool> >), 1), ex => Assert.AreEqual("predicate", ex.ParamName)); AssertEx.ThrowsException <ArgumentOutOfRangeException>(() => burs.Fallbacks.Add((Expression e) => new Const(1), _ => true, -1), ex => Assert.AreEqual("cost", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => burs.Rewrite(default(Expression)), ex => Assert.AreEqual("expression", ex.ParamName)); #pragma warning restore IDE0034 // Simplify 'default' expression }
public void BottomUpExpressionRewriter_MemberBinding1() { var log = new StringWriter(); var burs = new BottomUpExpressionRewriter <ArithExpr> { Leaves = { { (ConstantExpression c) => new Const((int)c.Value), c => c.Type == typeof(int), 1 }, }, Rules = { { (int x, int y) => new Adder { x = x, Y = y }, (x, y) => new Add(x, y), 2 }, }, Log = log }; AssertCount(burs.Leaves, 1); AssertCount(burs.Rules, 1); AssertCount(burs.Fallbacks, 0); var e1 = ((Expression <Func <Adder> >)(() => new Adder { x = 2, Y = 3 })).Body; var a1 = burs.Rewrite(e1); Assert.AreEqual("Add(Const(2), Const(3))", a1.ToString()); var e2 = ((Expression <Func <Adder> >)(() => new Adder(2) { x = 2, Y = 3 })).Body; Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(e2)); var e3 = ((Expression <Func <Adder> >)(() => new Adder { x = 2 })).Body; Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(e3)); var e4 = ((Expression <Func <Muller> >)(() => new Muller { x = 2, Y = 3 })).Body; Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(e4)); var e5 = ((Expression <Func <Adder> >)(() => new Adder { Y = 3, x = 2 })).Body; // Order matters due to side-effects Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(e5)); var e6 = ((Expression <Func <Adder> >)(() => new Adder { x = 2, Y = 3, z = 4 })).Body; Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(e6)); }
public void BottomUpExpressionRewriter_Simple5() { var log = new StringWriter(); var burs = new BottomUpExpressionRewriter <ArithExpr> { Leaves = { { (ConstantExpression c) => new Const((int)c.Value), c => c.Type == typeof(int), 1 }, }, Rules = { { (int x, int y) => x + y, (x, y) => new Add(x, y), 2 }, { (int x, int y) => x * y, (x, y) => new Mul(x, y), 3 }, { (int a, int b, int c, int d) => a * b + c * d, (a, b, c, d) => new Add(new Mul(c, d), new Mul(a, b)), 7}, }, Fallbacks = { { (Expression e) => new Lazy(e.Funcletize <int>()), e => e.NodeType != ExpressionType.Modulo, 9 }, }, Log = log }; AssertCount(burs.Leaves, 1); AssertCount(burs.Rules, 3); AssertCount(burs.Fallbacks, 1); var e1 = Expression.Add( Expression.Multiply( Expression.Constant(1), Expression.Constant(2) ), Expression.Modulo( Expression.Constant(3), Expression.Constant(4) ) ); Assert.ThrowsException <InvalidOperationException>(() => burs.Rewrite(e1)); var e2 = Expression.Add( Expression.Multiply( Expression.Constant(1), Expression.Constant(2) ), Expression.Divide( Expression.Constant(3), Expression.Constant(4) ) ); var a2 = burs.Rewrite(e2); Assert.AreEqual("Add(Mul(Const(1), Const(2)), Lazy(() => (3 / 4)))", a2.ToString()); var e3 = Expression.Add( Expression.Multiply( Expression.Constant(1), Expression.Constant(2) ), Expression.Multiply( Expression.Constant(3), Expression.Constant(4) ) ); var a3 = burs.Rewrite(e3); Assert.AreEqual("Add(Mul(Const(3), Const(4)), Mul(Const(1), Const(2)))", a3.ToString()); }
public void BottomUpExpressionRewriter_Simple2() { var log = new StringWriter(); var burs = new BottomUpExpressionRewriter <NumExpr> { Leaves = { { (ConstantExpression c) => new Val((int)c.Value), c => c.Type == typeof(int), 1 }, }, Rules = { { (int x) => x + 1, (x) => new Inc(x), 1 }, { (int x) => 1 + x, (x) => new Inc(x), 1 }, { (int x, int y) => x + y, (x, y) => new Plus(x, y), 2}, { (int x, int y) => x * y, (x, y) => new Times(x, y), 3}, { (int x, int y, int z) => x * y + z, (x, y, z) => new TimesPlus(x, y, z), 4}, }, Log = log }; AssertCount(burs.Leaves, 1); AssertCount(burs.Rules, 5); AssertCount(burs.Fallbacks, 0); var e1 = Expression.Add( Expression.Multiply( Expression.Add( Expression.Multiply( Expression.Constant(2), Expression.Constant(3) ), Expression.Constant(1) ), Expression.Multiply( Expression.Constant(4), Expression.Constant(5) ) ), Expression.Constant(6) ); var a1 = burs.Rewrite(e1); Assert.AreEqual("TimesPlus(Inc(Times(2, 3)), Times(4, 5), 6)", a1.ToString()); var e2 = Expression.Add( Expression.Multiply( Expression.Add( Expression.Constant(1), Expression.Multiply( Expression.Constant(2), Expression.Constant(3) ) ), Expression.Multiply( Expression.Constant(4), Expression.Constant(5) ) ), Expression.Constant(6) ); var a2 = burs.Rewrite(e2); Assert.AreEqual("TimesPlus(Inc(Times(2, 3)), Times(4, 5), 6)", a2.ToString()); }