Beispiel #1
0
        private static TExpression ConvertFromUnknownType <TExpression>(TExpression expression, Type type)
            where TExpression : ODataExpression
        {
            // sanity check
            Throw.If(expression.Type != ODataExpressionType.Unknown, "expression: must be of unknown type");

            switch (expression.Kind)
            {
            case ODataExpressionKind.MemberAccess:
                var memberAccess = (ODataMemberAccessExpression)expression.As <ODataExpression>();
                return((TExpression)MemberAccess(memberAccess.Expression, ODataEntity.GetProperty(memberAccess.Member.Name, type)).As <ODataExpression>());

            default:
                throw Throw.UnexpectedCase(expression.Kind);
            }
        }
Beispiel #2
0
        private ODataExpression ParseSimple()
        {
            if (this.TryEat(ODataTokenKind.LeftParen))
            {
                // parse group
                var group = this.ParseExpression();
                this.Eat(ODataTokenKind.RightParen);
                return(group);
            }

            ODataToken next;

            if (this.TryEat(ODataTokenKind.Identifier, out next))
            {
                if (this.TryEat(ODataTokenKind.LeftParen))
                {
                    // parse function
                    ODataFunction function;
                    if (!Enum.TryParse(next.Text, ignoreCase: true, result: out function))
                    {
                        throw new ODataParseException(next.Text + " is not a known ODataFunction!");
                    }
                    var arguments = this.ParseExpressionList(this.ParseExpression, ODataTokenKind.Comma);
                    this.Eat(ODataTokenKind.RightParen);

                    if (function == ODataFunction.IsOf || function == ODataFunction.Cast)
                    {
                        var typeLiteral   = this.ReParseAsType(arguments[arguments.Count - 1]);
                        var argumentsCopy = arguments.ToArray();
                        argumentsCopy[arguments.Count - 1] = ODataExpression.Constant(typeLiteral);
                        arguments = argumentsCopy;
                    }

                    return(ODataExpression.Call(function, arguments));
                }

                // parse member access
                var type = this._elementType;                 // root element type
                ODataMemberAccessExpression access = null;    // root member
                while (true)
                {
                    // get the property
                    var property = typeof(ODataObject).IsAssignableFrom(type)
                        ? ODataEntity.GetProperty(next.Text, typeof(ODataObject))
                        : type.GetProperty(next.Text, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                    if (property == null)
                    {
                        throw new ODataParseException("Property '" + next.Text + "' could not be found on type " + type.FullName);
                    }
                    access = ODataExpression.MemberAccess(access, property);

                    // if we don't see '/' followed by an identifier, we're done
                    // we can't just use TryEat() here, because we need to distinguish between Foo/Bar/* and Foo/Bar/Baz
                    if (this.Next().Kind != ODataTokenKind.Slash || this.Next(2).Kind != ODataTokenKind.Identifier)
                    {
                        break;
                    }

                    // otherwise, update next to the next id and then advance type down the property chain
                    this.Eat(ODataTokenKind.Slash);
                    next = this.Eat(ODataTokenKind.Identifier);
                    type = property.PropertyType;
                }
                return(access);
            }

            // literals
            if (this.TryEat(ODataTokenKind.NullLiteral, out next))
            {
                return(ODataExpression.Constant(null));
            }
            if (this.TryEat(ODataTokenKind.BinaryLiteral, out next))
            {
                throw new NotImplementedException("Binary Literal Parse");
            }
            if (this.TryEat(ODataTokenKind.BooleanLiteral, out next))
            {
                return(ODataExpression.Constant(bool.Parse(next.Text)));
            }
            // see comment on the enum
            //if (this.TryEat(ODataTokenKind.ByteLiteral, out next))
            //{
            //	return ODataExpression.Constant(Convert.ToByte(next.Text, fromBase: 16));
            //}
            if (this.TryEat(ODataTokenKind.DateTimeLiteral, out next))
            {
                Func <string, string> zeroIfEmpty = s => s.Length == 0 ? "0" : s;
                var dateTime = new DateTime(
                    year: int.Parse(next.Match.Groups["year"].Value),
                    month: int.Parse(next.Match.Groups["month"].Value),
                    day: int.Parse(next.Match.Groups["day"].Value),
                    hour: int.Parse(next.Match.Groups["hour"].Value),
                    minute: int.Parse(next.Match.Groups["minute"].Value),
                    second: int.Parse(zeroIfEmpty(next.Match.Groups["second"].Value)),
                    millisecond: 0
                    )
                               .AddSeconds(double.Parse(zeroIfEmpty(next.Match.Groups["fraction"].Value)));
                return(ODataExpression.Constant(dateTime));
            }
            if (this.TryEat(ODataTokenKind.DecimalLiteral, out next))
            {
                return(ODataExpression.Constant(decimal.Parse(next.Text.Substring(0, next.Text.Length - 1))));
            }
            if (this.TryEat(ODataTokenKind.DoubleLiteral, out next))
            {
                return(ODataExpression.Constant(double.Parse(next.Text)));
            }
            if (this.TryEat(ODataTokenKind.SingleLiteral, out next))
            {
                return(ODataExpression.Constant(float.Parse(next.Text.Substring(0, next.Text.Length - 1))));
            }
            if (this.TryEat(ODataTokenKind.GuidLiteral, out next))
            {
                return(ODataExpression.Constant(Guid.Parse(next.Match.Groups["digits"].Value)));
            }
            if (this.TryEat(ODataTokenKind.Int32Literal, out next))
            {
                // Note: this will fail hard if we have an out-of-range int value. However, this is consistent
                // with MSFT's implementation (see http://services.odata.org/v3/odata/odata.svc/Products?$format=json&$filter=Price%20ge%202147483648)
                return(ODataExpression.Constant(int.Parse(next.Text)));
            }
            if (this.TryEat(ODataTokenKind.Int64Literal, out next))
            {
                return(ODataExpression.Constant(long.Parse(next.Text.Substring(0, next.Text.Length - 1))));
            }
            if (this.TryEat(ODataTokenKind.StringLiteral, out next))
            {
                // unescaping, from http://stackoverflow.com/questions/3979367/how-to-escape-a-single-quote-to-be-used-in-an-odata-query
                return(ODataExpression.Constant(next.Match.Groups["chars"].Value.Replace("''", "'")));
            }

            throw new ODataParseException("Unexpected token " + this.Next());
        }