コード例 #1
0
        public override object Evaluate(object[] Parameters)
        {
            var value = MathConverter.ConvertToDouble(input.Evaluate(Parameters));

            if (value == null)
            {
                return(null);
            }
            else
            {
                return(formula(value.Value));
            }
        }
コード例 #2
0
ファイル: SyntaxTree.cs プロジェクト: jaelys/MathConverter-1
        public static object Average(IEnumerable <object> args)
        {
            dynamic sum   = 0.0;
            var     count = 0;

            foreach (double?arg in args.Select(p => MathConverter.ConvertToDouble(p)))
            {
                if (arg.HasValue)
                {
                    count++;
                    sum += arg;
                }
            }
            if (count == 0)
            {
                return(null);
            }

            return(sum / count);
        }
コード例 #3
0
        /// <summary>
        /// The actual convert method, for zero or more parameters.
        /// </summary>
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            Func <double, object> convert;

            if (parameter is string)
            {
                // Get the parameter
                var param = parameter is string?parameter as string : parameter.ToString();

                // Get the syntax tree from the expression.  We will cache the results to save time for future parsing of the same expression
                // by the same MathConverter.
                var x = ParseParameter(param);

                switch (targetType.FullName)
                {
                case "System.Object":
                    switch (x.Length)
                    {
                    case 1:
                        return(x[0].Evaluate(values));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; Double supports only one", x.Length));
                    }

                case "System.Double":
                    switch (x.Length)
                    {
                    case 1:
                        return(MathConverter.ConvertToDouble(x[0].Evaluate(values)));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; Double supports only one", x.Length));
                    }

                case "System.Windows.CornerRadius":
                    switch (x.Length)
                    {
                    case 1:
                        return(new CornerRadius(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value));

                    case 4:
                        return(new CornerRadius(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[2].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[3].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; CornerRadius supports only one or four", x.Length));
                    }

                case "System.Windows.GridLength":
                    switch (x.Length)
                    {
                    case 1:
                        return(new GridLength(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; GridLength supports only one", x.Length));
                    }

                case "System.Windows.Thickness":
                    switch (x.Length)
                    {
                    case 1:
                        return(new Thickness(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value));

                    case 2:
                        return(new Thickness(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value));

                    case 4:
                        return(new Thickness(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[2].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[3].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; Thickness supports only one, two, or four", x.Length));
                    }

                case "System.Windows.Rect":
                    switch (x.Length)
                    {
                    case 4:
                        return(new Rect(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[2].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[3].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; Rect supports only four", x.Length));
                    }

                case "System.Windows.Size":
                    switch (x.Length)
                    {
                    case 2:
                        return(new Size(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; Size supports only two", x.Length));
                    }

                case "System.Windows.Point":
                    switch (x.Length)
                    {
                    case 2:
                        return(new Point(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; Point supports only two", x.Length));
                    }

                case "System.Boolean":
                    switch (x.Length)
                    {
                    case 1:
                        return((bool?)x[0].Evaluate(values));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; Boolean supports only one", x.Length));
                    }

                case "System.String":
                    switch (x.Length)
                    {
                    case 1:
                        var val = x[0].Evaluate(values);
                        if (val is string)
                        {
                            return(val);
                        }
                        else if (val == null)
                        {
                            return(null);
                        }
                        else
                        {
                            return(val.ToString());
                        }

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; string supports only one", x.Length));
                    }

                case "System.Uri":
                    switch (x.Length)
                    {
                    case 1:
                        var val = x[0].Evaluate(values);
                        if (val is string)
                        {
                            return(new Uri(val as string));
                        }
                        else if (val == null)
                        {
                            return(null);
                        }
                        else
                        {
                            return(new Uri(val.ToString()));
                        }

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; Uri supports only one");
                    }

                case "System.Single":
                    convert = p => System.Convert.ToSingle(p);
                    break;

                case "System.Int32":
                    convert = p => System.Convert.ToInt32(p);
                    break;

                case "System.Int64":
                    convert = p => System.Convert.ToInt64(p);
                    break;

                case "System.Decimal":
                    convert = p => System.Convert.ToDecimal(p);
                    break;

                case "System.Byte":
                    convert = p => System.Convert.ToByte(p);
                    break;

                case "System.SByte":
                    convert = p => System.Convert.ToSByte(p);
                    break;

                case "System.Char":
                    convert = p => (char)System.Convert.ToInt32(p);
                    break;

                case "System.Int16":
                    convert = p => System.Convert.ToInt16(p);
                    break;

                case "System.UInt16":
                    convert = p => System.Convert.ToUInt16(p);
                    break;

                case "System.UInt32":
                    convert = p => System.Convert.ToUInt32(p);
                    break;

                case "System.UInt64":
                    convert = p => System.Convert.ToUInt64(p);
                    break;

                default:
                    if (targetType == typeof(double?))
                    {
                        return(MathConverter.ConvertToDouble(x[0].Evaluate(values)));
                    }

                    // We don't know what to return, so let's evaluate the parameter and try to convert it.
                    var evaluatedValue = x[0].Evaluate(values);
                    if ((targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable <>)))
                    {
                        // We're supposed to return a Nullable<T> where T : struct
                        if (evaluatedValue == null)
                        {
                            return(null);
                        }
                        else
                        {
                            return(System.Convert.ChangeType(evaluatedValue, targetType.GetGenericArguments()[0]));
                        }
                    }

                    return(System.Convert.ChangeType(evaluatedValue, targetType));
                }
                var value = x[0].Evaluate(values);
                if (value == null)
                {
                    return(null);
                }
                else
                {
                    return(convert(ConvertToDouble(value).Value));
                }
            }
            else if (parameter == null)
            {
                switch (targetType.FullName)
                {
                case "System.Object":
                    switch (values.Length)
                    {
                    case 1:
                        return(ConvertToObject(values[0]));

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; Object supports only one or one");
                    }

                case "System.Double":
                    switch (values.Length)
                    {
                    case 1:
                        return(ConvertToDouble(values[0]));

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; Double supports only one or one");
                    }

                case "System.Windows.CornerRadius":
                    switch (values.Length)
                    {
                    case 1:
                        return(new CornerRadius(ConvertToDouble(values[0]).Value));

                    case 4:
                        return(new CornerRadius(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value, ConvertToDouble(values[2]).Value, ConvertToDouble(values[3]).Value));

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; GridLength supports only one or four");
                    }

                case "System.Windows.GridLength":
                    switch (values.Length)
                    {
                    case 1:
                        return(new GridLength(ConvertToDouble(values[0]).Value));

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; GridLength supports only one");
                    }

                case "System.Windows.Thickness":
                    switch (values.Length)
                    {
                    case 1:
                        return(new Thickness(ConvertToDouble(values[0]).Value));

                    case 2:
                        return(new Thickness(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value, ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value));

                    case 4:
                        return(new Thickness(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value, ConvertToDouble(values[2]).Value, ConvertToDouble(values[3]).Value));

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; Thickness supports only one, two, or four");
                    }

                case "System.Windows.Rect":
                    switch (values.Length)
                    {
                    case 4:
                        return(new Rect(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value, ConvertToDouble(values[2]).Value, ConvertToDouble(values[3]).Value));

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; Rect supports only four");
                    }

                case "System.Windows.Size":
                    switch (values.Length)
                    {
                    case 2:
                        return(new Size(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value));

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; Size supports only two");
                    }

                case "System.Windows.Point":
                    switch (values.Length)
                    {
                    case 2:
                        return(new Point(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value));

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; Point supports only two");
                    }

                case "System.Boolean":
                    switch (values.Length)
                    {
                    case 1:
                        if (values[0] is string)
                        {
                            return(bool.Parse(values[0] as string));
                        }
                        return((bool?)values[0]);

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; boolean supports only one");
                    }

                case "System.String":
                    switch (values.Length)
                    {
                    case 1:
                        if (values[0] is string)
                        {
                            return(values[0]);
                        }
                        else if (values[0] == null)
                        {
                            return(null);
                        }
                        else
                        {
                            return(values[0].ToString());
                        }

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; string supports only one");
                    }

                case "System.Uri":
                    switch (values.Length)
                    {
                    case 1:
                        if (values[0] is string)
                        {
                            return(new Uri(values[0] as string));
                        }
                        else if (values[0] == null)
                        {
                            return(null);
                        }
                        else
                        {
                            return(new Uri(values[0].ToString()));
                        }

                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; Uri supports only one");
                    }

                case "System.Single":
                    convert = p => System.Convert.ToSingle(p);
                    break;

                case "System.Int32":
                    convert = p => System.Convert.ToInt32(p);
                    break;

                case "System.Int64":
                    convert = p => System.Convert.ToInt64(p);
                    break;

                case "System.Decimal":
                    convert = p => System.Convert.ToDecimal(p);
                    break;

                case "System.Byte":
                    convert = p => System.Convert.ToByte(p);
                    break;

                case "System.SByte":
                    convert = p => System.Convert.ToSByte(p);
                    break;

                case "System.Char":
                    convert = p => (char)System.Convert.ToInt32(p);
                    break;

                case "System.Int16":
                    convert = p => System.Convert.ToInt16(p);
                    break;

                case "System.UInt16":
                    convert = p => System.Convert.ToUInt16(p);
                    break;

                case "System.UInt32":
                    convert = p => System.Convert.ToUInt32(p);
                    break;

                case "System.UInt64":
                    convert = p => System.Convert.ToUInt64(p);
                    break;

                default:
                    switch (values.Length)
                    {
                    case 1:
                        if (targetType == typeof(double?))
                        {
                            return(ConvertToDouble(values[0]));
                        }

                        if ((targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable <>)))
                        {
                            // We're supposed to return a Nullable<T> where T : struct
                            if (values[0] == null)
                            {
                                return(null);
                            }
                            else
                            {
                                return(System.Convert.ChangeType(values[0], targetType.GetGenericArguments()[0]));
                            }
                        }

                        return(System.Convert.ChangeType(values[0], targetType));

                    //throw new NotSupportedException(string.Format("You cannot convert to a {0}", targetType.Name));
                    default:
                        throw new NotSupportedException($"You supplied {values.Length} values; {targetType.FullName} supports only one");
                    }
                }
                switch (values.Length)
                {
                case 1:
                    var value = values[0];
                    if (value == null)
                    {
                        return(null);
                    }
                    else
                    {
                        return(convert(ConvertToDouble(value).Value));
                    }

                default:
                    throw new NotSupportedException($"You supplied {values.Length} values; {targetType.FullName} supports only one");
                }
            }
            else
            {
                throw new ArgumentException("The Converter Parameter must be a string.", "parameter");
            }
        }
コード例 #4
0
        private AbstractSyntaxTree Primary()
        {
            var t = scanner.GetToken();

            switch (t.TokenType)
            {
            case TokenType.Number:
                return(new ConstantNumberNode(double.Parse((t as LexicalToken).Lex, NumberStyles.Number, CultureInfo.InvariantCulture)));

            case TokenType.Minus:
                return(new NegativeNode(Primary()));

            case TokenType.Not:
                return(new NotNode(Primary()));

            case TokenType.X:
                return(new VariableNode(0));

            case TokenType.Y:
                return(new VariableNode(1));

            case TokenType.Z:
                return(new VariableNode(2));

            case TokenType.String:
                return(new StringNode((t as LexicalToken).Lex));

            case TokenType.Lexical:
                var                                 lex      = (t as LexicalToken).Lex;
                Func <object>                       formula0 = null;
                Func <double, double>               formula1 = null;
                Func <object, object, object>       formula2 = null;
                Func <IEnumerable <object>, object> formulaN = null;
                switch (lex)
                {
                case "null":
                    return(new NullNode());

                case "NOW":
                case "Now":
                case "now":
                    formula0 = () => DateTime.Now;
                    break;

                case "COS":
                case "Cos":
                case "cos":
                    formula1 = Math.Cos;
                    break;

                case "SIN":
                case "Sin":
                case "sin":
                    formula1 = Math.Sin;
                    break;

                case "TAN":
                case "Tan":
                case "tan":
                    formula1 = Math.Tan;
                    break;

                case "ABS":
                case "Abs":
                case "abs":
                    formula1 = Math.Abs;
                    break;

                case "ACOS":
                case "ACos":
                case "Acos":
                case "acos":
                case "ARCCOS":
                case "ArcCos":
                case "Arccos":
                case "arccos":
                    formula1 = Math.Acos;
                    break;

                case "ASIN":
                case "ASin":
                case "Asin":
                case "asin":
                case "ARCSIN":
                case "ArcSin":
                case "Arcsin":
                case "arcsin":
                    formula1 = Math.Asin;
                    break;

                case "ATAN":
                case "ATan":
                case "Atan":
                case "atan":
                case "ARCTAN":
                case "ArcTan":
                case "Arctan":
                case "arctan":
                    formula1 = Math.Atan;
                    break;

                case "CEIL":
                case "Ceil":
                case "ceil":
                case "CEILING":
                case "Ceiling":
                case "ceiling":
                    formula1 = Math.Ceiling;
                    break;

                case "FLOOR":
                case "Floor":
                case "floor":
                    formula1 = Math.Floor;
                    break;

                case "SQRT":
                case "Sqrt":
                case "sqrt":
                    formula1 = Math.Sqrt;
                    break;

                case "DEGREES":
                case "Degrees":
                case "degrees":
                case "DEG":
                case "Deg":
                case "deg":
                    formula1 = x => x / Math.PI * 180;
                    break;

                case "RADIANS":
                case "Radians":
                case "radians":
                case "RAD":
                case "Rad":
                case "rad":
                    formula1 = x => x / 180 * Math.PI;
                    break;

                case "ROUND":
                case "Round":
                case "round":
                    formula2 = (x, y) =>
                    {
                        var a = MathConverter.ConvertToDouble(x);
                        var b = MathConverter.ConvertToDouble(y);
                        if (a.HasValue && b.HasValue)
                        {
                            if (b.Value == (int)b.Value)
                            {
                                return(Math.Round(a.Value, (int)b.Value));
                            }
                            else
                            {
                                throw new Exception(string.Format("Error calling Math.Round({0}, {1}):\r\n{1} is not an integer.", a, y));
                            }
                        }
                        else
                        {
                            return(null);
                        }
                    };
                    break;

                case "ATAN2":
                case "ATan2":
                case "Atan2":
                case "atan2":
                case "ARCTAN2":
                case "ArcTan2":
                case "Arctan2":
                case "arctan2":
                    formula2 = (x, y) =>
                    {
                        var a = MathConverter.ConvertToDouble(x);
                        var b = MathConverter.ConvertToDouble(y);
                        if (a.HasValue && b.HasValue)
                        {
                            return(Math.Atan2(a.Value, b.Value));
                        }
                        else
                        {
                            return(null);
                        }
                    };
                    break;

                case "LOG":
                case "Log":
                case "log":
                    formula2 = (x, y) =>
                    {
                        var a = MathConverter.ConvertToDouble(x);
                        var b = MathConverter.ConvertToDouble(y);
                        if (a.HasValue && b.HasValue)
                        {
                            return(Math.Log(a.Value, b.Value));
                        }
                        else
                        {
                            return(null);
                        }
                    };

                    break;

                case "ISNULL":
                case "IsNull":
                case "Isnull":
                case "isnull":
                case "IFNULL":
                case "IfNull":
                case "Ifnull":
                case "ifnull":
                    formula2 = (x, y) => ReferenceEquals(x, null) ? y : x;
                    break;

                case "AND":
                case "And":
                case "and":
                    formulaN = FormulaNodeN.And;
                    break;

                case "NOR":
                case "Nor":
                case "nor":
                    formulaN = FormulaNodeN.Nor;
                    break;

                case "OR":
                case "Or":
                case "or":
                    formulaN = FormulaNodeN.Or;
                    break;

                case "MAX":
                case "Max":
                case "max":
                    formulaN = FormulaNodeN.Max;
                    break;

                case "MIN":
                case "Min":
                case "min":
                    formulaN = FormulaNodeN.Min;
                    break;

                case "AVG":
                case "Avg":
                case "avg":
                case "AVERAGE":
                case "Average":
                case "average":
                    formulaN = FormulaNodeN.Average;
                    break;

                case "PI":
                case "pi":
                    return(new ConstantNumberNode(Math.PI));

                case "E":
                case "e":
                    return(new ConstantNumberNode(Math.E));

                case "FORMAT":
                case "Format":
                case "format":
                    formulaN = FormulaNodeN.Format;
                    break;

                default:
                    var err = lex + " is an invalid formula name";
                    throw new ParsingException(scanner.Position, err, new NotSupportedException(err));
                }

                if (formula0 != null)
                {
                    var ex = lex + " is a formula that takes zero arguments. You must call it like this: \"" + lex + "()\"";

                    if (scanner.GetToken().TokenType != TokenType.LParen)
                    {
                        throw new ParsingException(scanner.Position, ex);
                    }
                    if (scanner.GetToken().TokenType != TokenType.RParen)
                    {
                        throw new ParsingException(scanner.Position, ex);
                    }

                    return(new FormulaNode0(lex, formula0));
                }
                else if (formula1 != null)
                {
                    // Create a formula1.
                    var ex = lex + " is a formula that takes one argument.  You must specify the arguments like this: \"" + lex + "(3)\"";

                    if (scanner.GetToken().TokenType != TokenType.LParen)
                    {
                        throw new ParsingException(scanner.Position, ex);
                    }

                    AbstractSyntaxTree arg;

                    try
                    {
                        arg = Conditional();
                    }
                    catch (Exception e)
                    {
                        throw new ParsingException(scanner.Position, ex, new Exception(ex, e));
                    }

                    if (scanner.GetToken().TokenType != TokenType.RParen)
                    {
                        throw new ParsingException(scanner.Position, ex);
                    }

                    return(new FormulaNode1(lex, formula1, arg));
                }
                else if (formula2 != null)
                {
                    // Create a formula2.
                    var ex = lex + " is a formula that takes two arguments.  You must specify the arguments like this: \"" + lex + "(3;2)\"";
                    if (lex == "round")
                    {
                        ex = "round is a formula that takes one or two argments. You must specify the argument(s) like this: round(4.693) or round(4.693;2)";
                    }

                    if (scanner.GetToken().TokenType != TokenType.LParen)
                    {
                        throw new ParsingException(scanner.Position, ex);
                    }

                    AbstractSyntaxTree arg1, arg2;

                    try
                    {
                        arg1 = Conditional();
                    }
                    catch (Exception inner)
                    {
                        throw new ParsingException(scanner.Position, ex, inner);
                    }

                    switch (scanner.GetToken().TokenType)
                    {
                    case TokenType.Semicolon:
                        try
                        {
                            arg2 = Conditional();
                        }
                        catch (Exception inner)
                        {
                            throw new ParsingException(scanner.Position, ex, inner);
                        }

                        if (scanner.GetToken().TokenType == TokenType.RParen)
                        {
                            return(new FormulaNode2(lex, formula2, arg1, arg2));
                        }

                        break;

                    case TokenType.RParen:
                        if (lex == "round")
                        {
                            return(new FormulaNode2(lex, formula2, arg1, new ConstantNumberNode(0)));
                        }
                        break;
                    }
                    throw new ParsingException(scanner.Position, ex);
                }
                else
                {
                    // Create a formulaN.
                    if (scanner.GetToken().TokenType != TokenType.LParen)
                    {
                        throw new ParsingException(scanner.Position, "You must specify arguments for " + lex + ".  Those arguments must be enclosed in parentheses.");
                    }

                    var trees = new List <AbstractSyntaxTree>();

                    if (scanner.GetToken().TokenType == TokenType.RParen)
                    {
                        throw new ParsingException(scanner.Position, "You must specify at least one argument for " + lex + ".");
                    }
                    else
                    {
                        scanner.PutBackToken();
                    }

                    while (true)
                    {
                        try
                        {
                            trees.Add(Conditional());
                        }
                        catch (Exception e)
                        {
                            throw new ParsingException(scanner.Position, "Error parsing arguments for " + lex + ".", e);
                        }

                        var type = scanner.GetToken().TokenType;
                        switch (type)
                        {
                        case TokenType.RParen:
                            return(new FormulaNodeN(lex, formulaN, trees));

                        case TokenType.Semicolon:
                            break;

                        default:
                            throw new ParsingException(scanner.Position, "Error parsing arguments for " + lex + ". Invalid character: " + type + ". Expected either a comma, semicolon, or right parenthesis.");
                        }
                    }
                }

            case TokenType.LBracket:
                t = scanner.GetToken();
                var exc = new Exception("Variable accessors should come in the form [i], where i is an integer.");
                int i;
                if (t is LexicalToken)
                {
                    if (int.TryParse((t as LexicalToken).Lex, out i))
                    {
                        try
                        {
                            return(new VariableNode(i));
                        }
                        finally
                        {
                            if (scanner.GetToken().TokenType != TokenType.RBracket)
                            {
                                throw new ParsingException(scanner.Position, exc.Message, exc);
                            }
                        }
                    }
                }
                throw exc;

            case TokenType.LParen:
                var cond = Conditional();
                if (scanner.GetToken().TokenType != TokenType.RParen)
                {
                    throw new ParsingException(scanner.Position, "Mismatching parentheses");
                }

                return(cond);

            default:
                throw new ParsingException(scanner.Position, "Invalid conversion string.");
            }
        }
コード例 #5
0
ファイル: Parser.cs プロジェクト: ShineMissl/MathConverter
        private AbstractSyntaxTree Primary()
        {
            var t = scanner.GetToken();

            switch (t.TokenType)
            {
            case TokenType.Number:
                return(new ConstantNumberNode(double.Parse((t as LexicalToken).Lex, NumberStyles.Number, CultureInfo.InvariantCulture)));

            case TokenType.Minus:
                return(new NegativeNode(Primary()));

            case TokenType.Not:
                return(new NotNode(Primary()));

            case TokenType.X:
                return(new VariableNode(0));

            case TokenType.Y:
                return(new VariableNode(1));

            case TokenType.Z:
                return(new VariableNode(2));

            case TokenType.String:
                return(new StringNode((t as LexicalToken).Lex));

            case TokenType.InterpolatedString:
                var token = t as InterpolatedStringToken;
                return(new FormulaNodeN("Format", FormulaNodeN.Format, new AbstractSyntaxTree[] { new StringNode(token.Lex) }.Union(token.Arguments)));

            case TokenType.Lexical:
                var                                 lex          = (t as LexicalToken).Lex;
                Func <object>                       formula0     = null;
                Func <double, double>               formula1     = null;
                Func <object, object>               formula1_obj = null;
                Func <object, object, object>       formula2     = null;
                Func <IEnumerable <object>, object> formulaN     = null;
                switch (lex.ToLower())
                {
                case "null":
                    return(new NullNode());

                case "true":
                    return(new ValueNode(true));

                case "false":
                    return(new ValueNode(false));

                default:
                    switch (lex.ToLower())
                    {
                    case "now":
                        formula0 = () => DateTime.Now;
                        break;

                    case "cos":
                        formula1 = Math.Cos;
                        break;

                    case "sin":
                        formula1 = Math.Sin;
                        break;

                    case "tan":
                        formula1 = Math.Tan;
                        break;

                    case "abs":
                        formula1 = Math.Abs;
                        break;

                    case "acos":
                    case "arccos":
                        formula1 = Math.Acos;
                        break;

                    case "asin":
                    case "arcsin":
                        formula1 = Math.Asin;
                        break;

                    case "atan":
                    case "arctan":
                        formula1 = Math.Atan;
                        break;

                    case "ceil":
                    case "ceiling":
                        formula1 = Math.Ceiling;
                        break;

                    case "floor":
                        formula1 = Math.Floor;
                        break;

                    case "sqrt":
                        formula1 = Math.Sqrt;
                        break;

                    case "degrees":
                    case "deg":
                        formula1 = x => x / Math.PI * 180;
                        break;

                    case "radians":
                    case "rad":
                        formula1 = x => x / 180 * Math.PI;
                        break;

                    case "tolower":
                    case "lcase":
                        formula1_obj = x => x == null ? null : $"{x}".ToLowerInvariant();
                        break;

                    case "toupper":
                    case "ucase":
                        formula1_obj = x => x == null ? null : $"{x}".ToUpperInvariant();
                        break;

                    case "round":
                        formula2 = (x, y) =>
                        {
                            var a = MathConverter.ConvertToDouble(x);
                            var b = MathConverter.ConvertToDouble(y);
                            if (a.HasValue && b.HasValue)
                            {
                                if (b.Value == (int)b.Value)
                                {
                                    return(Math.Round(a.Value, (int)b.Value));
                                }
                                else
                                {
                                    throw new Exception(string.Format("Error calling Math.Round({0}, {1}):\r\n{1} is not an integer.", a, y));
                                }
                            }
                            else
                            {
                                return(null);
                            }
                        };
                        break;

                    case "atan2":
                    case "arctan2":
                        formula2 = (x, y) =>
                        {
                            var a = MathConverter.ConvertToDouble(x);
                            var b = MathConverter.ConvertToDouble(y);
                            if (a.HasValue && b.HasValue)
                            {
                                return(Math.Atan2(a.Value, b.Value));
                            }
                            else
                            {
                                return(null);
                            }
                        };
                        break;

                    case "log":
                        formula2 = (x, y) =>
                        {
                            var a = MathConverter.ConvertToDouble(x);
                            var b = MathConverter.ConvertToDouble(y);
                            if (a.HasValue && b.HasValue)
                            {
                                return(Math.Log(a.Value, b.Value));
                            }
                            else
                            {
                                return(null);
                            }
                        };
                        break;

                    case "isnull":
                    case "ifnull":
                        formula2 = (x, y) => ReferenceEquals(x, null) ? y : x;
                        break;

                    case "and":
                        formulaN = FormulaNodeN.And;
                        break;

                    case "nor":
                        formulaN = FormulaNodeN.Nor;
                        break;

                    case "or":
                        formulaN = FormulaNodeN.Or;
                        break;

                    case "max":
                        formulaN = FormulaNodeN.Max;
                        break;

                    case "min":
                        formulaN = FormulaNodeN.Min;
                        break;

                    case "avg":
                    case "average":
                        formulaN = FormulaNodeN.Average;
                        break;

                    case "pi":
                        return(new ConstantNumberNode(Math.PI));

                    case "e":
                        return(new ConstantNumberNode(Math.E));

                    case "format":
                        formulaN = FormulaNodeN.Format;
                        break;

                    case "concat":
                        formulaN = FormulaNodeN.Concat;
                        break;

                    case "join":
                        formulaN = FormulaNodeN.Join;
                        break;

                    case "contains":
                        formula2 = (x, y) =>
                        {
                            if (x is IEnumerable <dynamic> )
                            {
                                return((x as IEnumerable <dynamic>).Contains(y));
                            }
                            else if (x is string)
                            {
                                return((x as string).Contains(y as dynamic));
                            }
                            else
                            {
                                return(null);
                            }
                        };
                        break;

                    default:
                        var err = $"{lex} is an invalid formula name";
                        throw new ParsingException(scanner.Position, err, new NotSupportedException(err));
                    }
                    break;
                }

                if (formula0 != null)
                {
                    var ex = $"{lex} is a formula that takes zero arguments. You must call it like this: \"{lex}()\"";

                    if (scanner.GetToken().TokenType != TokenType.LParen)
                    {
                        throw new ParsingException(scanner.Position, ex);
                    }
                    if (scanner.GetToken().TokenType != TokenType.RParen)
                    {
                        throw new ParsingException(scanner.Position, ex);
                    }

                    return(new FormulaNode0(lex, formula0));
                }
                else if (formula1 != null || formula1_obj != null)
                {
                    // Create a formula1.
                    var ex = $"{lex} is a formula that takes one argument.  You must specify the arguments like this: \"{lex}(3)\"";

                    if (scanner.GetToken().TokenType != TokenType.LParen)
                    {
                        throw new ParsingException(scanner.Position, ex);
                    }

                    AbstractSyntaxTree arg;

                    try
                    {
                        arg = Conditional();
                    }
                    catch (Exception e)
                    {
                        throw new ParsingException(scanner.Position, ex, new Exception(ex, e));
                    }

                    if (scanner.GetToken().TokenType != TokenType.RParen)
                    {
                        throw new ParsingException(scanner.Position, ex);
                    }

                    if (formula1 != null)
                    {
                        formula1_obj = x =>
                        {
                            var val = MathConverter.ConvertToDouble(x);
                            if (val.HasValue)
                            {
                                return(formula1(val.Value));
                            }
                            else
                            {
                                return(null);
                            }
                        };
                    }

                    return(new FormulaNode1(lex, formula1_obj, arg));
                }
                else if (formula2 != null)
                {
                    // Create a formula2.
                    var ex = $"{lex} is a formula that takes two argument.  You must specify the arguments like this: \"{lex}(3;2)\"";
                    if (lex.ToLower() == "round")
                    {
                        ex = "round is a formula that takes one or two argments. You must specify the argument(s) like this: round(4.693) or round(4.693;2)";
                    }

                    if (scanner.GetToken().TokenType != TokenType.LParen)
                    {
                        throw new ParsingException(scanner.Position, ex);
                    }

                    AbstractSyntaxTree arg1, arg2;

                    try
                    {
                        arg1 = Conditional();
                    }
                    catch (Exception inner)
                    {
                        throw new ParsingException(scanner.Position, ex, inner);
                    }

                    switch (scanner.GetToken().TokenType)
                    {
                    case TokenType.Semicolon:
                        try
                        {
                            arg2 = Conditional();
                        }
                        catch (Exception inner)
                        {
                            throw new ParsingException(scanner.Position, ex, inner);
                        }

                        if (scanner.GetToken().TokenType == TokenType.RParen)
                        {
                            return(new FormulaNode2(lex, formula2, arg1, arg2));
                        }

                        break;

                    case TokenType.RParen:
                        if (lex.ToLower() == "round")
                        {
                            return(new FormulaNode2(lex, formula2, arg1, new ConstantNumberNode(0)));
                        }
                        break;
                    }
                    throw new ParsingException(scanner.Position, ex);
                }
                else
                {
                    // Create a formulaN.
                    if (scanner.GetToken().TokenType != TokenType.LParen)
                    {
                        throw new ParsingException(scanner.Position, $"You must specify arguments for {lex}.  Those arguments must be enclosed in parentheses.");
                    }

                    var trees = new List <AbstractSyntaxTree>();

                    if (scanner.GetToken().TokenType == TokenType.RParen)
                    {
                        throw new ParsingException(scanner.Position, $"You must specify at least one argument for {lex}.");
                    }
                    else
                    {
                        scanner.PutBackToken();
                    }

                    while (true)
                    {
                        try
                        {
                            trees.Add(Conditional());
                        }
                        catch (Exception e)
                        {
                            throw new ParsingException(scanner.Position, $"Error parsing arguments for {lex}.", e);
                        }

                        var type = scanner.GetToken().TokenType;
                        switch (type)
                        {
                        case TokenType.RParen:
                            return(new FormulaNodeN(lex, formulaN, trees));

                        case TokenType.Semicolon:
                            break;

                        default:
                            throw new ParsingException(scanner.Position, $"Error parsing arguments for {lex}. Invalid character: {type}. Expected either a comma, semicolon, or right parenthesis.");
                        }
                    }
                }

            case TokenType.LBracket:
                t = scanner.GetToken();
                var exc = new Exception("Variable accessors should come in the form [i], where i is an integer.");
                int i;
                if (t is LexicalToken)
                {
                    if (int.TryParse((t as LexicalToken).Lex, out i))
                    {
                        try
                        {
                            return(new VariableNode(i));
                        }
                        finally
                        {
                            if (scanner.GetToken().TokenType != TokenType.RBracket)
                            {
                                throw new ParsingException(scanner.Position, exc.Message, exc);
                            }
                        }
                    }
                }
                throw exc;

            case TokenType.LParen:
                var cond = Conditional();
                if (scanner.GetToken().TokenType != TokenType.RParen)
                {
                    throw new ParsingException(scanner.Position, "Mismatching parentheses");
                }

                return(cond);

            default:
                throw new ParsingException(scanner.Position, "Invalid conversion string.");
            }
        }
コード例 #6
0
ファイル: Parser.cs プロジェクト: jaelys/MathConverter-1
        private AbstractSyntaxTree Primary()
        {
            var t = scanner.GetToken();

            switch (t.TokenType)
            {
            case TokenType.Number:
                return(new ConstantNumberNode(double.Parse((t as LexicalToken).Lex, NumberStyles.Number, CultureInfo.InvariantCulture)));

            case TokenType.Minus:
                return(new NegativeNode(Primary()));

            case TokenType.Not:
                return(new NotNode(Primary()));

            case TokenType.X:
                return(new VariableNode(0));

            case TokenType.Y:
                return(new VariableNode(1));

            case TokenType.Z:
                return(new VariableNode(2));

            case TokenType.String:
                return(new StringNode((t as LexicalToken).Lex));

            case TokenType.InterpolatedString:
                var token = t as InterpolatedStringToken;
                return(new FormulaNodeN("Format", FormulaNodeN.Format, new AbstractSyntaxTree[] { new StringNode(token.Lex) }.Union(token.Arguments)));

            case TokenType.Lexical:
                var                                 lex          = (t as LexicalToken).Lex;
                Func <object>                       formula0     = null;
                Func <double, double>               formula1     = null;
                Func <object, object>               formula1_obj = null;
                Func <object, object, object>       formula2     = null;
                Func <IEnumerable <object>, object> formulaN     = null;
                switch (lex.ToLower())
                {
                case "null":
                    return(new NullNode());

                case "pi":
                    return(new ConstantNumberNode(Math.PI));

                case "e":
                    return(new ConstantNumberNode(Math.E));

                case "true":
                    return(new ValueNode(true));

                case "false":
                    return(new ValueNode(false));

                default:
                    switch (lex.ToLower())
                    {
                    case "now":
                        formula0 = () => DateTime.Now;
                        break;

                    case "cos":
                        formula1 = Math.Cos;
                        break;

                    case "sin":
                        formula1 = Math.Sin;
                        break;

                    case "tan":
                        formula1 = Math.Tan;
                        break;

                    case "abs":
                        formula1 = Math.Abs;
                        break;

                    case "acos":
                    case "arccos":
                        formula1 = Math.Acos;
                        break;

                    case "asin":
                    case "arcsin":
                        formula1 = Math.Asin;
                        break;

                    case "atan":
                    case "arctan":
                        formula1 = Math.Atan;
                        break;

                    case "ceil":
                    case "ceiling":
                        formula1 = Math.Ceiling;
                        break;

                    case "floor":
                        formula1 = Math.Floor;
                        break;

                    case "sqrt":
                        formula1 = Math.Sqrt;
                        break;

                    case "degrees":
                    case "deg":
                        formula1 = x => x / Math.PI * 180;
                        break;

                    case "radians":
                    case "rad":
                        formula1 = x => x / 180 * Math.PI;
                        break;

                    case "tolower":
                    case "lcase":
                        formula1_obj = x => x == null ? null : $"{x}".ToLowerInvariant();
                        break;

                    case "toupper":
                    case "ucase":
                        formula1_obj = x => x == null ? null : $"{x}".ToUpperInvariant();
                        break;

                    case "startswith":
                        formula2 = (x, y) => x is string str1 && (y is string || y?.ToString().Length > 0) ? str1.StartsWith($"{y}") : new bool?();
                        break;

                    case "endswith":
                        formula2 = (x, y) => x is string str1 && (y is string || y?.ToString().Length > 0) ? str1.EndsWith($"{y}") : new bool?();
                        break;

                    case "visibleorcollapsed":
                        formula1_obj = x => x is bool && (bool)x == true ? Visibility.Visible : Visibility.Collapsed;
                        break;

                    case "visibleorhidden":
                        formula1_obj = x => x is bool && (bool)x == true ? Visibility.Visible : Visibility.Hidden;
                        break;

                    case "round":
                        formula2 = (x, y) =>
                        {
                            var a = MathConverter.ConvertToDouble(x);
                            var b = MathConverter.ConvertToDouble(y);
                            if (a.HasValue && b.HasValue)
                            {
                                if (b.Value == (int)b.Value)
                                {
                                    return(Math.Round(a.Value, (int)b.Value));
                                }
                                else
                                {
                                    throw new Exception($"Error calling Math.Round({a}, {y}):\r\n{y} is not an integer.");
                                }
                            }
                            else
                            {
                                return(null);
                            }
                        };
                        break;

                    case "atan2":
                    case "arctan2":
                        formula2 = (x, y) =>
                        {
                            var a = MathConverter.ConvertToDouble(x);
                            var b = MathConverter.ConvertToDouble(y);
                            if (a.HasValue && b.HasValue)
                            {
                                return(Math.Atan2(a.Value, b.Value));
                            }
                            else
                            {
                                return(null);
                            }
                        };
                        break;

                    case "log":
                        formula2 = (x, y) =>
                        {
                            var a = MathConverter.ConvertToDouble(x);
                            var b = MathConverter.ConvertToDouble(y);
                            if (a.HasValue && b.HasValue)
                            {
                                return(Math.Log(a.Value, b.Value));
                            }
                            else
                            {
                                return(null);
                            }
                        };
                        break;

                    case "isnull":
                    case "ifnull":
                        formula2 = (x, y) => ReferenceEquals(x, null) ? y : x;
                        break;

                    case "and":
                        formulaN = FormulaNodeN.And;
                        break;

                    case "nor":
                        formulaN = FormulaNodeN.Nor;
                        break;

                    case "or":
                        formulaN = FormulaNodeN.Or;
                        break;

                    case "max":
                        formulaN = FormulaNodeN.Max;
                        break;

                    case "min":
                        formulaN = FormulaNodeN.Min;
                        break;

                    case "avg":
                    case "average":
                        formulaN = FormulaNodeN.Average;
                        break;

                    case "format":
                        formulaN = FormulaNodeN.Format;
                        break;

                    case "concat":
                        formulaN = FormulaNodeN.Concat;
                        break;

                    case "join":
                        formulaN = FormulaNodeN.Join;
                        break;

                    case "contains":
                        formula2 = (x, y) =>
                        {
                            if (x is IEnumerable <dynamic> )
                            {
                                return((x as IEnumerable <dynamic>).Contains(y));
                            }
                            else if (x is string str1 && (y is string || $"{y}".Length > 0))
                            {
                                return(str1.Contains($"{y}"));
                            }
コード例 #7
0
        /// <summary>
        /// The actual convert method, for zero or more parameters.
        /// </summary>
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (parameter is string)
            {
                // Get the parameter
                var param = parameter is string?parameter as string : parameter.ToString();

                // Get the syntax tree from the expression.  We will cache the results to save time for future parsing of the same expression
                // by the same MathConverter.
                var x = ParseParameter(param);

                switch (targetType.FullName)
                {
                case "System.Object":
                    switch (x.Length)
                    {
                    case 1:
                        return(x[0].Evaluate(values));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; Double supports only one", x.Length));
                    }

                case "System.Double":
                    switch (x.Length)
                    {
                    case 1:
                        return(MathConverter.ConvertToDouble(x[0].Evaluate(values)));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; Double supports only one", x.Length));
                    }

                case "System.Windows.CornerRadius":
                    switch (x.Length)
                    {
                    case 1:
                        return(new CornerRadius(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value));

                    case 4:
                        return(new CornerRadius(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[2].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[3].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; CornerRadius supports only one or four", x.Length));
                    }

                case "System.Windows.GridLength":
                    switch (x.Length)
                    {
                    case 1:
                        return(new GridLength(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; GridLength supports only one", x.Length));
                    }

                case "System.Windows.Thickness":
                    switch (x.Length)
                    {
                    case 1:
                        return(new Thickness(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value));

                    case 2:
                        return(new Thickness(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value));

                    case 4:
                        return(new Thickness(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[2].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[3].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; Thickness supports only one, two, or four", x.Length));
                    }

                case "System.Windows.Rect":
                    switch (x.Length)
                    {
                    case 4:
                        return(new Rect(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[2].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[3].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; Rect supports only four", x.Length));
                    }

                case "System.Windows.Size":
                    switch (x.Length)
                    {
                    case 2:
                        return(new Size(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; Size supports only two", x.Length));
                    }

                case "System.Windows.Point":
                    switch (x.Length)
                    {
                    case 2:
                        return(new Point(MathConverter.ConvertToDouble(x[0].Evaluate(values)).Value, MathConverter.ConvertToDouble(x[1].Evaluate(values)).Value));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; Point supports only two", x.Length));
                    }

                case "System.Boolean":
                    switch (x.Length)
                    {
                    case 1:
                        return((bool?)x[0].Evaluate(values));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; Boolean supports only one", x.Length));
                    }

                case "System.String":
                    switch (x.Length)
                    {
                    case 1:
                        var val = x[0].Evaluate(values);
                        if (val is string)
                        {
                            return(val);
                        }
                        else if (val == null)
                        {
                            return(null);
                        }
                        else
                        {
                            return(val.ToString());
                        }

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; string supports only one", x.Length));
                    }

                default:
                    if (targetType == typeof(double?))
                    {
                        return(MathConverter.ConvertToDouble(x[0].Evaluate(values)));
                    }

                    // We don't know what to return, so let's just evaluate the parameter and return what it returns.
                    return(x[0].Evaluate(values));    //throw new NotSupportedException(string.Format("You cannot convert to a {0}", targetType.Name));
                }
            }
            else if (parameter == null)
            {
                switch (targetType.FullName)
                {
                case "System.Object":
                    switch (values.Length)
                    {
                    case 1:
                        return(ConvertToObject(values[0]));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; Object supports only one", values.Length));
                    }

                case "System.Double":
                    switch (values.Length)
                    {
                    case 1:
                        return(ConvertToDouble(values[0]));

                    default:
                        throw new NotSupportedException(string.Format("The parameter specifies {0} values; Double supports only one", values.Length));
                    }

                case "System.Windows.CornerRadius":
                    switch (values.Length)
                    {
                    case 1:
                        return(new CornerRadius(ConvertToDouble(values[0]).Value));

                    case 4:
                        return(new CornerRadius(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value, ConvertToDouble(values[2]).Value, ConvertToDouble(values[3]).Value));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; CornerRadius supports only one or four", values.Length));
                    }

                case "System.Windows.GridLength":
                    switch (values.Length)
                    {
                    case 1:
                        return(new GridLength(ConvertToDouble(values[0]).Value));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; GridLength supports only one", values.Length));
                    }

                case "System.Windows.Thickness":
                    switch (values.Length)
                    {
                    case 1:
                        return(new Thickness(ConvertToDouble(values[0]).Value));

                    case 2:
                        return(new Thickness(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value, ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value));

                    case 4:
                        return(new Thickness(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value, ConvertToDouble(values[2]).Value, ConvertToDouble(values[3]).Value));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; Thickness supports only one, two, or four", values.Length));
                    }

                case "System.Windows.Rect":
                    switch (values.Length)
                    {
                    case 4:
                        return(new Rect(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value, ConvertToDouble(values[2]).Value, ConvertToDouble(values[3]).Value));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; Rect supports only four", values.Length));
                    }

                case "System.Windows.Size":
                    switch (values.Length)
                    {
                    case 2:
                        return(new Size(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; Size supports only two", values.Length));
                    }

                case "System.Windows.Point":
                    switch (values.Length)
                    {
                    case 2:
                        return(new Point(ConvertToDouble(values[0]).Value, ConvertToDouble(values[1]).Value));

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; Point supports only two", values.Length));
                    }

                case "System.Boolean":
                    switch (values.Length)
                    {
                    case 1:
                        return((bool?)values[0]);

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; Boolean supports only one", values.Length));
                    }

                case "System.String":
                    switch (values.Length)
                    {
                    case 1:
                        if (values[0] is string)
                        {
                            return(values[0]);
                        }
                        else if (values[0] == null)
                        {
                            return(null);
                        }
                        else
                        {
                            return(values[0].ToString());
                        }

                    default:
                        throw new NotSupportedException(string.Format("You supplied {0} values; string supports only one", values.Length));
                    }

                default:
                    if (targetType == typeof(double?))
                    {
                        return(ConvertToDouble(values[0]));
                    }

                    throw new NotSupportedException(string.Format("You cannot convert to a {0}", targetType.Name));
                }
            }
            else
            {
                throw new ArgumentException("The Converter Parameter must be a string.", "parameter");
            }
        }