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