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