|
1 |
| package edu.rice.cs.dynamicjava.interpreter; |
|
2 |
| |
|
3 |
| import java.util.Iterator; |
|
4 |
| import java.lang.reflect.Array; |
|
5 |
| import java.lang.reflect.Method; |
|
6 |
| import java.lang.reflect.InvocationTargetException; |
|
7 |
| import edu.rice.cs.plt.iter.IterUtil; |
|
8 |
| import edu.rice.cs.plt.iter.ReadOnlyIterator; |
|
9 |
| import edu.rice.cs.plt.lambda.WrappedException; |
|
10 |
| import edu.rice.cs.plt.tuple.Option; |
|
11 |
| |
|
12 |
| import koala.dynamicjava.tree.*; |
|
13 |
| import koala.dynamicjava.tree.visitor.*; |
|
14 |
| |
|
15 |
| import edu.rice.cs.dynamicjava.Options; |
|
16 |
| import edu.rice.cs.dynamicjava.symbol.LocalVariable; |
|
17 |
| import edu.rice.cs.dynamicjava.symbol.TypeSystem; |
|
18 |
| import edu.rice.cs.dynamicjava.symbol.SymbolUtil; |
|
19 |
| |
|
20 |
| import static koala.dynamicjava.interpreter.NodeProperties.*; |
|
21 |
| |
|
22 |
| |
|
23 |
| |
|
24 |
| |
|
25 |
| |
|
26 |
| |
|
27 |
| |
|
28 |
| |
|
29 |
| public class StatementEvaluator extends AbstractVisitor<StatementEvaluator.Result> { |
|
30 |
| |
|
31 |
| |
|
32 |
| |
|
33 |
| |
|
34 |
| |
|
35 |
| |
|
36 |
| |
|
37 |
| public static class Result { |
|
38 |
| private Option<Object> _val; |
|
39 |
| private RuntimeBindings _bindings; |
|
40 |
| |
|
41 |
0
| public Result(Object val, RuntimeBindings b) {
|
|
42 |
0
| _val = Option.some(val);
|
|
43 |
0
| _bindings = b;
|
|
44 |
| } |
|
45 |
1919
| public Result(RuntimeBindings b) {
|
|
46 |
1919
| _val = Option.none();
|
|
47 |
1919
| _bindings = b;
|
|
48 |
| } |
|
49 |
502
| public Option<Object> value() { return _val; }
|
|
50 |
1609
| public RuntimeBindings bindings() { return _bindings; }
|
|
51 |
| } |
|
52 |
| |
|
53 |
| |
|
54 |
| private final RuntimeBindings _bindings; |
|
55 |
| private final Options _opt; |
|
56 |
| |
|
57 |
1787
| public StatementEvaluator(RuntimeBindings bindings, Options opt) {
|
|
58 |
1787
| _bindings = bindings;
|
|
59 |
1787
| _opt = opt;
|
|
60 |
| } |
|
61 |
| |
|
62 |
| |
|
63 |
822
| public Result evaluateSequence(Iterable<? extends Node> nodes) {
|
|
64 |
822
| Result result = new Result(_bindings);
|
|
65 |
822
| for (Node n : nodes) {
|
|
66 |
1090
| result = n.acceptVisitor(new StatementEvaluator(result.bindings(), _opt));
|
|
67 |
| } |
|
68 |
796
| return result;
|
|
69 |
| } |
|
70 |
| |
|
71 |
| |
|
72 |
| |
|
73 |
| |
|
74 |
| |
|
75 |
| |
|
76 |
0
| @Override public Result visit(PackageDeclaration node) { return new Result(_bindings); }
|
|
77 |
9
| @Override public Result visit(ImportDeclaration node) { return new Result(_bindings); }
|
|
78 |
52
| @Override public Result visit(ClassDeclaration node) { return new Result(_bindings); }
|
|
79 |
0
| @Override public Result visit(InterfaceDeclaration node) { return new Result(_bindings); }
|
|
80 |
0
| @Override public Result visit(ConstructorDeclaration node) { return new Result(_bindings); }
|
|
81 |
183
| @Override public Result visit(MethodDeclaration node) { return new Result(_bindings); }
|
|
82 |
| |
|
83 |
326
| @Override public Result visit(VariableDeclaration node) {
|
|
84 |
| |
|
85 |
| |
|
86 |
326
| Object init = SymbolUtil.initialValue(getErasedType(node).value());
|
|
87 |
326
| RuntimeBindings newB = new RuntimeBindings(_bindings, getVariable(node), init);
|
|
88 |
326
| if (node.getInitializer() != null) {
|
|
89 |
316
| newB.set(getVariable(node), new ExpressionEvaluator(newB, _opt).value(node.getInitializer()));
|
|
90 |
| } |
|
91 |
326
| return new Result(newB);
|
|
92 |
| } |
|
93 |
| |
|
94 |
| |
|
95 |
| |
|
96 |
| |
|
97 |
| |
|
98 |
| |
|
99 |
1
| @Override public Result visit(EmptyStatement node) { return new Result(_bindings); }
|
|
100 |
| |
|
101 |
374
| @Override public Result visit(ExpressionStatement node) {
|
|
102 |
374
| if (hasStatementTranslation(node)) {
|
|
103 |
0
| return getStatementTranslation(node).acceptVisitor(this);
|
|
104 |
| } |
|
105 |
| else { |
|
106 |
374
| Object val = new ExpressionEvaluator(_bindings, _opt).value(node.getExpression());
|
|
107 |
374
| if (node.getHasSemicolon() || getType(node.getExpression()).equals(TypeSystem.VOID)) {
|
|
108 |
374
| return new Result(_bindings);
|
|
109 |
| } |
|
110 |
0
| else { return new Result(val, _bindings); }
|
|
111 |
| } |
|
112 |
| } |
|
113 |
| |
|
114 |
3
| @Override public Result visit(WhileStatement node) {
|
|
115 |
3
| ExpressionEvaluator eval = new ExpressionEvaluator(_bindings, _opt);
|
|
116 |
3
| try {
|
|
117 |
3
| while ((Boolean) eval.value(node.getCondition())) {
|
|
118 |
20
| try { node.getBody().acceptVisitor(this); }
|
|
119 |
| catch (ContinueException e) { |
|
120 |
0
| if (e.hasLabel() && !node.hasLabel(e.label())) { throw e; }
|
|
121 |
| } |
|
122 |
| } |
|
123 |
| } |
|
124 |
| catch (BreakException e) { |
|
125 |
0
| if (e.hasLabel() && !node.hasLabel(e.label())) { throw e; }
|
|
126 |
| } |
|
127 |
3
| return new Result(_bindings);
|
|
128 |
| } |
|
129 |
| |
|
130 |
9
| @Override public Result visit(final ForEachStatement node) {
|
|
131 |
| |
|
132 |
| |
|
133 |
| |
|
134 |
9
| LocalVariable param = getVariable(node.getParameter());
|
|
135 |
9
| RuntimeBindings newB = new RuntimeBindings(_bindings, param, null);
|
|
136 |
9
| final Object iterable = new ExpressionEvaluator(newB, _opt).value(node.getCollection());
|
|
137 |
0
| if (iterable == null) { throw new WrappedException(new EvaluatorException(new NullPointerException())); }
|
|
138 |
9
| Iterator<?> iter;
|
|
139 |
9
| if (iterable.getClass().isArray()) {
|
|
140 |
6
| final int length = Array.getLength(iterable);
|
|
141 |
6
| iter = new ReadOnlyIterator<Object>() {
|
|
142 |
| int i = 0; |
|
143 |
25
| public boolean hasNext() { return i < length; }
|
|
144 |
19
| public Object next() {
|
|
145 |
19
| try { return Array.get(iterable, i++); }
|
|
146 |
0
| catch (ArrayIndexOutOfBoundsException e) { throw new WrappedException(new EvaluatorException(e)); }
|
|
147 |
| } |
|
148 |
| }; |
|
149 |
| } |
|
150 |
| else { |
|
151 |
3
| try {
|
|
152 |
3
| Method getIterator = iterable.getClass().getMethod("iterator");
|
|
153 |
3
| try { getIterator.setAccessible(true); }
|
|
154 |
| catch (SecurityException e) { } |
|
155 |
3
| iter = (Iterator<?>) getIterator.invoke(iterable);
|
|
156 |
| } |
|
157 |
0
| catch (NoSuchMethodException e) { throw new RuntimeException(e); }
|
|
158 |
0
| catch (IllegalAccessException e) { throw new RuntimeException(e); }
|
|
159 |
0
| catch (InvocationTargetException e) { throw new WrappedException(new EvaluatorException(e.getCause())); }
|
|
160 |
| } |
|
161 |
| |
|
162 |
9
| StatementEvaluator seval = new StatementEvaluator(newB, _opt);
|
|
163 |
9
| try {
|
|
164 |
9
| while (true) {
|
|
165 |
38
| Object elt;
|
|
166 |
38
| try {
|
|
167 |
9
| if (!iter.hasNext()) { break; }
|
|
168 |
29
| elt = iter.next();
|
|
169 |
| } |
|
170 |
0
| catch (Throwable t) { throw new WrappedException(new EvaluatorException(t)); }
|
|
171 |
| |
|
172 |
29
| try {
|
|
173 |
29
| newB.set(param, elt);
|
|
174 |
29
| node.getBody().acceptVisitor(seval);
|
|
175 |
| } |
|
176 |
| catch (ContinueException e) { |
|
177 |
0
| if (e.hasLabel() && !node.hasLabel(e.label())) { throw e; }
|
|
178 |
| } |
|
179 |
| } |
|
180 |
| } |
|
181 |
| catch (BreakException e) { |
|
182 |
0
| if (e.hasLabel() && !node.hasLabel(e.label())) { throw e; }
|
|
183 |
| } |
|
184 |
9
| return new Result(_bindings);
|
|
185 |
| } |
|
186 |
| |
|
187 |
17
| @Override public Result visit(ForStatement node) {
|
|
188 |
17
| RuntimeBindings newB = _bindings;
|
|
189 |
17
| if (node.getInitialization() != null) {
|
|
190 |
17
| newB = evaluateSequence(node.getInitialization()).bindings();
|
|
191 |
| } |
|
192 |
17
| Expression cond = node.getCondition();
|
|
193 |
17
| Iterable<Node> update = node.getUpdate();
|
|
194 |
17
| ExpressionEvaluator eval = new ExpressionEvaluator(newB, _opt);
|
|
195 |
17
| StatementEvaluator seval = new StatementEvaluator(newB, _opt);
|
|
196 |
17
| try {
|
|
197 |
17
| while (cond == null || (Boolean) eval.value(cond)) {
|
|
198 |
44
| try { node.getBody().acceptVisitor(seval); }
|
|
199 |
| catch (ContinueException e) { |
|
200 |
0
| if (e.hasLabel() && !node.hasLabel(e.label())) { throw e; }
|
|
201 |
| } |
|
202 |
44
| if (update != null) { seval.evaluateSequence(update); }
|
|
203 |
| } |
|
204 |
| } |
|
205 |
| catch (BreakException e) { |
|
206 |
0
| if (e.hasLabel() && !node.hasLabel(e.label())) { throw e; }
|
|
207 |
| } |
|
208 |
17
| return new Result(_bindings);
|
|
209 |
| } |
|
210 |
| |
|
211 |
3
| @Override public Result visit(DoStatement node) {
|
|
212 |
3
| ExpressionEvaluator eval = new ExpressionEvaluator(_bindings, _opt);
|
|
213 |
3
| try {
|
|
214 |
3
| do {
|
|
215 |
21
| try { node.getBody().acceptVisitor(this); }
|
|
216 |
| catch (ContinueException e) { |
|
217 |
0
| if (e.hasLabel() && !node.hasLabel(e.label())) { throw e; }
|
|
218 |
| } |
|
219 |
21
| } while ((Boolean) eval.value(node.getCondition()));
|
|
220 |
| } catch (BreakException e) { |
|
221 |
0
| if (e.hasLabel() && !node.hasLabel(e.label())) { throw e; }
|
|
222 |
| } |
|
223 |
3
| return new Result(_bindings);
|
|
224 |
| } |
|
225 |
| |
|
226 |
0
| @Override public Result visit(SwitchStatement node) {
|
|
227 |
0
| ExpressionEvaluator eval = new ExpressionEvaluator(_bindings, _opt);
|
|
228 |
0
| Object sel = eval.value(node.getSelector());
|
|
229 |
0
| Iterator<SwitchBlock> body = node.getBindings().iterator();
|
|
230 |
| |
|
231 |
| |
|
232 |
0
| for (SwitchBlock block : node.getBindings()) {
|
|
233 |
0
| if (block.getExpression() != null && eval.value(block.getExpression()).equals(sel)) {
|
|
234 |
0
| break;
|
|
235 |
| } |
|
236 |
0
| else { body.next(); }
|
|
237 |
| } |
|
238 |
| |
|
239 |
| |
|
240 |
0
| if (!body.hasNext()) {
|
|
241 |
0
| body = node.getBindings().iterator();
|
|
242 |
0
| for (SwitchBlock block : node.getBindings()) {
|
|
243 |
0
| if (block.getExpression() == null) { break; }
|
|
244 |
0
| else { body.next(); }
|
|
245 |
| } |
|
246 |
| } |
|
247 |
| |
|
248 |
0
| Iterable<Node> toEvaluate = IterUtil.empty();
|
|
249 |
0
| while (body.hasNext()) { toEvaluate = IterUtil.compose(toEvaluate, body.next().getStatements()); }
|
|
250 |
0
| try { evaluateSequence(toEvaluate); }
|
|
251 |
| catch (BreakException e) { |
|
252 |
0
| if (e.hasLabel()) { throw e; }
|
|
253 |
| } |
|
254 |
0
| return new Result(_bindings);
|
|
255 |
| } |
|
256 |
| |
|
257 |
0
| @Override public Result visit(LabeledStatement node) {
|
|
258 |
0
| try { node.getStatement().acceptVisitor(this); }
|
|
259 |
| catch (BreakException e) { |
|
260 |
0
| if (!e.hasLabel() || !e.label().equals(node.getLabel())) { throw e; }
|
|
261 |
| } |
|
262 |
0
| return new Result(_bindings);
|
|
263 |
| } |
|
264 |
| |
|
265 |
0
| @Override public Result visit(SynchronizedStatement node) {
|
|
266 |
0
| synchronized (new ExpressionEvaluator(_bindings, _opt).value(node.getLock())) {
|
|
267 |
0
| node.getBody().acceptVisitor(this);
|
|
268 |
| } |
|
269 |
0
| return new Result(_bindings);
|
|
270 |
| } |
|
271 |
| |
|
272 |
0
| @Override public Result visit(BreakStatement node) {
|
|
273 |
0
| if (node.getLabel() == null) { throw new BreakException(); }
|
|
274 |
0
| else { throw new BreakException(node.getLabel()); }
|
|
275 |
| } |
|
276 |
| |
|
277 |
0
| @Override public Result visit(ContinueStatement node) {
|
|
278 |
0
| if (node.getLabel() == null) { throw new ContinueException(); }
|
|
279 |
0
| else { throw new ContinueException(node.getLabel()); }
|
|
280 |
| } |
|
281 |
| |
|
282 |
0
| @Override public Result visit(TryStatement node) {
|
|
283 |
0
| try { node.getTryBlock().acceptVisitor(this); }
|
|
284 |
| catch (WrappedException e) { |
|
285 |
0
| if (e.getCause() instanceof EvaluatorException) {
|
|
286 |
0
| Throwable t = e.getCause().getCause();
|
|
287 |
0
| boolean handled = false;
|
|
288 |
0
| for (CatchStatement cs : node.getCatchStatements()) {
|
|
289 |
0
| if (getErasedType(cs).value().isInstance(t)) {
|
|
290 |
0
| handled = true;
|
|
291 |
0
| RuntimeBindings newB = new RuntimeBindings(_bindings, getVariable(cs.getException()), t);
|
|
292 |
0
| cs.getBlock().acceptVisitor(new StatementEvaluator(newB, _opt));
|
|
293 |
0
| break;
|
|
294 |
| } |
|
295 |
| } |
|
296 |
0
| if (!handled) { throw e; }
|
|
297 |
| } |
|
298 |
0
| else { throw e; }
|
|
299 |
| } |
|
300 |
| finally { |
|
301 |
0
| if (node.getFinallyBlock() != null) { node.getFinallyBlock().acceptVisitor(this); }
|
|
302 |
| } |
|
303 |
0
| return new Result(_bindings);
|
|
304 |
| } |
|
305 |
| |
|
306 |
0
| @Override public Result visit(ThrowStatement node) {
|
|
307 |
0
| Throwable t = (Throwable) new ExpressionEvaluator(_bindings, _opt).value(node.getExpression());
|
|
308 |
| |
|
309 |
0
| if (t == null) {
|
|
310 |
| |
|
311 |
| |
|
312 |
| |
|
313 |
| |
|
314 |
0
| t = new NullPointerException();
|
|
315 |
0
| t.setStackTrace(new StackTraceElement[0]);
|
|
316 |
| } |
|
317 |
0
| throw new WrappedException(new EvaluatorException(t));
|
|
318 |
| } |
|
319 |
| |
|
320 |
26
| @Override public Result visit(ReturnStatement node) {
|
|
321 |
0
| if (node.getExpression() == null) { throw new ReturnException(); }
|
|
322 |
| else { |
|
323 |
26
| Object result = new ExpressionEvaluator(_bindings, _opt).value(node.getExpression());
|
|
324 |
26
| throw new ReturnException(result);
|
|
325 |
| } |
|
326 |
| } |
|
327 |
| |
|
328 |
114
| @Override public Result visit(IfThenStatement node) {
|
|
329 |
114
| if ((Boolean) new ExpressionEvaluator(_bindings, _opt).value(node.getCondition())) {
|
|
330 |
3
| node.getThenStatement().acceptVisitor(this);
|
|
331 |
| } |
|
332 |
114
| return new Result(_bindings);
|
|
333 |
| } |
|
334 |
| |
|
335 |
6
| @Override public Result visit(IfThenElseStatement node) {
|
|
336 |
6
| if ((Boolean) new ExpressionEvaluator(_bindings, _opt).value(node.getCondition())) {
|
|
337 |
3
| node.getThenStatement().acceptVisitor(this);
|
|
338 |
| } |
|
339 |
| else { |
|
340 |
3
| node.getElseStatement().acceptVisitor(this);
|
|
341 |
| } |
|
342 |
6
| return new Result(_bindings);
|
|
343 |
| } |
|
344 |
| |
|
345 |
0
| @Override public Result visit(AssertStatement node) {
|
|
346 |
| |
|
347 |
0
| ExpressionEvaluator eval = new ExpressionEvaluator(_bindings, _opt);
|
|
348 |
0
| if ((Boolean) eval.value(node.getCondition())) {
|
|
349 |
0
| return new Result(_bindings);
|
|
350 |
| } |
|
351 |
| else { |
|
352 |
0
| if (node.getFailString() == null) {
|
|
353 |
0
| throw new WrappedException(new EvaluatorException(new AssertionError()));
|
|
354 |
| } |
|
355 |
| else { |
|
356 |
0
| Object messageObj = eval.value(node.getFailString());
|
|
357 |
0
| String message;
|
|
358 |
0
| try { message = messageObj.toString(); }
|
|
359 |
0
| catch (Throwable t) { throw new WrappedException(new EvaluatorException(t)); }
|
|
360 |
0
| throw new WrappedException(new EvaluatorException(new AssertionError(message)));
|
|
361 |
| } |
|
362 |
| } |
|
363 |
| } |
|
364 |
| |
|
365 |
259
| @Override public Result visit(BlockStatement node) {
|
|
366 |
259
| return evaluateSequence(node.getStatements());
|
|
367 |
| } |
|
368 |
| |
|
369 |
| |
|
370 |
| public static class ControlFlowException extends RuntimeException {} |
|
371 |
| |
|
372 |
| public static class LabelControlException extends ControlFlowException { |
|
373 |
| private final String _label; |
|
374 |
0
| public LabelControlException() { _label = null; }
|
|
375 |
0
| public LabelControlException(String label) { _label = label; }
|
|
376 |
0
| public boolean hasLabel() { return _label != null; }
|
|
377 |
0
| public String label() { return _label; }
|
|
378 |
| } |
|
379 |
| |
|
380 |
| public static class ContinueException extends LabelControlException { |
|
381 |
0
| public ContinueException() { super(); }
|
|
382 |
0
| public ContinueException(String label) { super(label); }
|
|
383 |
| } |
|
384 |
| |
|
385 |
| public static class BreakException extends LabelControlException { |
|
386 |
0
| public BreakException() { super(); }
|
|
387 |
0
| public BreakException(String label) { super(label); }
|
|
388 |
| } |
|
389 |
| |
|
390 |
| public static class ReturnException extends ControlFlowException { |
|
391 |
| private final Option<Object> _value; |
|
392 |
0
| public ReturnException() { _value = Option.none(); }
|
|
393 |
26
| public ReturnException(Object value) { _value = Option.some(value); }
|
|
394 |
26
| public Option<Object> value() { return _value; }
|
|
395 |
| } |
|
396 |
| |
|
397 |
| |
|
398 |
| } |