public void ExponentSimplificationPass(MathExpression input, MathExpression expect, MathExpression[] expectRestrictions, bool allowRestrictions) { var context = OptimizationContext.CreateWith(new DefaultOptimizationSettings { AllowDomainChangingOptimizations = allowRestrictions }, new BuiltinExponentSimplificationPass()); var restrictions = DomainRestrictionSettings.GetDomainRestrictionsFor(context); var actual = context.Optimize(input); Assert.Equal(expect, actual); Assert.Equal(expectRestrictions.Length, restrictions.Count); foreach (var restrict in expectRestrictions) { Assert.Contains(restrict, restrictions); } }
/// <summary> /// Compiles the given expression using the provided context. /// </summary> /// <param name="expr">the <see cref="MathExpression"/> to compile</param> /// <param name="ctx">the context to compile in</param> /// <returns>the compiled <see cref="Expression"/></returns> public override Expression ApplyTo(MathExpression expr, ICompilationContext <TSettings> ctx) { try { if (!IsRootExpression(ctx)) { return(base.ApplyTo(expr, ctx)); } SetRootExpression(ctx); SetTypeHint(ctx, ctx.Settings.ExpectReturn); var subexpr = base.ApplyTo(expr, ctx); if (subexpr.Type != ctx.Settings.ExpectReturn) { subexpr = CompilerHelpers.ConvertToType(subexpr, ctx.Settings.ExpectReturn); } if (ctx.Settings is IDomainRestrictionSettings domainSettings && !domainSettings.IgnoreDomainRestrictions) { var overflowCtor = Helpers.GetConstructor <Action>(() => new OverflowException("")); subexpr = DomainRestrictionSettings.GetDomainRestrictionsFor(ctx) .Select(e => { SetTypeHint(ctx, typeof(bool)); return(x: CompilerHelpers.ConvertToType(base.ApplyTo(e, ctx), typeof(bool)), e); }) .Aggregate(subexpr, (start, restrict) => Expression.Condition(restrict.x, Expression.Throw(Expression.New(overflowCtor, Expression.Constant($"{restrict.e} not in domain")), start.Type), start)); } return(subexpr); } catch (CompilationException) { throw; } catch (Exception e) { throw new CompilationException(expr, e); } }
public void CompileDomainRestriction(MathExpression expr, MathExpression restrict, Type expectType, object xarg, object result, bool shouldThrow) { var context = CompilationContext.CreateWith(new DefaultLinqExpressionCompilerSettings { ExpectReturn = expectType, IgnoreDomainRestrictions = false, }, new DefaultLinqExpressionCompiler <DefaultLinqExpressionCompilerSettings>()); var objParam = Expression.Parameter(typeof(object)); var var = Expression.Variable(expectType); context.Settings.ParameterMap.Add(new VariableExpression("x"), var); var restrictions = DomainRestrictionSettings.GetDomainRestrictionsFor(context); restrictions.Add(restrict); var fn = Expression.Lambda <Func <object, object> >( Expression.Block( new[] { var }, Expression.Assign(var, Expression.Convert(objParam, expectType)), Expression.Convert( context.Compile(expr), typeof(object) ) ), objParam ).Compile(); try { Assert.Equal(fn(xarg), result); Assert.False(shouldThrow, "Function should have thrown"); } catch (Exception e) { Assert.True(shouldThrow, $"Function threw when it shouldn't have {e}"); } }
private ICollection <MathExpression> GetDomainRestrictions(IDataContext ctx) => DomainRestrictionSettings.GetDomainRestrictionsFor(ctx);