/// <inheritdoc/> public bool TryCompile(IReadOnlyList <MathExpression> arguments, ICompilationContext <object?> context, ITypeHintHandler typeHintHandler, [MaybeNullWhen(false)] out Expression expr) { if (arguments.Count != 1) { expr = null; return(false); } var argExpr = context.Transform(arguments.First()); if (argExpr.Type == typeof(float) || argExpr.Type == typeof(double)) { // if this is a floating point var method = Helpers.GetMethod <Action <double> >(d => Math.Log(d)) !; expr = Expression.Call(method, CompilerHelpers.ConvertToType(argExpr, typeof(double))); return(true); } else if (CompilerHelpers.IsFloating(argExpr.Type) || CompilerHelpers.IsIntegral(argExpr.Type)) { // if this is a built-in integer or decimal var method = Helpers.GetMethod <Action <decimal> >(d => DecimalMath.Ln(d)) !; expr = Expression.Call(method, CompilerHelpers.ConvertToType(argExpr, typeof(decimal))); return(true); } expr = null; return(false); }
/// <inheritdoc/> public bool TryCompile(IReadOnlyList <MathExpression> arguments, ICompilationContext <object?> context, ITypeHintHandler typeHintHandler, [MaybeNullWhen(false)] out Expression expr) { // TODO: add logging to contexts if (arguments.Count != 1) { expr = null; return(false); } expr = Expression.Call(Method, CompilerHelpers.ConvertToType( typeHintHandler.TransformWithHint(arguments.First(), typeof(double), context), typeof(double))); return(true); }
/// <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); } }
/// <inheritdoc/> public override Expression ApplyTo(Syntax.BinaryExpression expr, ICompilationContext <TSettings> ctx) { var exprType = expr.Type; var args = expr.Arguments.Select(m => { var origHint = GetTypeHint(ctx); if (exprType.IsComparisonType()) { SetTypeHint(ctx, null); } else if (exprType.IsBooleanType()) { SetTypeHint(ctx, typeof(bool)); } var applied = ApplyTo(m, ctx); SetTypeHint(ctx, origHint); return(applied); }).ToList(); var boolResType = exprType.IsComparisonType() ? typeof(bool) : GetTypeHint(ctx) ?? args.First().Type; try { return(AggregateBinaryExpr(expr.Type, args, boolResType, ctx.Settings)); } catch { // ignore } // if we fail to do it with the base implicitly gotten arguments, attempt to convert all arguments to the same (largest) type var allTypes = args.Select(e => e.Type); var convertAllTo = allTypes .OrderByDescending(CompilerHelpers.EstimateTypeSize) .Where(ty => allTypes.All(t => CompilerHelpers.HasConversionPathTo(t, ty))) .First(); // biggest one boolResType = GetTypeHint(ctx) ?? convertAllTo; // re-compile arguments with new type hint SetTypeHint(ctx, convertAllTo); args = expr.Arguments.Select(m => CompilerHelpers.ConvertToType(ApplyTo(m, ctx), convertAllTo)).ToList(); return(AggregateBinaryExpr(expr.Type, args, boolResType, ctx.Settings)); }
/// <inheritdoc/> public bool TryCompile(IReadOnlyList <MathExpression> arguments, ICompilationContext <object?> ctx, ITypeHintHandler hintHandler, [MaybeNullWhen(false)] out Expression expr) { if (arguments.Count != 3) { expr = null; return(false); } var condition = hintHandler.TransformWithHint(arguments.First(), typeof(bool), ctx); var hint = hintHandler.CurrentHint(ctx); Expression?thenExpr = null, elseExpr = null; Type? convertAllTo, lastThen, lastElse; do { lastThen = thenExpr?.Type; lastElse = elseExpr?.Type; thenExpr = hintHandler.TransformWithHint(arguments[1], hint, ctx); elseExpr = hintHandler.TransformWithHint(arguments[2], hint, ctx); var allTypes = new[] { thenExpr.Type, elseExpr.Type }; convertAllTo = allTypes .OrderByDescending(CompilerHelpers.EstimateTypeSize) .Where(ty => allTypes.All(t => CompilerHelpers.HasConversionPathTo(t, ty))) .FirstOrDefault(); // biggest one }while (thenExpr.Type != elseExpr.Type && thenExpr.Type != convertAllTo && lastThen != thenExpr.Type && lastElse != elseExpr.Type); if (convertAllTo == null) { throw new ArgumentException("True and False branches of condition do not have a common type to be converted to"); } expr = Expression.Condition(CompilerHelpers.AsBoolean(condition), CompilerHelpers.ConvertToType(thenExpr, convertAllTo), CompilerHelpers.ConvertToType(elseExpr, convertAllTo)); return(true); }