KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > hivemind > impl > SymbolExpander


1 // Copyright 2004, 2005 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.hivemind.impl;
16
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19 import org.apache.hivemind.ErrorHandler;
20 import org.apache.hivemind.Location;
21 import org.apache.hivemind.SymbolSource;
22
23 /**
24  * A simple parser used to identify symbols in a string and expand them via a
25  * {@link org.apache.hivemind.SymbolSource}.
26  *
27  * @author Howard Lewis Ship
28  */

29 public class SymbolExpander
30 {
31     private ErrorHandler _errorHandler;
32
33     private SymbolSource _source;
34
35     public SymbolExpander(ErrorHandler handler, SymbolSource source)
36     {
37         _errorHandler = handler;
38         _source = source;
39     }
40
41     private static final Log LOG = LogFactory.getLog(SymbolExpander.class);
42
43     private static final int STATE_START = 0;
44
45     private static final int STATE_DOLLAR = 1;
46
47     private static final int STATE_COLLECT_SYMBOL_NAME = 2;
48
49     /**
50      * <p>
51      * Identifies symbols in the text and expands them, using the {@link SymbolSource}. Returns the
52      * modified text. May return text if text does not contain any symbols.
53      *
54      * @param text
55      * the text to scan
56      * @param location
57      * the location to report errors (undefined symbols)
58      */

59     public String JavaDoc expandSymbols(String JavaDoc text, Location location)
60     {
61         StringBuffer JavaDoc result = new StringBuffer JavaDoc(text.length());
62         char[] buffer = text.toCharArray();
63         int state = STATE_START;
64         int blockStart = 0;
65         int blockLength = 0;
66         int symbolStart = -1;
67         int symbolLength = 0;
68         int i = 0;
69         int braceDepth = 0;
70         boolean anySymbols = false;
71
72         while (i < buffer.length)
73         {
74             char ch = buffer[i];
75
76             switch (state)
77             {
78                 case STATE_START:
79
80                     if (ch == '$')
81                     {
82                         state = STATE_DOLLAR;
83                         i++;
84                         continue;
85                     }
86
87                     blockLength++;
88                     i++;
89                     continue;
90
91                 case STATE_DOLLAR:
92
93                     if (ch == '{')
94                     {
95                         state = STATE_COLLECT_SYMBOL_NAME;
96                         i++;
97
98                         symbolStart = i;
99                         symbolLength = 0;
100                         braceDepth = 1;
101
102                         continue;
103                     }
104
105                     // Any time two $$ appear, it is collapsed down to a single $,
106
// but the next character is passed through un-interpreted (even if it
107
// is a brace).
108

109                     if (ch == '$')
110                     {
111                         // This is effectively a symbol, meaning that the input string
112
// will not equal the output string.
113

114                         anySymbols = true;
115
116                         if (blockLength > 0)
117                             result.append(buffer, blockStart, blockLength);
118
119                         result.append(ch);
120
121                         i++;
122                         blockStart = i;
123                         blockLength = 0;
124                         state = STATE_START;
125
126                         continue;
127                     }
128
129                     // The '$' was just what it was, not the start of a ${} expression
130
// block, so include it as part of the static text block.
131

132                     blockLength++;
133
134                     state = STATE_START;
135                     continue;
136
137                 case STATE_COLLECT_SYMBOL_NAME:
138
139                     if (ch != '}')
140                     {
141                         if (ch == '{')
142                             braceDepth++;
143
144                         i++;
145                         symbolLength++;
146                         continue;
147                     }
148
149                     braceDepth--;
150
151                     if (braceDepth > 0)
152                     {
153                         i++;
154                         symbolLength++;
155                         continue;
156                     }
157
158                     // Hit the closing brace of a symbol.
159

160                     // Degenerate case: the string "${}".
161

162                     if (symbolLength == 0)
163                         blockLength += 3;
164
165                     // Append anything up to the start of the sequence (this is static
166
// text between symbol references).
167

168                     if (blockLength > 0)
169                         result.append(buffer, blockStart, blockLength);
170
171                     if (symbolLength > 0)
172                     {
173                         String JavaDoc variableName = text.substring(symbolStart, symbolStart
174                                 + symbolLength);
175
176                         result.append(expandSymbol(variableName, location));
177
178                         anySymbols = true;
179                     }
180
181                     i++;
182                     blockStart = i;
183                     blockLength = 0;
184
185                     // And drop into state start
186

187                     state = STATE_START;
188
189                     continue;
190             }
191
192         }
193
194         // If get this far without seeing any variables, then just pass
195
// the input back.
196

197         if (!anySymbols)
198             return text;
199
200         // OK, to handle the end. Couple of degenerate cases where
201
// a ${...} was incomplete, so we adust the block length.
202

203         if (state == STATE_DOLLAR)
204             blockLength++;
205
206         if (state == STATE_COLLECT_SYMBOL_NAME)
207             blockLength += symbolLength + 2;
208
209         if (blockLength > 0)
210             result.append(buffer, blockStart, blockLength);
211
212         return result.toString();
213     }
214
215     private String JavaDoc expandSymbol(String JavaDoc name, Location location)
216     {
217         String JavaDoc value = _source.valueForSymbol(name);
218
219         if (value != null)
220             return value;
221
222         _errorHandler.error(LOG, ImplMessages.noSuchSymbol(name), location, null);
223
224         return "${" + name + "}";
225     }
226
227 }
Popular Tags