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