예제 #1
0
        private Yytoken[] Lex(string value)
        {
            ArrayList tokens = new ArrayList();

            using (StringReader reader = new StringReader(value))
            {
                OPathLexer lexer = new OPathLexer(reader);

                Yytoken token;
                while ((token = lexer.Lex()) != null)
                {
                    tokens.Add(token);
                }
            }

            return((Yytoken[])tokens.ToArray(typeof(Yytoken)));
        }
예제 #2
0
        public OrderBy Parse(Type type, string expression)
        {
            // Example expressions for an Employee query:
            // "FirstName, LastName"
            // "FirstName ASC, LastName DESC"
            // "Company.Name"
            // "Company.Name ASC"
            // "Company.Address.State ASC"
            // "Company.Name ASC, Company.Address.State ASC, FirstName ASC"
            // "Company.Name ASC, HomeAddress.ZipCode, Company.Address.State DESC, ZipCode"

            _expression = expression;

            EntityMap entity = _maps[type];

            if (entity == null)
            {
                throw new Exception("Type " + type + " does not have an entity mapping defined to the database.");
            }

            OrderByItemCollection items = new OrderByItemCollection();
            OrderByJoinCollection joins = new OrderByJoinCollection();

            using (StringReader reader = new StringReader(expression))
            {
                OPathLexer lexer = new OPathLexer(reader);

                lexer.Lex();
                while (lexer.CurrentToken != null)
                {
                    OrderByItem item = ParseItem(lexer, entity, joins, null);
                    items.Add(item);
                }

                if (lexer.LastToken != null && lexer.LastToken.Type == TokenType.COMMA)
                {
                    throw new OPathException("A trailing comma was detected in sort expression '" + expression + "'.");
                }
            }

            return(new OrderBy(null, items, joins));
        }
예제 #3
0
        public OrderBy Parse(Type type, string expression)
        {
            // Example expressions for an Employee query:
            // "FirstName, LastName"
            // "FirstName ASC, LastName DESC"
            // "Company.Name"
            // "Company.Name ASC"
            // "Company.Address.State ASC"
            // "Company.Name ASC, Company.Address.State ASC, FirstName ASC"
            // "Company.Name ASC, HomeAddress.ZipCode, Company.Address.State DESC, ZipCode"

            _expression = expression;

            EntityMap entity = _maps[type];
            if( entity == null )
            {
                throw new Exception("Type " + type + " does not have an entity mapping defined to the database.");
            }

            OrderByItemCollection items = new OrderByItemCollection();
            OrderByJoinCollection joins = new OrderByJoinCollection();

            using( StringReader reader = new StringReader(expression) )
            {
                OPathLexer lexer = new OPathLexer(reader);

                lexer.Lex();
                while( lexer.CurrentToken != null )
                {
                    OrderByItem item = ParseItem(lexer, entity, joins, null);
                    items.Add(item);
                }

                if( lexer.LastToken != null && lexer.LastToken.Type == TokenType.COMMA )
                {
                    throw new OPathException("A trailing comma was detected in sort expression '" + expression + "'.");
                }
            }

            return new OrderBy(null, items, joins);
        }
예제 #4
0
        private OrderByItem ParseItem(OPathLexer lexer, EntityMap entity, OrderByJoinCollection joins, OrderByJoin parentJoin)
        {
            Yytoken token = lexer.CurrentToken;

            if (token.Type != TokenType.IDENT)
            {
                throw new OPathException("'" + token.Text + "' encountered where a property or relationship was expected in sort expression '" + _expression + "'.");
            }

            string propertyName = token.Text;

            token = lexer.Lex();
            if (token == null)
            {
                FieldMap field;
                try
                {
                    field = entity.GetFieldMap(propertyName);
                }
                catch
                {
                    throw new OPathException(string.Format("The specified property '{0}' in the sort '{1}' is not defined in the entity map for type '{2}'.", propertyName, _expression, entity.Type));
                }

                return(new OrderByItem(propertyName, field, true, parentJoin));
            }
            if (token.Type != TokenType.PERIOD)
            {
                if (token.Type != TokenType.ASCEND && token.Type != TokenType.DESCEND && token.Type != TokenType.COMMA)
                {
                    throw new OPathException("'" + token.Text + "' is not valid in sort expression '" + _expression + "'.");
                }

                FieldMap field;
                try
                {
                    field = entity.GetFieldMap(propertyName);
                }
                catch
                {
                    throw new OPathException(string.Format("The specified property '{0}' in the sort '{1}' is not defined in the entity map for type '{2}'.", propertyName, _expression, entity.Type));
                }

                bool ascending = (token.Type != TokenType.DESCEND);

                if (token.Type != TokenType.COMMA)
                {
                    lexer.MoveToNext();
                }
                lexer.MoveToNext();

                return(new OrderByItem(propertyName, field, ascending, parentJoin));
            }
            else             // dot operator (.)
            {
                token = lexer.Lex();
                if (token == null)
                {
                    throw new OPathException("End of expression encountered where a property or relationship was expected in sort expression '" + _expression + "'.");
                }
                if (token.Type != TokenType.IDENT)
                {
                    throw new OPathException("'" + token.Text + "' encountered where a property or relationship was expected in sort expression '" + _expression + "'.");
                }

                RelationMap relation = entity.Relation(propertyName);
                if (relation == null)
                {
                    throw new OPathException(string.Format("The specified relationship '{0}' in the sort expression '{1}' is not defined in the entity map for type '{2}'.", propertyName, _expression, entity.Type));
                }
                if (relation.Relationship != Relationship.Parent)
                {
                    throw new Exception("Relationship '" + relation.Alias + "' is not a ManyToOne relation.  Only ManyToOne relations are allowed in sort expressions.");
                }

                EntityMap relEntity = _maps[relation.Type];

                OrderByJoin join = joins[propertyName];
                if (join == null)
                {
                    join = new OrderByJoin(relation);
                    joins.Add(join);
                }

                // recursive call
                return(ParseItem(lexer, relEntity, join.NestedJoins, join));
            }
        }
예제 #5
0
        public Expression Parse(string expression)
        {
            // reset our member vars
            _args.Clear();
            _ops.Clear();
            _parameterCount = 0;

            if (expression == null)
            {
                expression = string.Empty;
            }

            using (StringReader reader = new StringReader(expression))
            {
                OPathLexer lexer = new OPathLexer(reader);

                Yytoken token;
                while ((token = lexer.Lex()) != null)
                {
#if DEBUG_PARSER
                    Debug.WriteLine("----------------------------------------");
                    DumpStacks("Starting Token: " + token.ToString());
#endif
                    ProcessToken(token, lexer);

#if DEBUG_PARSER
                    Debug.WriteLine("----------------------------------------\n");
                    Debug.WriteLine("");
#endif
                }
            }

#if DEBUG_PARSER
            Debug.WriteLine("----------------------------------------");
            Debug.WriteLine("Starting Final Reduction");
#endif
            // see if we have a empty expression
            if (_args.Count == 0)
            {
                return(new Empty());
            }

            // reduce remaining operators on the stack
            while (_ops.Count > 0)
            {
                Reduce();                 // reduce the stacks
            }

#if DEBUG_PARSER
            Debug.WriteLine("----------------------------------------");
            Debug.WriteLine("");
#endif
            // expression better be completely reduced
            if (_args.Count > 1)
            {
                throw new OPathException("Expression is not valid.");
            }

            // return root of the tree
            return((Expression)_args.Pop());
        }
예제 #6
0
        private void ProcessToken(Yytoken token, OPathLexer lexer)
        {
            switch (token.Type)
            {
            case TokenType.IDENT:
            {
                Property node = new Property(token.Text, new Context());
                _args.Push(node);
                break;
            }

            case TokenType.PARENT:
            {
                if (lexer.NextToken == null || lexer.NextToken.Type != TokenType.PERIOD)
                {
                    throw new OPathException("Position " + token.Position + ": Parent relationship operator must be followed by a dot operator.");
                }
                Parent node = new Parent(new Context());
                _args.Push(node);
                break;
            }

            case TokenType.PARAM:
            {
                Parameter node = new Parameter(_parameterCount);
                _parameterCount += 1;

                _args.Push(node);
                break;
            }

            case TokenType.CONST:
            {
                Literal node = new Literal(token.Value);
                _args.Push(node);
                break;
            }

            case TokenType.PERIOD:
            {
                Yytoken last = lexer.LastToken;
                Yytoken next = lexer.NextToken;
                if (last == null || next == null)
                {
                    throw new OPathException("Position " + token.Position + ": The dot operator (.) cannot be at the very beginning or end of an expression.");
                }
                // dot operator not valid unless it follows a property/relationship identifier, parent operator, or filter
                if (last.Type != TokenType.IDENT && last.Type != TokenType.PARENT && last.Type != TokenType.RBRACE)
                {
                    throw new OPathException("Position " + token.Position + ": Dot operators cannot be used in this way.");
                }
                // parent operator cannot be after a property/relationship identifer
                if (next.Type == TokenType.PARENT && last.Type != TokenType.PARENT)
                {
                    throw new OPathException("Position " + token.Position + ": Parent relationship operators (^) cannot be used in this way.");
                }
                goto case TokenType.MODULO;
            }

            case TokenType.MINUS:
            {
                // change the token to a negation unless followed by a token that supports subtraction
                Yytoken last = lexer.LastToken;
                if (last == null || (last.Type != TokenType.CONST && last.Type != TokenType.IDENT && last.Type != TokenType.PARAM && last.Type != TokenType.RPAREN))
                {
                    token.Type = TokenType.NEGATE;
                }
                goto case TokenType.COMMA;
            }

            case TokenType.COMMA:
            case TokenType.OP_EQ:
            case TokenType.OP_NE:
            case TokenType.OP_GT:
            case TokenType.OP_GE:
            case TokenType.OP_LT:
            case TokenType.OP_LE:
            case TokenType.OP_LIKE:
            case TokenType.AND:
            case TokenType.OR:
            case TokenType.NOT:
            case TokenType.PLUS:
            case TokenType.MULTIPLY:
            case TokenType.DIVIDE:
            case TokenType.MODULO:
            {
                if (_ops.Count == 0 || ComparePrecedence(token, (Yytoken)_ops.Peek()) > 0)                          // new token has higher precedence
                {
                    _ops.Push(token);
                }
                else                         // new token has lower or same precedence
                {
                    Reduce();
                    // process this token again
                    ProcessToken(token, lexer);                             // note: recursive call
                }
                break;
            }

            case TokenType.OP_IN:
            case TokenType.FN_ISNULL:
            case TokenType.FN_LEN:
            case TokenType.FN_TRIM:
            case TokenType.FN_LEFT:
            case TokenType.FN_RIGHT:
            case TokenType.FN_SUBSTR:
            case TokenType.FN_UPPER:
            case TokenType.FN_LOWER:
            case TokenType.FN_EXISTS:
            {
                Yytoken nextToken = lexer.Lex();
                if (nextToken.Type != TokenType.LPAREN)
                {
                    throw new OPathException("Function '" + token.Text + "' must be followed by an opening parenthesis.");
                }
                _ops.Push(nextToken);
                _ops.Push(token);
                break;
            }

            case TokenType.LPAREN:
            case TokenType.LBRACE:
            {
                _ops.Push(token);
                break;
            }

            case TokenType.RPAREN:
            {
                if (_ops.Count == 0)
                {
                    throw new OPathException("Closing parenthesis encountered without matching opening parenthesis.");
                }

                if (((Yytoken)_ops.Peek()).Type == TokenType.LPAREN)
                {
                    _ops.Pop();                             // "cancel" the operator pair
                }
                else
                {
                    Reduce();
                    // process this token again
                    ProcessToken(token, lexer);                             // note: recursive call
                }
                break;
            }

            case TokenType.RBRACE:
            {
                if (_ops.Count == 0)
                {
                    throw new OPathException("Closing brace encountered without matching opening brace.");
                }

                if (((Yytoken)_ops.Peek()).Type == TokenType.LBRACE)
                {
                    Reduce();                             // a final reduce to "cancel" the pair
                }
                else
                {
                    Reduce();
                    // process this token again
                    ProcessToken(token, lexer);                             // note: recursive call
                }
                break;
            }

            default:
            {
                throw new NotSupportedException("Token type " + token.Type + " at position " + token.Position + " in expression is not supported.");
            }
            }

#if DEBUG_PARSER
            DumpStacks("\nAfter Token: " + token.ToString());
#endif
        }
예제 #7
0
        private Yytoken[] Lex(string value)
        {
            ArrayList tokens = new ArrayList();
            using( StringReader reader = new StringReader(value) )
            {
                OPathLexer lexer = new OPathLexer(reader);

                Yytoken token;
                while( (token = lexer.Lex()) != null )
                {
                    tokens.Add(token);
                }
            }

            return (Yytoken[])tokens.ToArray(typeof(Yytoken));
        }
예제 #8
0
        private OrderByItem ParseItem(OPathLexer lexer, EntityMap entity, OrderByJoinCollection joins, OrderByJoin parentJoin)
        {
            Yytoken token = lexer.CurrentToken;
            if( token.Type != TokenType.IDENT )
            {
                throw new OPathException("'" + token.Text + "' encountered where a property or relationship was expected in sort expression '" + _expression + "'.");
            }

            string propertyName = token.Text;

            token = lexer.Lex();
            if( token == null )
            {
                FieldMap field;
                try
                {
                    field = entity.GetFieldMap(propertyName);
                }
                catch
                {
                    throw new OPathException(string.Format("The specified property '{0}' in the sort '{1}' is not defined in the entity map for type '{2}'.", propertyName, _expression, entity.Type));
                }

                return new OrderByItem(propertyName, field, true, parentJoin);
            }
            if( token.Type != TokenType.PERIOD )
            {
                if( token.Type != TokenType.ASCEND && token.Type != TokenType.DESCEND && token.Type != TokenType.COMMA )
                {
                    throw new OPathException("'" + token.Text + "' is not valid in sort expression '" + _expression + "'.");
                }

                FieldMap field;
                try
                {
                    field = entity.GetFieldMap(propertyName);
                }
                catch
                {
                    throw new OPathException(string.Format("The specified property '{0}' in the sort '{1}' is not defined in the entity map for type '{2}'.", propertyName, _expression, entity.Type));
                }

                bool ascending = (token.Type != TokenType.DESCEND);

                if( token.Type != TokenType.COMMA )
                {
                    lexer.MoveToNext();
                }
                lexer.MoveToNext();

                return new OrderByItem(propertyName, field, ascending, parentJoin);
            }
            else // dot operator (.)
            {
                token = lexer.Lex();
                if( token == null )
                {
                    throw new OPathException("End of expression encountered where a property or relationship was expected in sort expression '" + _expression + "'.");
                }
                if( token.Type != TokenType.IDENT )
                {
                    throw new OPathException("'" + token.Text + "' encountered where a property or relationship was expected in sort expression '" + _expression + "'.");
                }

                RelationMap relation = entity.Relation(propertyName);
                if( relation == null )
                {
                    throw new OPathException(string.Format("The specified relationship '{0}' in the sort expression '{1}' is not defined in the entity map for type '{2}'.", propertyName, _expression, entity.Type));
                }
                if( relation.Relationship != Relationship.Parent )
                {
                    throw new Exception("Relationship '" + relation.Alias + "' is not a ManyToOne relation.  Only ManyToOne relations are allowed in sort expressions.");
                }

                EntityMap relEntity = _maps[relation.Type];

                OrderByJoin join = joins[propertyName];
                if( join == null )
                {
                    join = new OrderByJoin(relation);
                    joins.Add(join);
                }

                // recursive call
                return ParseItem(lexer, relEntity, join.NestedJoins, join);
            }
        }
예제 #9
0
        public Expression Parse(string expression)
        {
            // reset our member vars
            _args.Clear();
            _ops.Clear();
            _parameterCount = 0;

            if( expression == null )
            {
                expression = string.Empty;
            }

            using( StringReader reader = new StringReader(expression) )
            {
                OPathLexer lexer = new OPathLexer(reader);

                Yytoken token;
                while( (token = lexer.Lex()) != null )
                {
            #if DEBUG_PARSER
                    Debug.WriteLine("----------------------------------------");
                    DumpStacks("Starting Token: " + token.ToString());
            #endif
                    ProcessToken(token, lexer);

            #if DEBUG_PARSER
                    Debug.WriteLine("----------------------------------------\n");
                    Debug.WriteLine("");
            #endif
                }
            }

            #if DEBUG_PARSER
            Debug.WriteLine("----------------------------------------");
            Debug.WriteLine("Starting Final Reduction");
            #endif
            // see if we have a empty expression
            if( _args.Count == 0 )
            {
                return new Empty();
            }

            // reduce remaining operators on the stack
            while( _ops.Count > 0 )
            {
                Reduce(); // reduce the stacks
            }

            #if DEBUG_PARSER
            Debug.WriteLine("----------------------------------------");
            Debug.WriteLine("");
            #endif
            // expression better be completely reduced
            if( _args.Count > 1 )
            {
                throw new OPathException("Expression is not valid.");
            }

            // return root of the tree
            return (Expression)_args.Pop();
        }
예제 #10
0
        private void ProcessToken(Yytoken token, OPathLexer lexer)
        {
            switch( token.Type )
            {
                case TokenType.IDENT:
                {
                    Property node = new Property(token.Text, new Context());
                    _args.Push(node);
                    break;
                }
                case TokenType.PARENT:
                {
                    if( lexer.NextToken == null || lexer.NextToken.Type != TokenType.PERIOD )
                    {
                        throw new OPathException("Position " + token.Position + ": Parent relationship operator must be followed by a dot operator.");
                    }
                    Parent node = new Parent(new Context());
                    _args.Push(node);
                    break;
                }
                case TokenType.PARAM:
                {
                    Parameter node = new Parameter(_parameterCount);
                    _parameterCount += 1;

                    _args.Push(node);
                    break;
                }
                case TokenType.CONST:
                {
                    Literal node = new Literal(token.Value);
                    _args.Push(node);
                    break;
                }
                case TokenType.PERIOD:
                {
                    Yytoken last = lexer.LastToken;
                    Yytoken next = lexer.NextToken;
                    if( last == null || next == null )
                    {
                        throw new OPathException("Position " + token.Position + ": The dot operator (.) cannot be at the very beginning or end of an expression.");
                    }
                    // dot operator not valid unless it follows a property/relationship identifier, parent operator, or filter
                    if( last.Type != TokenType.IDENT && last.Type != TokenType.PARENT && last.Type != TokenType.RBRACE )
                    {
                        throw new OPathException("Position " + token.Position + ": Dot operators cannot be used in this way.");
                    }
                    // parent operator cannot be after a property/relationship identifer
                    if( next.Type == TokenType.PARENT && last.Type != TokenType.PARENT )
                    {
                        throw new OPathException("Position " + token.Position + ": Parent relationship operators (^) cannot be used in this way.");
                    }
                    goto case TokenType.MODULO;
                }
                case TokenType.MINUS:
                {
                    // change the token to a negation unless followed by a token that supports subtraction
                    Yytoken last = lexer.LastToken;
                    if( last == null || (last.Type != TokenType.CONST && last.Type != TokenType.IDENT && last.Type != TokenType.PARAM && last.Type != TokenType.RPAREN) )
                    {
                        token.Type = TokenType.NEGATE;
                    }
                    goto case TokenType.COMMA;
                }
                case TokenType.COMMA:
                case TokenType.OP_EQ:
                case TokenType.OP_NE:
                case TokenType.OP_GT:
                case TokenType.OP_GE:
                case TokenType.OP_LT:
                case TokenType.OP_LE:
                case TokenType.OP_LIKE:
                case TokenType.AND:
                case TokenType.OR:
                case TokenType.NOT:
                case TokenType.PLUS:
                case TokenType.MULTIPLY:
                case TokenType.DIVIDE:
                case TokenType.MODULO:
                {
                    if( _ops.Count == 0 || ComparePrecedence(token, (Yytoken)_ops.Peek()) > 0 ) // new token has higher precedence
                    {
                        _ops.Push(token);
                    }
                    else // new token has lower or same precedence
                    {
                        Reduce();
                        // process this token again
                        ProcessToken(token, lexer); // note: recursive call
                    }
                    break;
                }
                case TokenType.OP_IN:
                case TokenType.FN_ISNULL:
                case TokenType.FN_LEN:
                case TokenType.FN_TRIM:
                case TokenType.FN_LEFT:
                case TokenType.FN_RIGHT:
                case TokenType.FN_SUBSTR:
                case TokenType.FN_UPPER:
                case TokenType.FN_LOWER:
                case TokenType.FN_EXISTS:
                {
                    Yytoken nextToken = lexer.Lex();
                    if( nextToken.Type != TokenType.LPAREN )
                    {
                        throw new OPathException("Function '" + token.Text + "' must be followed by an opening parenthesis.");
                    }
                    _ops.Push(nextToken);
                    _ops.Push(token);
                    break;
                }
                case TokenType.LPAREN:
                case TokenType.LBRACE:
                {
                    _ops.Push(token);
                    break;
                }
                case TokenType.RPAREN:
                {
                    if( _ops.Count == 0 ) throw new OPathException("Closing parenthesis encountered without matching opening parenthesis.");

                    if( ((Yytoken)_ops.Peek()).Type == TokenType.LPAREN )
                    {
                        _ops.Pop(); // "cancel" the operator pair
                    }
                    else
                    {
                        Reduce();
                        // process this token again
                        ProcessToken(token, lexer); // note: recursive call
                    }
                    break;
                }
                case TokenType.RBRACE:
                {
                    if( _ops.Count == 0 ) throw new OPathException("Closing brace encountered without matching opening brace.");

                    if( ((Yytoken)_ops.Peek()).Type == TokenType.LBRACE )
                    {
                        Reduce(); // a final reduce to "cancel" the pair
                    }
                    else
                    {
                        Reduce();
                        // process this token again
                        ProcessToken(token, lexer); // note: recursive call
                    }
                    break;
                }
                default:
                {
                    throw new NotSupportedException("Token type " + token.Type + " at position " + token.Position + " in expression is not supported.");
                }
            }

            #if DEBUG_PARSER
            DumpStacks("\nAfter Token: " + token.ToString());
            #endif
        }