Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
        /// <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));
        }
Ejemplo n.º 5
0
        /// <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);
        }