/// <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.º 2
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);
        }