1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.onemind.commons.java.datastructure;
22
23 import java.util.*;
24 import java.util.logging.Logger;
25 /***
26 * A nametable stack contains key-value mapping that has a scope.
27 * A new scope can be opened for putting new mappings and all the
28 * mappings added in this scope can be wiped out easily with a
29 * closeScope command. In effect this is like a stack of Maps,
30 * hence the name NametableStack.
31 *
32 * NOTE: the implementation use a map and list to achieve the behaviour.
33 * @author TiongHiang Lee (thlee@onemindsoft.org)
34 * @version $Id: NametableStack.java,v 1.7 2005/06/22 22:57:37 thlee Exp $ $Name: $
35 */
36 public class NametableStack
37 {
38
39 /*** the logger * */
40 private static final Logger _logger = Logger.getLogger(NametableStack.class.getName());
41
42 /*** the map * */
43 private Nametable _nametable;
44
45 /*** the list of maps * */
46 private ArrayList _list = new ArrayList();
47
48 /***
49 * The local nametable defines a scope where local variables mask out the global
50 * variables, but the global variable can still be accessed. This is useful for
51 * implementing function context
52 *
53 * @author TiongHiang Lee (thlee@onemindsoft.org)
54 */
55 private static class LocalNametable implements Nametable
56 {
57
58 /*** the local variables **/
59 private final Map _locals = new HashMap();
60
61 /*** the global map **/
62 private final Nametable _global;
63
64 /*** the scope **/
65 private final int _scope;
66
67 /***
68 * Constructor
69 * @param global the global
70 * @param scope the scope # where this local nametabe is openned
71 */
72 private LocalNametable(Nametable global, int scope)
73 {
74 _global = global;
75 _scope = scope;
76 }
77
78 /***
79 * Get the global
80 * @return the global
81 */
82 private Nametable getGlobal()
83 {
84 return _global;
85 }
86
87 /***
88 * {@inheritDoc}
89 */
90 public boolean containsName(String key)
91 {
92 return _locals.containsKey(key) || _global.containsName(key);
93 }
94
95 /***
96 * {@inheritDoc}
97 */
98 public void declare(String name, Object value)
99 {
100 _locals.put(name, value);
101 }
102
103 /***
104 * {@inheritDoc}
105 */
106 public Object assign(String name, Object value)
107 {
108 if (_locals.containsKey(name))
109 {
110 return _locals.put(name, value);
111 } else
112 {
113
114 return _global.assign(name, value);
115 }
116 }
117
118 /***
119 * {@inheritDoc}
120 */
121 public Object access(String name)
122 {
123 if (_locals.containsKey(name))
124 {
125 return _locals.get(name);
126 } else
127 {
128 return _global.access(name);
129 }
130 }
131
132 /***
133 * {@inheritDoc}
134 */
135 public void undeclare(String name)
136 {
137 if (_locals.containsKey(name))
138 {
139 _locals.remove(name);
140 } else
141 {
142
143 _global.undeclare(name);
144 }
145 }
146
147 public String toString(){
148 StringBuffer sb = new StringBuffer();
149 sb.append("Scope=");
150 sb.append(_scope);
151 sb.append("\n");
152 sb.append("Locals=" + _locals + "\n");
153 sb.append("Global=" + _global + "\n");
154 return sb.toString();
155 }
156
157 public Map asMap(){
158 Map m = new HashMap(_global.asMap());
159 m.putAll(_locals);
160 return Collections.unmodifiableMap(m);
161 }
162 }
163
164 /***
165 * {@inheritDoc}
166 */
167 public NametableStack()
168 {
169 this(new HashMap());
170 }
171
172 /***
173 * {@inheritDoc}
174 * @param m the initial mapping
175 */
176 public NametableStack(Map m)
177 {
178 _nametable = new SimpleNametable(m);
179 }
180
181 /***
182 * Open a new scope for mappings. Return an integer that represents a scope id
183 * @return the new scope
184 */
185 public int newScope()
186 {
187 return _list.size();
188 }
189
190 public int newLocalScope()
191 {
192 _nametable = new LocalNametable(_nametable, _list.size());
193 return _list.size();
194 }
195
196 public void closeLocalScope(int i)
197 {
198 if (_nametable instanceof LocalNametable)
199 {
200 LocalNametable nt = (LocalNametable) _nametable;
201 if (nt._scope != i)
202 {
203 throw new IllegalArgumentException("Local scope " + i + " not matched");
204 } else
205 {
206 for (int k = _list.size(); k > i; k--)
207 {
208 _list.remove(k-1);
209 }
210 _nametable = nt.getGlobal();
211 }
212 } else
213 {
214 throw new IllegalStateException("Cannot find scope " + i);
215 }
216 }
217
218 /***
219 * Close a scope
220 * @param l the scope id
221 */
222 public void closeScope(int l)
223 {
224 if (_nametable instanceof LocalNametable)
225 {
226 if (l < ((LocalNametable) _nametable)._scope)
227 {
228 throw new IllegalStateException("Encounter unclosed local scope");
229 }
230 }
231 int n = _list.size();
232 if (l > n)
233 {
234 throw new IllegalArgumentException("The scope has been closed");
235 } else if (l < n)
236 {
237 int diff = n - l;
238 for (int i = 0; i < diff; i++)
239 {
240 _nametable.undeclare((String)_list.remove(n - i - 1));
241 }
242 }
243 }
244
245 /***
246 * Declare name value pair
247 * @param name
248 * @param value
249 * @return
250 */
251 public void declare(String name, Object value)
252 {
253 _nametable.declare(name, value);
254 _list.add(name);
255 }
256
257 /***
258 * Assign name/value pair
259 * @param name
260 * @param value
261 * @return
262 */
263 public Object assign(String name, Object value)
264 {
265 return _nametable.assign(name, value);
266 }
267
268 /***
269 * Resolve the value associated with key name
270 * @param name the key
271 * @return the value associated with key
272 */
273 public Object access(String name)
274 {
275 return _nametable.access(name);
276 }
277
278 /***
279 * Whether the map contains key name
280 * @param name the key
281 * @return true if map contains key name
282 */
283 public boolean containsName(String name)
284 {
285 return _nametable.containsName(name);
286 }
287
288 /***
289 * Return map representation of the nametable stack
290 * @return the map
291 */
292 public Map asMap()
293 {
294 return _nametable.asMap();
295 }
296
297 /***
298 * {@inheritDoc}
299 */
300 public String toString()
301 {
302 return _nametable.toString();
303 }
304 }