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 }