001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.hivemind.conditional;
016    
017    import org.apache.hivemind.util.Defense;
018    
019    /**
020     * Parser for conditional expressions. This class is not threadsafe; it is inexpensive to create,
021     * however, and can be discarded after parsing one or more expressions.
022     * 
023     * @author Howard M. Lewis Ship
024     * @since 1.1
025     */
026    public class Parser
027    {
028        private String _input;
029    
030        private Lexer _lexer;
031    
032        private Token _nextToken;
033    
034        private boolean _onDeck;
035    
036        // No reason to have multiple instances of these, since they are always
037        // identical (one of the advantages of the NodeImpl being purely structural.
038    
039        private static final Evaluator NOT_EVALUATOR = new NotEvaluator();
040    
041        private static final Evaluator OR_EVALUATOR = new OrEvaluator();
042    
043        private static final Evaluator AND_EVALUATOR = new AndEvaluator();
044    
045        public Node parse(String input)
046        {
047            Defense.notNull(input, "input");
048    
049            try
050            {
051                _input = input;
052                _lexer = new Lexer(input);
053    
054                Node result = expression();
055    
056                Token token = next();
057    
058                if (token != null)
059                    throw new RuntimeException(ConditionalMessages.unparsedToken(token, _input));
060    
061                return result;
062            }
063            finally
064            {
065                _input = null;
066                _nextToken = null;
067                _lexer = null;
068                _onDeck = false;
069            }
070        }
071    
072        private Token next()
073        {
074            Token result = _onDeck ? _nextToken : _lexer.next();
075    
076            _onDeck = false;
077            _nextToken = null;
078    
079            return result;
080        }
081    
082        private Token match(TokenType expected)
083        {
084            Token actual = next();
085    
086            if (actual == null)
087                throw new RuntimeException(ConditionalMessages.unexpectedEndOfInput(_input));
088    
089            if (actual.getType() != expected)
090                throw new RuntimeException(ConditionalMessages.unexpectedToken(expected, actual
091                        .getType(), _input));
092    
093            return actual;
094        }
095    
096        private Token peek()
097        {
098            if (! _onDeck)
099            {
100                _nextToken = _lexer.next();
101                _onDeck = true;
102            }
103    
104            return _nextToken;
105        }
106    
107        private TokenType peekType()
108        {
109            Token next = peek();
110    
111            return next == null ? null : next.getType();
112        }
113    
114        private boolean isPeek(TokenType type)
115        {
116            return peekType() == type;
117        }
118    
119        private Node expression()
120        {
121            Node lnode = term();
122    
123            if (isPeek(TokenType.OR))
124            {
125                next();
126    
127                Node rnode = expression();
128    
129                return new NodeImpl(lnode, rnode, OR_EVALUATOR);
130            }
131    
132            if (isPeek(TokenType.AND))
133            {
134                next();
135    
136                Node rnode = expression();
137    
138                return new NodeImpl(lnode, rnode, AND_EVALUATOR);
139            }
140    
141            return lnode;
142        }
143    
144        private Node term()
145        {
146            if (isPeek(TokenType.OPAREN))
147            {
148                next();
149    
150                Node result = expression();
151    
152                match(TokenType.CPAREN);
153    
154                return result;
155            }
156    
157            if (isPeek(TokenType.NOT))
158            {
159                next();
160    
161                match(TokenType.OPAREN);
162    
163                Node expression = expression();
164    
165                match(TokenType.CPAREN);
166    
167                return new NodeImpl(expression, null, NOT_EVALUATOR);
168            }
169    
170            if (isPeek(TokenType.PROPERTY))
171            {
172                next();
173    
174                Token symbolToken = match(TokenType.SYMBOL);
175    
176                Evaluator ev = new PropertyEvaluator(symbolToken.getValue());
177    
178                return new NodeImpl(ev);
179            }
180    
181            if (isPeek(TokenType.CLASS))
182            {
183                next();
184    
185                Token symbolToken = match(TokenType.SYMBOL);
186    
187                Evaluator ev = new ClassNameEvaluator(symbolToken.getValue());
188    
189                return new NodeImpl(ev);
190            }
191    
192            throw new RuntimeException(ConditionalMessages.unparsedToken(next(), _input));
193        }
194    }