1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3.internal;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.LinkedHashMap;
22 import java.util.List;
23 import java.util.Map;
24
25
26
27
28
29
30 public final class Scope {
31
32
33
34 static final Object UNDECLARED = new Object() {
35 @Override public String toString() {
36 return "??";
37 }
38 };
39
40
41
42 static final Object UNDEFINED = new Object() {
43 @Override public String toString() {
44 return "?";
45 }
46 };
47
48
49
50 private static final String[] EMPTY_STRS = {};
51
52
53
54 private final Scope parent;
55
56
57
58 private int parms;
59
60
61
62 private int vars;
63
64
65
66
67
68 private Map<String, Integer> namedVariables;
69
70
71
72 private Map<Integer, Integer> capturedVariables;
73
74
75
76
77 private LexicalScope lexicalVariables;
78
79
80
81
82
83
84 public Scope(final Scope scope, final String... parameters) {
85 if (parameters != null) {
86 parms = parameters.length;
87 namedVariables = new LinkedHashMap<>();
88 for (int p = 0; p < parms; ++p) {
89 namedVariables.put(parameters[p], p);
90 }
91 } else {
92 parms = 0;
93 }
94 vars = 0;
95 parent = scope;
96 }
97
98
99
100
101
102
103 public boolean addLexical(final int s) {
104 if (lexicalVariables == null) {
105 lexicalVariables = new LexicalScope();
106 }
107 return lexicalVariables.addSymbol(s);
108 }
109
110
111
112
113
114
115
116
117 public Frame createFrame(final Frame frame, final Object...args) {
118 if (namedVariables == null) {
119 return null;
120 }
121 final Object[] arguments = new Object[namedVariables.size()];
122 Arrays.fill(arguments, UNDECLARED);
123 if (frame != null && capturedVariables != null && parent != null) {
124 for (final Map.Entry<Integer, Integer> capture : capturedVariables.entrySet()) {
125 final Integer target = capture.getKey();
126 final Integer source = capture.getValue();
127 final Object arg = frame.get(source);
128 arguments[target] = arg;
129 }
130 }
131 return new Frame(this, arguments, 0).assign(args);
132 }
133
134
135
136
137
138
139
140
141
142 public int declareParameter(final String name) {
143 if (namedVariables == null) {
144 namedVariables = new LinkedHashMap<>();
145 } else if (vars > 0) {
146 throw new IllegalStateException("cant declare parameters after variables");
147 }
148 Integer register = namedVariables.get(name);
149 if (register == null) {
150 register = namedVariables.size();
151 namedVariables.put(name, register);
152 parms += 1;
153 }
154 return register;
155 }
156
157
158
159
160
161
162
163
164
165 public int declareVariable(final String name) {
166 if (namedVariables == null) {
167 namedVariables = new LinkedHashMap<>();
168 }
169 Integer register = namedVariables.get(name);
170 if (register == null) {
171 register = namedVariables.size();
172 namedVariables.put(name, register);
173 vars += 1;
174
175 if (parent != null) {
176 final Integer pr = parent.getSymbol(name, true);
177 if (pr != null) {
178 if (capturedVariables == null) {
179 capturedVariables = new LinkedHashMap<>();
180 }
181 capturedVariables.put(register, pr);
182 }
183 }
184 }
185 return register;
186 }
187
188
189
190
191
192 public int getArgCount() {
193 return parms;
194 }
195
196
197
198
199
200
201 public Integer getCaptured(final int symbol) {
202 if (capturedVariables != null) {
203 for (final Map.Entry<Integer, Integer> capture : capturedVariables.entrySet()) {
204 final Integer source = capture.getValue();
205 if (source == symbol) {
206 return capture.getKey();
207 }
208 }
209 }
210 return null;
211 }
212
213
214
215
216
217
218 public int getCaptureDeclaration(final int symbol) {
219 final Integer declared = capturedVariables != null ? capturedVariables.get(symbol) : null;
220 return declared != null ? declared.intValue() : -1;
221 }
222
223
224
225
226
227
228 public String[] getCapturedVariables() {
229 if (capturedVariables != null) {
230 final List<String> captured = new ArrayList<>(vars);
231 for (final Map.Entry<String, Integer> entry : namedVariables.entrySet()) {
232 final int symnum = entry.getValue();
233 if (symnum >= parms && capturedVariables.containsKey(symnum)) {
234 captured.add(entry.getKey());
235 }
236 }
237 if (!captured.isEmpty()) {
238 return captured.toArray(new String[0]);
239 }
240 }
241 return EMPTY_STRS;
242 }
243
244
245
246
247
248 public String[] getLocalVariables() {
249 if (namedVariables == null || vars <= 0) {
250 return EMPTY_STRS;
251 }
252 final List<String> locals = new ArrayList<>(vars);
253 for (final Map.Entry<String, Integer> entry : namedVariables.entrySet()) {
254 final int symnum = entry.getValue();
255 if (symnum >= parms && (capturedVariables == null || !capturedVariables.containsKey(symnum))) {
256 locals.add(entry.getKey());
257 }
258 }
259 return locals.toArray(new String[0]);
260 }
261
262
263
264
265
266 public String[] getParameters() {
267 return getParameters(0);
268 }
269
270
271
272
273
274
275 String[] getParameters(final int bound) {
276 final int unbound = parms - bound;
277 if (namedVariables == null || unbound <= 0) {
278 return EMPTY_STRS;
279 }
280 final String[] pa = new String[unbound];
281 int p = 0;
282 for (final Map.Entry<String, Integer> entry : namedVariables.entrySet()) {
283 final int argn = entry.getValue();
284 if (argn >= bound && argn < parms) {
285 pa[p++] = entry.getKey();
286 }
287 }
288 return pa;
289 }
290
291 Scope getParent() {
292 return parent;
293 }
294
295
296
297
298
299
300
301 public Integer getSymbol(final String name) {
302 return getSymbol(name, true);
303 }
304
305
306
307
308
309
310
311 private Integer getSymbol(final String name, final boolean capture) {
312 Integer register = namedVariables != null ? namedVariables.get(name) : null;
313 if (register == null && capture && parent != null) {
314 final Integer pr = parent.getSymbol(name, true);
315 if (pr != null) {
316 if (capturedVariables == null) {
317 capturedVariables = new LinkedHashMap<>();
318 }
319 if (namedVariables == null) {
320 namedVariables = new LinkedHashMap<>();
321 }
322 register = namedVariables.size();
323 namedVariables.put(name, register);
324 capturedVariables.put(register, pr);
325 }
326 }
327 return register;
328 }
329
330
331
332
333
334 public String[] getSymbols() {
335 return namedVariables != null ? namedVariables.keySet().toArray(new String[0]) : EMPTY_STRS;
336 }
337
338
339
340
341
342
343 public boolean isCapturedSymbol(final int symbol) {
344 return capturedVariables != null && capturedVariables.containsKey(symbol);
345 }
346
347
348
349
350
351
352 public boolean isLexical(final int s) {
353 return lexicalVariables != null && s >= 0 && lexicalVariables.hasSymbol(s);
354 }
355 }