Beispiel #1
0
        /// <summary>
        /// Implement a JSON-Path like navigation on BsonDocument. Support a simple range of paths
        /// </summary>
        private static Expression ParsePath(StringScanner s, Expression expr, ParameterExpression root)
        {
            if (s.Match(@"\.[\$\-\w]+"))
            {
                var method = typeof(BsonExpression).GetMethod("Member");
                var name   = Expression.Constant(s.Scan(@"\.([\$\-\w]+)", 1));
                return(Expression.Call(method, expr, name));
            }
            else if (s.Match(@"\["))
            {
                var method = typeof(BsonExpression).GetMethod("Array");
                var i      = s.Scan(@"\[\s*(-?[\d+\*])\s*\]", 1);
                var index  = i != "*" && i != "" ? Convert.ToInt32(i) : int.MaxValue;
                var inner  = new BsonExpression(null);

                if (i == "") // if array operation are not index based, read expression
                {
                    s.Scan(@"\[\s*");
                    // read expression with full support to all operators/formulas
                    inner = ReadExpression(s, true, false, false);
                    if (inner == null)
                    {
                        throw LiteException.SyntaxError(s, "Invalid expression formula");
                    }
                    s.Scan(@"\s*\]");
                }

                return(Expression.Call(method, expr, Expression.Constant(index), Expression.Constant(inner), root));
            }
            else
            {
                return(null);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Throw syntax exception if not terminate string
        /// </summary>
        public void ThrowIfNotFinish()
        {
            Scan(@"\s*");

            if (!HasTerminated)
            {
                throw LiteException.SyntaxError(this);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Start parse string into linq expression. Read path, function or base type bson values (int, double, bool, string)
        /// </summary>
        internal static Expression ParseSingleExpression(StringScanner s, ParameterExpression root, ParameterExpression current, bool isRoot)
        {
            if (s.Match(@"[\$@]") || isRoot)   // read root path
            {
                var r      = s.Scan(@"[\$@]"); // read root/current
                var method = typeof(BsonExpression).GetMethod("Root");
                var name   = Expression.Constant(s.Scan(@"\.?([\$\-\w]+)", 1));
                var expr   = Expression.Call(method, r == "@" ? current : root, name) as Expression;

                // parse the rest of path
                while (!s.HasTerminated)
                {
                    var result = ParsePath(s, expr, root);

                    if (result == null)
                    {
                        break;
                    }

                    expr = result;
                }

                return(expr);
            }
            else if (s.Match(@"-?\d*\.\d+")) // read double
            {
                var number = Convert.ToDouble(s.Scan(@"-?\d*\.\d+"), CultureInfo.InvariantCulture.NumberFormat);
                var value  = Expression.Constant(new BsonValue(number));

                return(Expression.NewArrayInit(typeof(BsonValue), value));
            }
            else if (s.Match(@"-?\d+")) // read int
            {
                var number = Convert.ToInt32(s.Scan(@"-?\d+"), CultureInfo.InvariantCulture.NumberFormat);
                var value  = Expression.Constant(new BsonValue(number));

                return(Expression.NewArrayInit(typeof(BsonValue), value));
            }
            else if (s.Match(@"(true|false)")) // read bool
            {
                var boolean = Convert.ToBoolean(s.Scan(@"(true|false)"));
                var value   = Expression.Constant(new BsonValue(boolean));

                return(Expression.NewArrayInit(typeof(BsonValue), value));
            }
            else if (s.Match(@"null")) // read null
            {
                var value = Expression.Constant(BsonValue.Null);

                return(Expression.NewArrayInit(typeof(BsonValue), value));
            }
            else if (s.Match(@"'")) // read string
            {
                var str   = s.Scan(@"'([\s\S]*?)'", 1);
                var value = Expression.Constant(new BsonValue(str));

                return(Expression.NewArrayInit(typeof(BsonValue), value));
            }
            else if (s.Scan(@"\{\s*").Length > 0) // read document {
            {
                // read key value
                var method = typeof(ExpressionOperators).GetMethod("DOCUMENT");
                var keys   = new List <Expression>();
                var values = new List <Expression>();

                while (!s.HasTerminated)
                {
                    // read key + value
                    var key   = s.Scan(@"(.+?)\s*:\s*", 1).ThrowIfEmpty("Invalid token", s);
                    var value = ParseExpression(s, root, current, false);

                    // add key and value to parameter list (as an expression)
                    keys.Add(Expression.Constant(new BsonValue(key)));
                    values.Add(value);

                    if (s.Scan(@"\s*,\s*").Length > 0)
                    {
                        continue;
                    }
                    else if (s.Scan(@"\s*\}\s*").Length > 0)
                    {
                        break;
                    }
                    throw LiteException.SyntaxError(s);
                }

                var arrKeys   = Expression.NewArrayInit(typeof(BsonValue), keys.ToArray());
                var arrValues = Expression.NewArrayInit(typeof(IEnumerable <BsonValue>), values.ToArray());

                return(Expression.Call(method, new Expression[] { arrKeys, arrValues }));
            }
            else if (s.Scan(@"\[\s*").Length > 0) // read array [
            {
                var method = typeof(ExpressionOperators).GetMethod("ARRAY");
                var values = new List <Expression>();

                while (!s.HasTerminated)
                {
                    // read value expression
                    var value = ParseExpression(s, root, current, false);

                    values.Add(value);

                    if (s.Scan(@"\s*,\s*").Length > 0)
                    {
                        continue;
                    }
                    else if (s.Scan(@"\s*\]\s*").Length > 0)
                    {
                        break;
                    }
                    throw LiteException.SyntaxError(s);
                }

                var arrValues = Expression.NewArrayInit(typeof(IEnumerable <BsonValue>), values.ToArray());

                return(Expression.Call(method, new Expression[] { arrValues }));
            }
            else if (s.Scan(@"\(\s*").Length > 0) // read inner (
            {
                // read a inner expression inside ( and )
                var inner = ParseExpression(s, root, current, false);

                if (s.Scan(@"\s*\)").Length == 0)
                {
                    throw LiteException.SyntaxError(s);
                }

                return(inner);
            }
            else if (s.Match(@"\w+\s*\(")) // read function
            {
                // get static method from this class
                var name       = s.Scan(@"(\w+)\s*\(", 1).ToUpper();
                var parameters = new List <Expression>();

                if (s.Scan(@"\s*\)\s*").Length == 0)
                {
                    while (!s.HasTerminated)
                    {
                        var parameter = ParseExpression(s, root, current, false);

                        parameters.Add(parameter);

                        if (s.Scan(@"\s*,\s*").Length > 0)
                        {
                            continue;
                        }
                        else if (s.Scan(@"\s*\)\s*").Length > 0)
                        {
                            break;
                        }
                        throw LiteException.SyntaxError(s);
                    }
                }

                var method = _methods.FirstOrDefault(x => x.Name == name && x.GetParameters().Count() == parameters.Count);

                if (method == null)
                {
                    throw LiteException.SyntaxError(s, "Method " + name + " not exist or invalid parameter count");
                }

                return(Expression.Call(method, parameters.ToArray()));
            }

            throw LiteException.SyntaxError(s);
        }