示例#1
0
        /// <summary>
        /// Deserialize a json using a StringScanner and returns BsonValue
        /// </summary>
        public static BsonValue Deserialize(StringScanner s)
        {
            if (s == null) throw new ArgumentNullException("s");

            if (s.HasTerminated) return BsonValue.Null;

            using (var sr = new StringReader(s.ToString()))
            {
                var reader = new JsonReader(sr);

                var value = reader.Deserialize();

                s.Seek((int)(reader.Position - 1));

                return value;
            }
        }
示例#2
0
        /// <summary>
        /// Parse and compile an expression from a stringscanner. Must define if will read a path only or support for full expression. Can parse only arithmetic (+/-/*/..) or full logic operators (=/!=/>/...)
        /// </summary>
        private static Func <BsonDocument, BsonValue, IEnumerable <BsonValue> > Compile(StringScanner s, bool pathOnly, bool arithmeticOnly)
        {
            var        isRoot  = pathOnly;
            var        root    = Expression.Parameter(typeof(BsonDocument), "root");
            var        current = Expression.Parameter(typeof(BsonValue), "current");
            Expression expr;

            if (pathOnly)
            {
                // if read path, read first expression only
                // support missing $ as root
                s.Scan(@"\$\.?");
                expr = ParseSingleExpression(s, root, current, true);
            }
            else
            {
                // read all expression (a + b)
                // if include operator, support = > < && || too
                expr = ParseExpression(s, root, current, arithmeticOnly);
            }

            var lambda = Expression.Lambda <Func <BsonDocument, BsonValue, IEnumerable <BsonValue> > >(expr, root, current);

            return(lambda.Compile());
        }
示例#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+"));
                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+"));
                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.Match(@"\w+\s*\(")) // read function
            {
                // get static method from this class
                var name       = s.Scan(@"(\w+)\s*\(", 1).ToUpper();
                var method     = typeof(BsonExpression).GetMethod(name);
                var parameters = new List <Expression>();

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

                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);
                }

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

            throw LiteException.SyntaxError(s);
        }
示例#4
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+"));
                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+"));
                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("(.+?):", 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);
        }