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 private LexicalScope lexicalVariables;
77
78
79
80
81
82
83 public Scope(final Scope scope, final String... parameters) {
84 if (parameters != null) {
85 parms = parameters.length;
86 namedVariables = new LinkedHashMap<>();
87 for (int p = 0; p < parms; ++p) {
88 namedVariables.put(parameters[p], p);
89 }
90 } else {
91 parms = 0;
92 }
93 vars = 0;
94 parent = scope;
95 }
96
97
98
99
100
101
102 public boolean addLexical(final int s) {
103 if (lexicalVariables == null) {
104 lexicalVariables = new LexicalScope();
105 }
106 return lexicalVariables.addSymbol(s);
107 }
108
109
110
111
112
113
114
115
116 public Frame createFrame(final boolean ref, final Frame frame, final Object...args) {
117 if (namedVariables == null) {
118 return null;
119 }
120 final Object[] arguments = new Object[namedVariables.size()];
121 Arrays.fill(arguments, UNDECLARED);
122 final Frame newFrame;
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.capture(source);
128 arguments[target] = arg;
129 }
130 newFrame = frame.newFrame(this, arguments, 0);
131 } else {
132 newFrame = ref
133 ? new ReferenceFrame(this, arguments, 0)
134 : new Frame(this, arguments, 0);
135 }
136 return newFrame.assign(args);
137 }
138
139
140
141
142
143
144
145
146
147 public int declareParameter(final String param) {
148 if (namedVariables == null) {
149 namedVariables = new LinkedHashMap<>();
150 } else if (vars > 0) {
151 throw new IllegalStateException("cant declare parameters after variables");
152 }
153 return namedVariables.computeIfAbsent(param, name -> {
154 final int register = namedVariables.size();
155 parms += 1;
156 return register;
157 });
158 }
159
160
161
162
163
164
165
166
167
168 public int declareVariable(final String varName) {
169 if (namedVariables == null) {
170 namedVariables = new LinkedHashMap<>();
171 }
172 return namedVariables.computeIfAbsent(varName, name -> {
173 final int register = namedVariables.size();
174 vars += 1;
175
176 if (parent != null) {
177 final Integer pr = parent.getSymbol(name, true);
178 if (pr != null) {
179 if (capturedVariables == null) {
180 capturedVariables = new LinkedHashMap<>();
181 }
182 capturedVariables.put(register, pr);
183 }
184 }
185 return register;
186 });
187 }
188
189
190
191
192
193 public int getArgCount() {
194 return parms;
195 }
196
197
198
199
200
201
202 public Integer getCaptured(final int symbol) {
203 if (capturedVariables != null) {
204 for (final Map.Entry<Integer, Integer> capture : capturedVariables.entrySet()) {
205 final Integer source = capture.getValue();
206 if (source == symbol) {
207 return capture.getKey();
208 }
209 }
210 }
211 return null;
212 }
213
214
215
216
217
218
219 public int getCaptureDeclaration(final int symbol) {
220 final Integer declared = capturedVariables != null ? capturedVariables.get(symbol) : null;
221 return declared != null ? declared : -1;
222 }
223
224
225
226
227
228
229 public String[] getCapturedVariables() {
230 if (capturedVariables != null) {
231 final List<String> captured = new ArrayList<>(vars);
232 for (final Map.Entry<String, Integer> entry : namedVariables.entrySet()) {
233 final int symnum = entry.getValue();
234 if (symnum >= parms && capturedVariables.containsKey(symnum)) {
235 captured.add(entry.getKey());
236 }
237 }
238 if (!captured.isEmpty()) {
239 return captured.toArray(new String[0]);
240 }
241 }
242 return EMPTY_STRS;
243 }
244
245
246
247
248
249 public String[] getLocalVariables() {
250 if (namedVariables == null || vars <= 0) {
251 return EMPTY_STRS;
252 }
253 final List<String> locals = new ArrayList<>(vars);
254 for (final Map.Entry<String, Integer> entry : namedVariables.entrySet()) {
255 final int symnum = entry.getValue();
256 if (symnum >= parms && (capturedVariables == null || !capturedVariables.containsKey(symnum))) {
257 locals.add(entry.getKey());
258 }
259 }
260 return locals.toArray(new String[0]);
261 }
262
263
264
265
266
267 public String[] getParameters() {
268 return getParameters(0);
269 }
270
271
272
273
274
275
276 String[] getParameters(final int bound) {
277 final int unbound = parms - bound;
278 if (namedVariables == null || unbound <= 0) {
279 return EMPTY_STRS;
280 }
281 final String[] pa = new String[unbound];
282 int p = 0;
283 for (final Map.Entry<String, Integer> entry : namedVariables.entrySet()) {
284 final int argn = entry.getValue();
285 if (argn >= bound && argn < parms) {
286 pa[p++] = entry.getKey();
287 }
288 }
289 return pa;
290 }
291
292 Scope getParent() {
293 return parent;
294 }
295
296
297
298
299
300
301
302 public Integer getSymbol(final String name) {
303 return getSymbol(name, true);
304 }
305
306
307
308
309
310
311
312 private Integer getSymbol(final String name, final boolean capture) {
313 Integer register = namedVariables != null ? namedVariables.get(name) : null;
314 if (register == null && capture && parent != null) {
315 final Integer pr = parent.getSymbol(name, true);
316 if (pr != null) {
317 if (capturedVariables == null) {
318 capturedVariables = new LinkedHashMap<>();
319 }
320 if (namedVariables == null) {
321 namedVariables = new LinkedHashMap<>();
322 }
323 register = namedVariables.size();
324 namedVariables.put(name, register);
325 capturedVariables.put(register, pr);
326 }
327 }
328 return register;
329 }
330
331
332
333
334
335 public String[] getSymbols() {
336 return namedVariables != null ? namedVariables.keySet().toArray(new String[0]) : EMPTY_STRS;
337 }
338
339
340
341
342
343
344 public boolean isCapturedSymbol(final int symbol) {
345 return capturedVariables != null && capturedVariables.containsKey(symbol);
346 }
347
348
349
350
351
352
353 public boolean isLexical(final int s) {
354 return lexicalVariables != null && s >= 0 && lexicalVariables.hasSymbol(s);
355 }
356 }