/// <summary>
    ///     Generates a property call on the parameter.
    /// </summary>
    /// <typeparam name="T">The type to call the property from.</typeparam>
    /// <param name="methodName">Name of the parameter.</param>
    /// <param name="tolerance">The tolerance for this expression. Can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param>
    /// <returns>An expression representing a property call.</returns>
    /// <exception cref="ArgumentException"><paramref name="methodName" /> represents a property that cannot be found.</exception>
    protected Expression GenerateParameterMethodCall <T>(
        string methodName,
        Tolerance?tolerance)
    {
        if (string.IsNullOrWhiteSpace(methodName))
        {
            throw new ArgumentException(
                      string.Format(
                          CultureInfo.CurrentCulture,
                          Resources.FunctionCouldNotBeFound,
                          methodName),
                      nameof(methodName));
        }

        MethodInfo mi = typeof(T).GetRuntimeMethod(
            methodName,
            Array.Empty <Type>()) ??
                        throw new ArgumentException(
                                  string.Format(
                                      CultureInfo.CurrentCulture,
                                      Resources.FunctionCouldNotBeFound,
                                      methodName),
                                  nameof(methodName));

        return(tolerance == null
            ? Expression.Call(
                   Parameter.GenerateExpression(),
                   mi)
            : Expression.Call(
                   Parameter.GenerateExpression(tolerance),
                   mi));
    }
    /// <summary>
    ///     Generates a property call on the parameter.
    /// </summary>
    /// <typeparam name="T">The type to call the property from.</typeparam>
    /// <param name="propertyName">Name of the parameter.</param>
    /// <param name="tolerance">The tolerance for this expression. Can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param>
    /// <returns>An expression representing a property call.</returns>
    /// <exception cref="ArgumentException"><paramref name="propertyName" /> represents a property that cannot be found.</exception>
    protected Expression GenerateParameterPropertyCall <T>(
        string propertyName,
        Tolerance?tolerance)
    {
        if (string.IsNullOrWhiteSpace(propertyName))
        {
            throw new ArgumentException(
                      string.Format(
                          CultureInfo.CurrentCulture,
                          Resources.FunctionCouldNotBeFound,
                          propertyName),
                      nameof(propertyName));
        }

        PropertyInfo pi = typeof(T).GetRuntimeProperty(propertyName) ??
                          throw new ArgumentException(
                                    string.Format(
                                        CultureInfo.CurrentCulture,
                                        Resources.FunctionCouldNotBeFound,
                                        propertyName),
                                    nameof(propertyName));

        return(Expression.Property(
                   tolerance == null ? Parameter.GenerateExpression() : Parameter.GenerateExpression(tolerance),
                   pi));
    }
示例#3
0
        private bool DeserializeSecondTouchingPoint(XmlReader reader)
        {
            var angleString     = reader.GetAttribute("Angle");
            var deviationString = reader.GetAttribute("Deviation");

            Tolerance?tolerance = null;

            if (!reader.IsEmptyElement)
            {
                while (reader.Read() && reader.NodeType != XmlNodeType.EndElement)
                {
                    if (reader.Name.Equals("Tolerance"))
                    {
                        tolerance = Tolerance.Deserialize(reader);
                    }
                }
            }

            SecondTouchingPoint = new CircleInProfilePoint
            {
                Angle     = Property.ObjectToNullableDouble(angleString, CultureInfo.InvariantCulture) ?? 0.0,
                Deviation = Property.ObjectToNullableDouble(deviationString, CultureInfo.InvariantCulture) ?? 0.0
            };

            if (tolerance != null)
            {
                SecondTouchingPoint.Tolerance = tolerance;
            }

            return(true);
        }
 /// <summary>
 ///     Generates a static unary function call.
 /// </summary>
 /// <typeparam name="T">The type to call the method from.</typeparam>
 /// <param name="functionName">Name of the function.</param>
 /// <param name="tolerance">The tolerance for this expression. Can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param>
 /// <returns>An expression representing the static function call.</returns>
 /// <exception cref="ArgumentException"><paramref name="functionName" /> represents a function that cannot be found.</exception>
 protected Expression GenerateStaticUnaryFunctionCall <T>(
     string functionName,
     Tolerance?tolerance) =>
 GenerateStaticUnaryFunctionCall(
     typeof(T),
     functionName,
     tolerance);
示例#5
0
    /// <summary>
    /// Computes the expression and returns a result.
    /// </summary>
    /// <param name="tolerance">The tolerance.</param>
    /// <param name="dataFinder">The data finder for the arguments with which to invoke execution of the expression.</param>
    /// <returns>
    /// The computed result, or, if the expression is not recognized correctly, the expression as a <see cref="string" />.
    /// </returns>
    public object Compute(Tolerance?tolerance, IDataFinder dataFinder)
    {
        this.RequiresNotDisposed();

        if (!RecognizedCorrectly)
        {
            return(initialExpression);
        }

        var pars = new List <object>();

        _ = Requires.NotNull(
            dataFinder,
            nameof(dataFinder));

        foreach (ParameterContext p in parametersRegistry?.Dump() ?? Array.Empty <ParameterContext>())
        {
            if (!dataFinder.TryGetData(p.Name, out var data))
            {
                data = null;
            }

            pars.Add(data);
        }

        return(pars.Any(p => p == null) ? initialExpression : Compute(tolerance, pars.ToArray()));
    }
示例#6
0
 /// <summary>
 ///     Generates the expression with tolerance that will be compiled into code.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>The expression.</returns>
 protected override Expression GenerateExpressionInternal(Tolerance?tolerance) =>
 Expression.Divide(
     Expression.Convert(
         Left.GenerateExpression(tolerance),
         typeof(double)),
     Expression.Convert(
         Right.GenerateExpression(tolerance),
         typeof(double)));
 /// <summary>
 ///     Generates the expression with tolerance that will be compiled into code.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>The expression.</returns>
 protected override Expression GenerateExpressionInternal(Tolerance?tolerance) =>
 Expression.Call(
     typeof(global::System.Math),
     nameof(global::System.Math.Pow),
     null,
     Expression.Convert(
         Left.GenerateExpression(tolerance),
         typeof(double)),
     Expression.Convert(
         Right.GenerateExpression(tolerance),
         typeof(double)));
    /// <summary>
    ///     Generates the expression with tolerance that will be compiled into code.
    /// </summary>
    /// <param name="tolerance">The tolerance.</param>
    /// <returns>The expression.</returns>
    protected override Expression GenerateExpressionInternal(Tolerance?tolerance)
    {
        var left  = Left.GenerateExpression(tolerance);
        var right = Right.GenerateExpression(tolerance);

        EnsureCompatibleNumericExpressions(
            ref left,
            ref right);

        return(Expression.Multiply(
                   left,
                   right));
    }
    /// <summary>
    ///     Generates a string expression that will be cached before being compiled.
    /// </summary>
    /// <param name="tolerance">The tolerance.</param>
    /// <returns>The generated <see cref="Expression" /> to be cached.</returns>
    public sealed override Expression GenerateCachedStringExpression(Tolerance?tolerance)
    {
        var expression = GenerateExpression(tolerance);

        if (expression.Type == typeof(string))
        {
            return(expression);
        }

        var stringFormatters = SpecialObjectRequestFunction?.Invoke(typeof(IStringFormatter)) as List <IStringFormatter>;

        return(StringFormatter.CreateStringConversionExpression(
                   expression,
                   stringFormatters));
    }
示例#10
0
        /// <summary>
        /// Can the given instances be considered equal?
        /// </summary>
        public static bool Equals(Tolerance?t1, Tolerance?t2)
        {
            if (ReferenceEquals(t1, t2))
            {
                return(true);
            }

            if (t1 == null || t2 == null)
            {
                return(false);
            }

            if (t1.ToleranceType != t2.ToleranceType)
            {
                return(false);
            }

            switch (t1.ToleranceType)
            {
            case ToleranceType.Default:
                return
                    (t1.Lower.IsCloseTo(t2.Lower) &&
                     t1.Upper.IsCloseTo(t2.Upper));

            case ToleranceType.Circular:
                return(t1.CircularToleranceRadius.IsCloseTo(t2.CircularToleranceRadius));

            case ToleranceType.Rectangular:
                return
                    (t1.RectangleToleranceHeight.IsCloseTo(t2.RectangleToleranceHeight) &&
                     t1.RectangleToleranceWidth.IsCloseTo(t2.RectangleToleranceWidth));

            case ToleranceType.Spatial:
                return(t1.SpatialTolerance == t2.SpatialTolerance);
            }

            return(false);
        }
示例#11
0
    /// <summary>
    ///     Gets the expressions of same type from operands.
    /// </summary>
    /// <param name="tolerance">The tolerance.</param>
    /// <returns>The left and right operand expressions.</returns>
    protected (Expression Left, Expression Right) GetExpressionsOfSameTypeFromOperands(Tolerance?tolerance)
    {
        if (Left.ReturnType == SupportedValueType.String || Right.ReturnType == SupportedValueType.String)
        {
            return(Left.GenerateStringExpression(tolerance),
                   Right.GenerateStringExpression(tolerance));
        }

        Expression le = Left.GenerateExpression(tolerance);
        Expression re = Right.GenerateExpression(tolerance);

        if (le.Type == typeof(double) && re.Type == typeof(long))
        {
            return(Left : le,
                   Right : Expression.Convert(
                       re,
                       typeof(double)));
        }

        if (le.Type == typeof(long) && re.Type == typeof(double))
        {
            return(Left : Expression.Convert(
                       le,
                       typeof(double)),
                   Right : re);
        }

        return(Left : le, Right : re);
    }
 /// <summary>
 ///     Generates the expression with tolerance that will be compiled into code.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>The expression.</returns>
 protected override Expression GenerateExpressionInternal(Tolerance?tolerance) =>
 GenerateParameterMethodCall <string>(
     nameof(string.Trim),
     tolerance);
示例#13
0
 /// <summary>
 /// Generates the expression with tolerance that will be compiled into code.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>The expression.</returns>
 protected override Expression GenerateExpressionInternal(Tolerance?tolerance) =>
 GenerateStaticBinaryFunctionCall <double, int>(
     typeof(GlobalSystem.Math),
     nameof(GlobalSystem.Math.Round),
     tolerance);
    /// <summary>
    /// Generates an expression with tolerance that will be cached before being compiled.
    /// </summary>
    /// <param name="tolerance">The tolerance.</param>
    /// <returns>
    /// The generated <see cref="Expression" /> to be cached.
    /// </returns>
    /// <remarks>
    /// <para>This method works by first attempting to simplify this node.</para>
    /// <para>If the node can be simplified, <see cref="CachedExpressionNodeBase.GenerateExpression()" /> is called on the new node and returned in lieu of this expression.</para>
    /// <para>If this node cannot be simplified, or its simplification method returns reflexively, <see cref="GenerateExpressionInternal(Tolerance)" /> is called.</para>
    /// </remarks>
    public sealed override Expression GenerateCachedExpression(Tolerance?tolerance)
    {
        NodeBase simplifiedExpression = Simplify();

        return(simplifiedExpression != this ? simplifiedExpression.GenerateExpression(tolerance) : GenerateExpressionInternal(tolerance));
    }
 /// <summary>
 /// Generates the expression with tolerance that will be compiled into code.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>The expression.</returns>
 protected virtual Expression GenerateExpressionInternal(Tolerance?tolerance) => GenerateExpressionInternal();
    /// <summary>
    ///     Generates a static unary function call.
    /// </summary>
    /// <param name="t">The type to call the method from.</param>
    /// <param name="functionName">Name of the function.</param>
    /// <param name="tolerance">The tolerance for this expression. Can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param>
    /// <returns>
    ///     An expression representing the static function call.
    /// </returns>
    /// <exception cref="ArgumentException"><paramref name="functionName" /> represents a function that cannot be found.</exception>
    protected Expression GenerateStaticUnaryFunctionCall(
        Type t,
        string functionName,
        Tolerance?tolerance)
    {
        if (string.IsNullOrWhiteSpace(functionName))
        {
            throw new ArgumentException(
                      string.Format(
                          CultureInfo.CurrentCulture,
                          Resources.FunctionCouldNotBeFound,
                          functionName),
                      nameof(functionName));
        }

        Type parameterType = ParameterTypeFromParameter(Parameter);

        MethodInfo?mi = t.GetMethodWithExactParameters(
            functionName,
            parameterType);

        if (mi == null)
        {
            parameterType = typeof(double);

            mi = t.GetMethodWithExactParameters(
                functionName,
                parameterType);

            if (mi == null)
            {
                parameterType = typeof(long);

                mi = t.GetMethodWithExactParameters(
                    functionName,
                    parameterType);

                if (mi == null)
                {
                    parameterType = typeof(int);

                    mi = t.GetMethodWithExactParameters(
                        functionName,
                        parameterType) ??
                         throw new ArgumentException(
                                   string.Format(
                                       CultureInfo.CurrentCulture,
                                       Resources.FunctionCouldNotBeFound,
                                       functionName),
                                   nameof(functionName));
                }
            }
        }

        Expression e = tolerance == null
            ? Parameter.GenerateExpression()
            : Parameter.GenerateExpression(tolerance);

        if (e.Type != parameterType)
        {
            e = Expression.Convert(
                e,
                parameterType);
        }

        return(Expression.Call(
                   mi,
                   e));
    }
示例#17
0
    public object Compute(Tolerance?tolerance, params object[] arguments)
    {
        this.RequiresNotDisposed();

        if (!RecognizedCorrectly)
        {
            // Expression was not recognized correctly.
            return(initialExpression);
        }

        var convertedArguments = FormatArgumentsAccordingToParameters(arguments, parametersRegistry?.Dump() ?? Array.Empty <ParameterContext>());

        object[]? FormatArgumentsAccordingToParameters(
            object[] parameterValues,
            ParameterContext[] parameters)
        {
            if (parameterValues.Length != parameters.Length)
            {
                return(null);
            }

            var finalValues = new object[parameterValues.Length];

            var i = 0;

            object?paramValue = null;

            while (i < finalValues.Length)
            {
                ParameterContext paraContext = parameters[i];

                // If there was no continuation, initialize parameter with value.
                paramValue ??= parameterValues[i];

                // Initial filtration
                switch (paramValue)
                {
                case byte convertedParam:
                    paramValue = Convert.ToInt64(convertedParam);
                    continue;

                case sbyte convertedParam:
                    paramValue = Convert.ToInt64(convertedParam);
                    continue;

                case short convertedParam:
                    paramValue = Convert.ToInt64(convertedParam);
                    continue;

                case ushort convertedParam:
                    paramValue = Convert.ToInt64(convertedParam);
                    continue;

                case int convertedParam:
                    paramValue = Convert.ToInt64(convertedParam);
                    continue;

                case uint convertedParam:
                    paramValue = Convert.ToInt64(convertedParam);
                    continue;

                case long convertedParam:
                    paramValue = convertedParam;
                    break;

                case ulong convertedParam:
                    paramValue = Convert.ToDouble(convertedParam);
                    continue;

                case float convertedParam:
                    paramValue = Convert.ToDouble(convertedParam);
                    continue;

                case double convertedParam:
                    paramValue = convertedParam;
                    break;

                case string convertedParam:
                    paramValue = convertedParam;
                    break;

                case bool convertedParam:
                    paramValue = convertedParam;
                    break;

                case byte[] convertedParam:
                    paramValue = convertedParam;
                    break;

                case Func <byte> convertedParam:
                    paramValue = new Func <long>(() => Convert.ToInt64(convertedParam()));
                    continue;

                case Func <sbyte> convertedParam:
                    paramValue = new Func <long>(() => Convert.ToInt64(convertedParam()));
                    continue;

                case Func <short> convertedParam:
                    paramValue = new Func <long>(() => Convert.ToInt64(convertedParam()));
                    continue;

                case Func <ushort> convertedParam:
                    paramValue = new Func <long>(() => Convert.ToInt64(convertedParam()));
                    continue;

                case Func <int> convertedParam:
                    paramValue = new Func <long>(() => Convert.ToInt64(convertedParam()));
                    continue;

                case Func <uint> convertedParam:
                    paramValue = new Func <long>(() => Convert.ToInt64(convertedParam()));
                    continue;

                case Func <long> convertedParam:
                    paramValue = convertedParam;
                    break;

                case Func <ulong> convertedParam:
                    paramValue = new Func <double>(() => Convert.ToDouble(convertedParam()));
                    continue;

                case Func <float> convertedParam:
                    paramValue = new Func <double>(() => Convert.ToDouble(convertedParam()));
                    continue;

                case Func <double> convertedParam:
                    paramValue = convertedParam;
                    break;

                case Func <string> convertedParam:
                    paramValue = convertedParam;
                    break;

                case Func <bool> convertedParam:
                    paramValue = convertedParam;
                    break;

                case Func <byte[]> convertedParam:
                    paramValue = convertedParam;
                    break;

                default:
                    // Argument type is not (yet) supported
                    return(null);
                }

                // Secondary filtration
                switch (paramValue)
                {
                case long convertedParam:
                    switch (paraContext.ReturnType)
                    {
                    case SupportedValueType.Boolean:
                        paramValue = CreateValue(paraContext, convertedParam != 0);
                        break;

                    case SupportedValueType.ByteArray:
                        paramValue = CreateValue(paraContext, BitConverter.GetBytes(convertedParam));
                        break;

                    case SupportedValueType.Numeric:
                        switch (paraContext.IsFloat)
                        {
                        case true:
                            paramValue = CreateValue(paraContext, Convert.ToDouble(convertedParam));
                            break;

                        case false:
                            paramValue = CreateValue(paraContext, convertedParam);
                            break;

                        default:
                            paraContext.DetermineInteger();
                            continue;
                        }

                        break;

                    case SupportedValueType.String:
                        paramValue = CreateValue(
                            paraContext,
                            StringFormatter.FormatIntoString(convertedParam, stringFormatters));

                        break;

                    case SupportedValueType.Unknown:
                        paraContext.DetermineType(SupportedValueType.Numeric);
                        continue;
                    }

                    break;

                case double convertedParam:
                    switch (paraContext.ReturnType)
                    {
                    case SupportedValueType.Boolean:
                        // ReSharper disable once CompareOfFloatsByEqualityOperator - no better idea for now
                        paramValue = CreateValue(paraContext, convertedParam != 0D);
                        break;

                    case SupportedValueType.ByteArray:
                        paramValue = CreateValue(paraContext, BitConverter.GetBytes(convertedParam));
                        break;

                    case SupportedValueType.Numeric:
                        switch (paraContext.IsFloat)
                        {
                        case true:
                            paramValue = CreateValue(paraContext, convertedParam);
                            break;

                        case false:
                            paramValue = CreateValue(paraContext, Convert.ToInt64(convertedParam));
                            break;

                        default:
                            paraContext.DetermineFloat();
                            continue;
                        }

                        break;

                    case SupportedValueType.String:
                        paramValue = CreateValue(
                            paraContext,
                            StringFormatter.FormatIntoString(convertedParam, stringFormatters));
                        break;

                    case SupportedValueType.Unknown:
                        paraContext.DetermineType(SupportedValueType.Numeric);
                        continue;
                    }

                    break;

                case bool convertedParam:
                    switch (paraContext.ReturnType)
                    {
                    case SupportedValueType.Boolean:
                        paramValue = CreateValue(paraContext, convertedParam);
                        break;

                    case SupportedValueType.ByteArray:
                        paramValue = CreateValue(paraContext, BitConverter.GetBytes(convertedParam));
                        break;

                    case SupportedValueType.Numeric:
                        return(null);

                    case SupportedValueType.String:
                        paramValue = CreateValue(
                            paraContext,
                            StringFormatter.FormatIntoString(convertedParam, stringFormatters));
                        break;

                    case SupportedValueType.Unknown:
                        paraContext.DetermineType(SupportedValueType.Boolean);
                        continue;
                    }

                    break;

                case string convertedParam:
                    switch (paraContext.ReturnType)
                    {
                    case SupportedValueType.Boolean:
                        paramValue = CreateValue(paraContext, bool.Parse(convertedParam));
                        break;

                    case SupportedValueType.ByteArray:
                    {
                        if (ParsingFormatter.ParseByteArray(convertedParam, out var byteArrayResult))
                        {
                            paramValue = CreateValue(paraContext, byteArrayResult);
                        }
                        else
                        {
                            // Cannot parse byte array.
                            return(null);
                        }
                    }

                    break;

                    case SupportedValueType.Numeric:
                    {
                        if (ParsingFormatter.ParseNumeric(convertedParam, out var numericResult))
                        {
                            switch (numericResult)
                            {
                            case long integerResult:
                                paramValue = CreateValue(paraContext, integerResult);
                                break;

                            case double floatResult:
                                paramValue = CreateValue(paraContext, floatResult);
                                break;

                            default:
                                // Numeric type unknown.
                                return(null);
                            }
                        }
                        else
                        {
                            // Cannot parse numeric type.
                            return(null);
                        }
                    }

                    break;

                    case SupportedValueType.String:
                        paramValue = CreateValue(paraContext, convertedParam);
                        break;

                    case SupportedValueType.Unknown:
                        paraContext.DetermineType(SupportedValueType.String);
                        continue;
                    }

                    break;

                case byte[] convertedParam:
                    switch (paraContext.ReturnType)
                    {
                    case SupportedValueType.Boolean:
                        paramValue = CreateValue(paraContext, BitConverter.ToBoolean(convertedParam, 0));
                        break;

                    case SupportedValueType.ByteArray:
                        paramValue = CreateValue(paraContext, convertedParam);
                        break;

                    case SupportedValueType.Numeric:
                        switch (paraContext.IsFloat)
                        {
                        case true:
                            paramValue = CreateValue(paraContext, BitConverter.ToDouble(convertedParam, 0));
                            break;

                        case false:
                            paramValue = CreateValue(paraContext, BitConverter.ToInt64(convertedParam, 0));
                            break;

                        default:
                            paraContext.DetermineFloat();
                            continue;
                        }

                        break;

                    case SupportedValueType.String:
                        paramValue = CreateValue(
                            paraContext,
                            StringFormatter.FormatIntoString(convertedParam, stringFormatters));
                        break;

                    case SupportedValueType.Unknown:
                        paraContext.DetermineType(SupportedValueType.ByteArray);
                        continue;
                    }

                    break;

                case Func <long> convertedParam:
                    paraContext.DetermineFunc();

                    switch (paraContext.ReturnType)
                    {
                    case SupportedValueType.Boolean:
                        paramValue = CreateValueFromFunc(paraContext, () => convertedParam() == 0);
                        break;

                    case SupportedValueType.ByteArray:
                        paramValue = CreateValueFromFunc(paraContext, () => BitConverter.GetBytes(convertedParam()));
                        break;

                    case SupportedValueType.Numeric:
                        switch (paraContext.IsFloat)
                        {
                        case true:
                            paramValue = CreateValueFromFunc(paraContext, () => Convert.ToDouble(convertedParam()));
                            break;

                        case false:
                            paramValue = CreateValueFromFunc(paraContext, convertedParam);
                            break;

                        default:
                            paraContext.DetermineInteger();
                            continue;
                        }

                        break;

                    case SupportedValueType.String:
                        paramValue = CreateValueFromFunc(paraContext, () => StringFormatter.FormatIntoString(convertedParam(), stringFormatters));
                        break;

                    case SupportedValueType.Unknown:
                        paraContext.DetermineType(SupportedValueType.Numeric);
                        continue;
                    }

                    break;

                case Func <double> convertedParam:
                    paraContext.DetermineFunc();

                    switch (paraContext.ReturnType)
                    {
                    case SupportedValueType.Boolean:
                        // ReSharper disable once CompareOfFloatsByEqualityOperator - no better idea for now
                        paramValue = CreateValueFromFunc(paraContext, () => convertedParam() == 0D);
                        break;

                    case SupportedValueType.ByteArray:
                        paramValue = CreateValueFromFunc(paraContext, () => BitConverter.GetBytes(convertedParam()));
                        break;

                    case SupportedValueType.Numeric:
                        switch (paraContext.IsFloat)
                        {
                        case true:
                            paramValue = CreateValueFromFunc(paraContext, convertedParam);
                            break;

                        case false:
                            paramValue = CreateValueFromFunc(paraContext, () => Convert.ToInt64(convertedParam()));
                            break;

                        default:
                            paraContext.DetermineFloat();
                            continue;
                        }

                        break;

                    case SupportedValueType.String:
                        paramValue = CreateValueFromFunc(paraContext, () => StringFormatter.FormatIntoString(convertedParam(), stringFormatters));

                        break;

                    case SupportedValueType.Unknown:
                        paraContext.DetermineType(SupportedValueType.Numeric);
                        continue;
                    }

                    break;

                case Func <bool> convertedParam:
                    paraContext.DetermineFunc();

                    switch (paraContext.ReturnType)
                    {
                    case SupportedValueType.Boolean:
                        paramValue = CreateValueFromFunc(paraContext, convertedParam);
                        break;

                    case SupportedValueType.ByteArray:
                        paramValue = CreateValueFromFunc(paraContext, () => BitConverter.GetBytes(convertedParam()));
                        break;

                    case SupportedValueType.Numeric:
                        return(null);

                    case SupportedValueType.String:
                        paramValue = CreateValueFromFunc(paraContext, () => StringFormatter.FormatIntoString(convertedParam(), stringFormatters));
                        break;

                    case SupportedValueType.Unknown:
                        paraContext.DetermineType(SupportedValueType.Boolean);
                        continue;
                    }

                    break;

                case Func <string> convertedParam:
                    paraContext.DetermineFunc();

                    switch (paraContext.ReturnType)
                    {
                    case SupportedValueType.Boolean:
                        paramValue = CreateValueFromFunc(paraContext, () => bool.Parse(convertedParam()));
                        break;

                    case SupportedValueType.ByteArray:
                        paramValue = CreateValueFromFunc(paraContext, () => ParsingFormatter.ParseByteArray(convertedParam(), out var baResult) ? baResult : null);
                        break;

                    case SupportedValueType.Numeric:
                        switch (paraContext.IsFloat)
                        {
                        case true:
                            paramValue = CreateValueFromFunc(paraContext, () => ParsingFormatter.ParseNumeric(
                                                                 convertedParam(),
                                                                 out var numericResult)
                                            ? Convert.ToDouble(numericResult, CultureInfo.CurrentCulture)
                                            : throw new ArgumentInvalidTypeException(paraContext.Name));
                            break;

                        case false:
                            paramValue = CreateValueFromFunc(paraContext, () => ParsingFormatter.ParseNumeric(
                                                                 convertedParam(),
                                                                 out var numericResult)
                                            ? Convert.ToInt64(numericResult, CultureInfo.CurrentCulture)
                                            : throw new ArgumentInvalidTypeException(paraContext.Name));
                            break;

                        default:
                            paraContext.DetermineFloat();
                            continue;
                        }

                        break;

                    case SupportedValueType.String:
                        paramValue = CreateValueFromFunc(paraContext, convertedParam);
                        break;

                    case SupportedValueType.Unknown:
                        paraContext.DetermineType(SupportedValueType.String);
                        continue;
                    }

                    break;

                case Func <byte[]> convertedParam:
                    paraContext.DetermineFunc();

                    switch (paraContext.ReturnType)
                    {
                    case SupportedValueType.Boolean:
                        paramValue = CreateValueFromFunc(paraContext, () => BitConverter.ToBoolean(convertedParam(), 0));
                        break;

                    case SupportedValueType.ByteArray:
                        paramValue = CreateValueFromFunc(paraContext, convertedParam);
                        break;

                    case SupportedValueType.Numeric:
                        switch (paraContext.IsFloat)
                        {
                        case true:
                            paramValue = CreateValueFromFunc(paraContext, () => BitConverter.ToDouble(convertedParam(), 0));
                            break;

                        case false:
                            paramValue = CreateValueFromFunc(paraContext, () => BitConverter.ToInt64(convertedParam(), 0));
                            break;

                        default:
                            paraContext.DetermineFloat();
                            continue;
                        }

                        break;

                    case SupportedValueType.String:
                        paramValue = CreateValueFromFunc(paraContext, () => StringFormatter.FormatIntoString(convertedParam(), stringFormatters));
                        break;

                    case SupportedValueType.Unknown:
                        paraContext.DetermineType(SupportedValueType.ByteArray);
                        continue;
                    }

                    break;

                default:
                    // Argument type is not (yet) supported
                    return(null);
                }

#pragma warning disable HAA0601 // Value type to reference type conversion causing boxing allocation - This is unavoidable now
#pragma warning disable HAA0303 // Considering moving this out of the generic method - Not really possible
                object CreateValue <T>(ParameterContext parameterContext, T value) => parameterContext.FuncParameter ? new Func <T>(() => value) : (object)value;

                object CreateValueFromFunc <T>(
                    ParameterContext parameterContext,
                    Func <T> value) => parameterContext.FuncParameter ? (object)value : value();

#pragma warning restore HAA0303 // Considering moving this out of the generic method
#pragma warning restore HAA0601 // Value type to reference type conversion causing boxing allocation

                if (paramValue == null)
                {
                    return(null);
                }

                finalValues[i] = paramValue;

                paramValue = null;

                i++;
            }

            return(finalValues);
        }

        if (convertedArguments == null)
        {
            // The arguments could not be correctly converted.
            return(initialExpression);
        }

        Delegate?del;

        if (body == null)
        {
            del = null;
        }
        else
        {
            try
            {
                del = Expression.Lambda(
                    tolerance == null ? body.GenerateExpression() : body.GenerateExpression(tolerance),
                    parametersRegistry?.Dump().Select(p => p.ParameterExpression) ?? Array.Empty <ParameterExpression>())
                      .Compile();
            }
            catch
            {
                // Expression is somehow not valid
                del = null;
            }
        }

        if (del == null)
        {
            // Delegate could not be compiled with the given arguments.
            return(initialExpression);
        }

        try
        {
            return(del.DynamicInvoke(convertedArguments));
        }
        catch (OutOfMemoryException)
        {
            throw;
        }
        catch (DivideByZeroException)
        {
            throw;
        }
        catch
        {
            // Dynamic invocation of generated expression failed.
            return(initialExpression);
        }
    }
示例#18
0
    /// <summary>
    /// Generates a static binary function call expression.
    /// </summary>
    /// <param name="t">The type to call on.</param>
    /// <param name="functionName">Name of the function.</param>
    /// <param name="tolerance">The tolerance, should there be any. This argument can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param>
    /// <returns>
    /// Expression.
    /// </returns>
    /// <exception cref="ArgumentException">The function name is invalid.</exception>
    protected Expression GenerateBinaryFunctionCallFirstParameterInstance(Type t, string functionName, Tolerance?tolerance)
    {
        if (string.IsNullOrWhiteSpace(functionName))
        {
            throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, functionName), nameof(functionName));
        }

        Type firstParameterType  = ParameterTypeFromParameter(FirstParameter);
        Type secondParameterType = ParameterTypeFromParameter(SecondParameter);

        MethodInfo?mi = t.GetMethodWithExactParameters(functionName, firstParameterType, secondParameterType);

        if (mi == null)
        {
            if ((firstParameterType == typeof(long) && secondParameterType == typeof(double)) ||
                (firstParameterType == typeof(double) && secondParameterType == typeof(long)))
            {
                firstParameterType  = typeof(double);
                secondParameterType = typeof(double);

                mi = t.GetMethodWithExactParameters(functionName, firstParameterType, secondParameterType);

                if (mi == null)
                {
                    firstParameterType  = typeof(long);
                    secondParameterType = typeof(long);

                    mi = t.GetMethodWithExactParameters(functionName, firstParameterType, secondParameterType);

                    if (mi == null)
                    {
                        firstParameterType  = typeof(int);
                        secondParameterType = typeof(int);

                        mi = t.GetMethodWithExactParameters(functionName, firstParameterType, secondParameterType) ??
                             throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, functionName), nameof(functionName));
                    }
                }
            }
            else
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, functionName), nameof(functionName));
            }
        }

        Expression e1, e2;

        if (tolerance == null)
        {
            e1 = FirstParameter.GenerateExpression();
            e2 = SecondParameter.GenerateExpression();
        }
        else
        {
            e1 = FirstParameter.GenerateExpression(tolerance);
            e2 = SecondParameter.GenerateExpression(tolerance);
        }

        if (e1.Type != firstParameterType)
        {
            e1 = Expression.Convert(e1, firstParameterType);
        }

        if (e2.Type != secondParameterType)
        {
            e2 = Expression.Convert(e2, secondParameterType);
        }

        return(Expression.Call(e1, mi, e2));
    }
示例#19
0
 /// <summary>
 ///     Generates the expression with tolerance that will be compiled into code.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>The expression.</returns>
 protected override Expression GenerateExpressionInternal(Tolerance?tolerance) =>
 GenerateStaticUnaryFunctionCall(
     typeof(GlobalSystem.Math),
     nameof(GlobalSystem.Math.Log10),
     tolerance);
 /// <summary>
 ///     Generates the expression that will be compiled into code.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>
 ///     The generated <see cref="Expression" />.
 /// </returns>
 public sealed override Expression GenerateExpression(Tolerance?tolerance) =>
 generatedExpression ??= GenerateCachedExpression(tolerance);
示例#21
0
    protected Expression?GenerateNumericalToleranceEquateExpression(
        Expression leftExpression,
        Expression rightExpression,
        Tolerance?tolerance)
    {
        if (tolerance?.IntegerToleranceRangeLowerBound != null || tolerance?.IntegerToleranceRangeUpperBound != null)
        {
            // Integer tolerance
            MethodInfo mi = typeof(ToleranceFunctions).GetMethodWithExactParameters(
                nameof(ToleranceFunctions.EquateRangeTolerant),
                leftExpression.Type,
                rightExpression.Type,
                typeof(long),
                typeof(long)) !;

            return(Expression.Call(
                       mi,
                       leftExpression,
                       rightExpression,
                       Expression.Constant(
                           tolerance.IntegerToleranceRangeLowerBound ?? 0L,
                           typeof(long)),
                       Expression.Constant(
                           tolerance.IntegerToleranceRangeUpperBound ?? 0L,
                           typeof(long))));
        }

        if (tolerance?.ToleranceRangeLowerBound != null || tolerance?.ToleranceRangeUpperBound != null)
        {
            // Floating-point tolerance
            MethodInfo mi = typeof(ToleranceFunctions).GetMethodWithExactParameters(
                nameof(ToleranceFunctions.EquateRangeTolerant),
                leftExpression.Type,
                rightExpression.Type,
                typeof(double),
                typeof(double)) !;

            return(Expression.Call(
                       mi,
                       leftExpression,
                       rightExpression,
                       Expression.Constant(
                           tolerance.ToleranceRangeLowerBound ?? 0D,
                           typeof(double)),
                       Expression.Constant(
                           tolerance.ToleranceRangeUpperBound ?? 0D,
                           typeof(double))));
        }

        switch (tolerance?.ProportionalTolerance)
        {
        case > 1D:
        {
            // Proportional tolerance
            MethodInfo mi = typeof(ToleranceFunctions).GetMethodWithExactParameters(
                nameof(ToleranceFunctions.EquateProportionTolerant),
                leftExpression.Type,
                rightExpression.Type,
                typeof(double)) !;

            return(Expression.Call(
                       mi,
                       leftExpression,
                       rightExpression,
                       Expression.Constant(
                           tolerance.ProportionalTolerance,
                           typeof(double))));
        }

        case < 1D and > 0D:
        {
            // Percentage tolerance
            MethodInfo mi = typeof(ToleranceFunctions).GetMethodWithExactParameters(
                nameof(ToleranceFunctions.EquatePercentageTolerant),
                leftExpression.Type,
                rightExpression.Type,
                typeof(double)) !;

            return(Expression.Call(
                       mi,
                       leftExpression,
                       rightExpression,
                       Expression.Constant(
                           tolerance.ProportionalTolerance,
                           typeof(double))));
        }

        default:
        {
            return(null);
        }
        }
    }
示例#22
0
 /// <summary>
 ///     Generates the expression that will be compiled into code as a string expression.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>The generated <see cref="Expression" /> that gives the values as a string.</returns>
 public virtual Expression GenerateStringExpression(Tolerance?tolerance) => GenerateStringExpression();
 /// <summary>
 ///     Generates the expression with tolerance that will be compiled into code.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>The expression.</returns>
 protected override Expression GenerateExpressionInternal(Tolerance?tolerance) =>
 Expression.Convert(
     GenerateParameterPropertyCall <string>(
         nameof(string.Length),
         tolerance),
     typeof(long));
示例#24
0
 /// <summary>
 /// Generates the expression with tolerance that will be compiled into code.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>The expression.</returns>
 protected override Expression GenerateExpressionInternal(Tolerance?tolerance) =>
 GenerateStaticBinaryFunctionCall <FunctionNodeRandom>(nameof(GenerateRandom), tolerance);
 /// <summary>
 ///     Generates the expression that will be compiled into code as a string expression.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>The generated <see cref="Expression" /> that gives the values as a string.</returns>
 public override Expression GenerateStringExpression(Tolerance?tolerance) =>
 generatedStringExpression ??= GenerateCachedStringExpression(tolerance);
示例#26
0
    /// <summary>
    ///     Generates the expression with tolerance that will be compiled into code.
    /// </summary>
    /// <param name="tolerance">The tolerance.</param>
    /// <returns>The expression.</returns>
    protected override Expression GenerateExpressionInternal(Tolerance?tolerance)
    {
        Type         firstParameterType  = typeof(string);
        Type         secondParameterType = typeof(int);
        Type         thirdParameterType  = typeof(int);
        const string functionName        = nameof(string.Substring);

        MethodInfo mi = typeof(string).GetMethodWithExactParameters(
            functionName,
            secondParameterType,
            thirdParameterType) !;

        if (mi == null)
        {
            throw new InvalidOperationException(
                      string.Format(
                          CultureInfo.CurrentCulture,
                          Resources.FunctionCouldNotBeFound,
                          functionName));
        }

        Expression e1, e2, e3;

        if (tolerance == null)
        {
            e1 = FirstParameter.GenerateExpression();
            e2 = SecondParameter.GenerateExpression();
            e3 = ThirdParameter.GenerateExpression();
        }
        else
        {
            e1 = FirstParameter.GenerateExpression(tolerance);
            e2 = SecondParameter.GenerateExpression(tolerance);
            e3 = ThirdParameter.GenerateExpression(tolerance);
        }

        if (e1.Type != firstParameterType)
        {
            e1 = Expression.Convert(
                e1,
                firstParameterType);
        }

        if (e2.Type != secondParameterType)
        {
            e2 = Expression.Convert(
                e2,
                secondParameterType);
        }

        if (e3.Type != thirdParameterType)
        {
            e3 = Expression.Convert(
                e3,
                thirdParameterType);
        }

        return(Expression.Call(
                   e1,
                   mi,
                   e2,
                   e3));
    }
 /// <summary>
 ///     Generates an expression with tolerance that will be cached before being compiled.
 /// </summary>
 /// <param name="tolerance">The tolerance.</param>
 /// <returns>
 ///     The generated <see cref="Expression" /> to be cached.
 /// </returns>
 public virtual Expression GenerateCachedExpression(Tolerance?tolerance) => GenerateCachedExpression();
示例#28
0
    /// <summary>
    /// Generates a static binary function call with explicit parameter types.
    /// </summary>
    /// <typeparam name="TParam1">The type of the first parameter.</typeparam>
    /// <typeparam name="TParam2">The type of the second parameter.</typeparam>
    /// <param name="t">The type to call on.</param>
    /// <param name="functionName">Name of the function.</param>
    /// <param name="tolerance">The tolerance, should there be any. This argument can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param>
    /// <returns>
    /// The generated binary method call expression.
    /// </returns>
    /// <exception cref="ArgumentException">The function name is invalid.</exception>
    protected Expression GenerateStaticBinaryFunctionCall <TParam1, TParam2>(Type t, string functionName, Tolerance?tolerance)
    {
        if (string.IsNullOrWhiteSpace(functionName))
        {
            throw new ArgumentException(string.Format(Resources.FunctionCouldNotBeFound, functionName), nameof(functionName));
        }

        Type firstParameterType  = ParameterTypeFromParameter(FirstParameter);
        Type secondParameterType = ParameterTypeFromParameter(SecondParameter);

        MethodInfo mi = t.GetMethodWithExactParameters(functionName, typeof(TParam1), typeof(TParam2)) ?? throw new FunctionCallNotValidLogicallyException();

        Expression e1, e2;

        if (tolerance == null)
        {
            e1 = FirstParameter.GenerateExpression();
            e2 = SecondParameter.GenerateExpression();
        }
        else
        {
            e1 = FirstParameter.GenerateExpression(tolerance);
            e2 = SecondParameter.GenerateExpression(tolerance);
        }

        if (e1.Type != firstParameterType)
        {
            e1 = Expression.Convert(e1, firstParameterType);
        }

        if (e2.Type != secondParameterType)
        {
            e2 = Expression.Convert(e2, secondParameterType);
        }

        if (e1.Type != typeof(TParam1))
        {
            e1 = Expression.Convert(e1, typeof(TParam1));
        }

        if (e2.Type != typeof(TParam2))
        {
            e2 = Expression.Convert(e2, typeof(TParam2));
        }

        return(Expression.Call(mi, e1, e2));
    }