001: /*BEGIN_COPYRIGHT_BLOCK
002: *
003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are met:
008: * * Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.
010: * * Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014: * names of its contributors may be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: *
029: * This software is Open Source Initiative approved Open Source Software.
030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
031: *
032: * This file is part of DrJava. Download the current version of this project
033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034: *
035: * END_COPYRIGHT_BLOCK*/
036:
037: package edu.rice.cs.drjava.model.repl;
038:
039: import java.lang.reflect.*;
040: import koala.dynamicjava.interpreter.*;
041: import koala.dynamicjava.interpreter.context.*;
042: import koala.dynamicjava.interpreter.error.*;
043: import koala.dynamicjava.tree.*;
044:
045: /**
046: * A subclass of EvaluationVisitor to do two new things.
047: * <OL>
048: * <LI>Check thread interrupted status and throw InterruptedException
049: * if the thread was interrupted.</LI>
050: * <LI>Returns Interpreter.NO_RESULT if the computation
051: * had no result. (This is instead of returning null, which
052: * DynamicJava does.</LI>
053: * </OL>
054: *
055: * This class is loaded in the Interpreter JVM, not the Main JVM.
056: * (Do not use DrJava's config framework here.)
057: *
058: * @version $Id: EvaluationVisitorExtension.java 4255 2007-08-28 19:17:37Z mgricken $
059: */
060:
061: public class EvaluationVisitorExtension extends EvaluationVisitor {
062: private Context _context;
063:
064: public EvaluationVisitorExtension(Context ctx) {
065: super (ctx);
066: _context = ctx;
067: }
068:
069: private void _checkInterrupted(Node node) {
070: // An interesting and arcane Thread fact: There are two different methods to check if a Thread is interrupted.
071: // (See the javadocs.) Thread.isInterrupted() gets the status but doesn't reset it, while Thread.interrupted()
072: // gets the status and resets it. This code did not work when I used isInterrupted.
073: if (Thread.currentThread().interrupted()) {
074: throw new InterpreterInterruptedException(node
075: .getBeginLine(), node.getBeginColumn(), node
076: .getEndLine(), node.getEndColumn());
077: }
078: }
079:
080: /* Note: protected static Object performCast(Class<?> tc, Object o) is inherited from EvaluationVisitor */
081:
082: public Object visit(WhileStatement node) {
083: _checkInterrupted(node);
084: super .visit(node);
085: return Interpreter.NO_RESULT;
086: }
087:
088: public Object visit(ForStatement node) {
089: _checkInterrupted(node);
090: super .visit(node);
091: return Interpreter.NO_RESULT;
092: }
093:
094: public Object visit(ForEachStatement node) {
095: _checkInterrupted(node);
096: super .visit(node);
097: return Interpreter.NO_RESULT;
098: }
099:
100: public Object visit(DoStatement node) {
101: _checkInterrupted(node);
102: super .visit(node);
103: return Interpreter.NO_RESULT;
104: }
105:
106: public Object visit(SwitchStatement node) {
107: _checkInterrupted(node);
108: super .visit(node);
109: return Interpreter.NO_RESULT;
110: }
111:
112: public Object visit(LabeledStatement node) {
113: _checkInterrupted(node);
114: super .visit(node);
115: return Interpreter.NO_RESULT;
116: }
117:
118: public Object visit(SynchronizedStatement node) {
119: _checkInterrupted(node);
120: super .visit(node);
121: return Interpreter.NO_RESULT;
122: }
123:
124: public Object visit(TryStatement node) {
125: _checkInterrupted(node);
126: super .visit(node);
127: return Interpreter.NO_RESULT;
128: }
129:
130: public Object visit(IfThenStatement node) {
131: _checkInterrupted(node);
132: super .visit(node);
133: return Interpreter.NO_RESULT;
134: }
135:
136: public Object visit(IfThenElseStatement node) {
137: _checkInterrupted(node);
138: super .visit(node);
139: return Interpreter.NO_RESULT;
140: }
141:
142: public Object visit(AssertStatement node) {
143: _checkInterrupted(node);
144: super .visit(node);
145: return Interpreter.NO_RESULT;
146: }
147:
148: public Object visit(BlockStatement node) {
149: _checkInterrupted(node);
150: super .visit(node);
151: return Interpreter.NO_RESULT;
152: }
153:
154: public Object visit(Literal node) {
155: _checkInterrupted(node);
156: return super .visit(node);
157: }
158:
159: /** Overrides EvaluationVisitor to enforce a proper type check at runtime. It combines code from the actual visit
160: * code in EvaluationVisitor as well as code from the modify method in VariableModifier.
161: */
162: public Object visit(VariableDeclaration node) {
163: _checkInterrupted(node);
164: Class<?> c = (Class<?>) NodeProperties.getType(node.getType());
165:
166: if (node.getInitializer() != null) {
167: Object o = performCast(c, node.getInitializer()
168: .acceptVisitor(this ));
169:
170: // Forces a runtime type-check on the cast.
171: String name = node.getName();
172:
173: if (!(c.isPrimitive() || o == null || c.isAssignableFrom(o
174: .getClass()))) {
175: Exception e = new ClassCastException(name);
176: throw new CatchedExceptionError(e, node);
177: }
178:
179: if (node.isFinal())
180: _context.setConstant(node.getName(), o);
181: else
182: _context.set(node.getName(), o);
183: } else if (node.isFinal())
184: _context.setConstant(node.getName(),
185: UninitializedObject.INSTANCE);
186: else {
187: // Non-final variables have default values, and are not uninitialized.
188: // Primitive variables have special default values, Objects default to null.
189: // Fixes bug #797515.
190: // _context.set(node.getName(), UninitializedObject.INSTANCE);
191: Object value = null;
192: if (!c.isPrimitive())
193: value = null;
194: else if (c == byte.class)
195: value = new Byte((byte) 0);
196: else if (c == short.class)
197: value = new Short((short) 0);
198: else if (c == int.class)
199: value = new Integer(0);
200: else if (c == long.class)
201: value = new Long(0L);
202: else if (c == float.class)
203: value = new Float(0.0f);
204: else if (c == double.class)
205: value = new Double(0.0d);
206: else if (c == char.class)
207: value = new Character('\u0000');
208: else if (c == boolean.class)
209: value = Boolean.valueOf(false);
210: _context.set(node.getName(), value);
211: }
212: return Interpreter.NO_RESULT;
213: }
214:
215: public Object visit(ObjectFieldAccess node) {
216: _checkInterrupted(node);
217: return super .visit(node);
218: }
219:
220: public Object visit(ObjectMethodCall node) {
221: _checkInterrupted(node);
222: Method m = (Method) node.getProperty(NodeProperties.METHOD);
223: // m.setAccessible(true);
224: Object ret = super .visit(node);
225:
226: // this workaround avoids returning null for void returns; null test intercepts array clone invocation which has
227: // no METHOD property
228: if (m != null && m.getReturnType().equals(Void.TYPE))
229: return Interpreter.NO_RESULT;
230: return ret;
231: }
232:
233: public Object visit(StaticFieldAccess node) {
234: _checkInterrupted(node);
235: return super .visit(node);
236: }
237:
238: public Object visit(SuperFieldAccess node) {
239: _checkInterrupted(node);
240: return super .visit(node);
241: }
242:
243: public Object visit(SuperMethodCall node) {
244: _checkInterrupted(node);
245: return super .visit(node);
246: }
247:
248: public Object visit(StaticMethodCall node) {
249: _checkInterrupted(node);
250: Method m = (Method) node.getProperty(NodeProperties.METHOD);
251:
252: // DynamicJava doesn't check that the method is really static!
253: if (!Modifier.isStatic(m.getModifiers())) {
254: final StringBuilder buf = new StringBuilder();
255: buf.append(m.getDeclaringClass());
256: buf.append(".");
257: buf.append(m.getName());
258: buf.append("(");
259:
260: boolean first = true;
261: Class<?>[] params = m.getParameterTypes();
262: for (int i = 0; i < params.length; i++) {
263: if (first)
264: first = false;
265: else
266: buf.append(", ");
267: buf.append(params[i].getName());
268: }
269:
270: buf.append(")");
271: buf.append(" is not a static method.");
272:
273: throw new InteractionsException(buf.toString());
274: }
275:
276: Object ret = super .visit(node);
277:
278: // workaround to not return null for void returns
279: if (m.getReturnType().equals(Void.TYPE))
280: return Interpreter.NO_RESULT;
281: else
282: return ret;
283: }
284:
285: public Object visit(SimpleAssignExpression node) {
286: _checkInterrupted(node);
287: return super .visit(node);
288: }
289:
290: public Object visit(QualifiedName node) {
291: _checkInterrupted(node);
292: return super .visit(node);
293: }
294:
295: public Object visit(TypeExpression node) {
296: _checkInterrupted(node);
297: return super .visit(node);
298: }
299:
300: public Object visit(SimpleAllocation node) {
301: _checkInterrupted(node);
302: return super .visit(node);
303: }
304:
305: public Object visit(ArrayAllocation node) {
306: _checkInterrupted(node);
307: return super .visit(node);
308: }
309:
310: public Object visit(ArrayInitializer node) {
311: _checkInterrupted(node);
312: return super .visit(node);
313: }
314:
315: public Object visit(ArrayAccess node) {
316: _checkInterrupted(node);
317: return super .visit(node);
318: }
319:
320: public Object visit(InnerAllocation node) {
321: _checkInterrupted(node);
322: return super .visit(node);
323: }
324:
325: public Object visit(ClassAllocation node) {
326: _checkInterrupted(node);
327: return super .visit(node);
328: }
329:
330: public Object visit(NotExpression node) {
331: _checkInterrupted(node);
332: return super .visit(node);
333: }
334:
335: public Object visit(ComplementExpression node) {
336: _checkInterrupted(node);
337: return super .visit(node);
338: }
339:
340: public Object visit(PlusExpression node) {
341: _checkInterrupted(node);
342: return super .visit(node);
343: }
344:
345: public Object visit(MinusExpression node) {
346: _checkInterrupted(node);
347: return super .visit(node);
348: }
349:
350: public Object visit(AddExpression node) {
351: _checkInterrupted(node);
352: return super .visit(node);
353: }
354:
355: public Object visit(AddAssignExpression node) {
356: _checkInterrupted(node);
357: return super .visit(node);
358: }
359:
360: public Object visit(SubtractExpression node) {
361: _checkInterrupted(node);
362: return super .visit(node);
363: }
364:
365: public Object visit(SubtractAssignExpression node) {
366: _checkInterrupted(node);
367: return super .visit(node);
368: }
369:
370: public Object visit(MultiplyExpression node) {
371: _checkInterrupted(node);
372: return super .visit(node);
373: }
374:
375: public Object visit(MultiplyAssignExpression node) {
376: _checkInterrupted(node);
377: return super .visit(node);
378: }
379:
380: public Object visit(DivideExpression node) {
381: _checkInterrupted(node);
382: return super .visit(node);
383: }
384:
385: public Object visit(DivideAssignExpression node) {
386: _checkInterrupted(node);
387: return super .visit(node);
388: }
389:
390: public Object visit(RemainderExpression node) {
391: _checkInterrupted(node);
392: return super .visit(node);
393: }
394:
395: public Object visit(RemainderAssignExpression node) {
396: _checkInterrupted(node);
397: return super .visit(node);
398: }
399:
400: public Object visit(EqualExpression node) {
401: _checkInterrupted(node);
402: return super .visit(node);
403: }
404:
405: public Object visit(NotEqualExpression node) {
406: _checkInterrupted(node);
407: return super .visit(node);
408: }
409:
410: public Object visit(LessExpression node) {
411: _checkInterrupted(node);
412: return super .visit(node);
413: }
414:
415: public Object visit(LessOrEqualExpression node) {
416: _checkInterrupted(node);
417: return super .visit(node);
418: }
419:
420: public Object visit(GreaterExpression node) {
421: _checkInterrupted(node);
422: return super .visit(node);
423: }
424:
425: public Object visit(GreaterOrEqualExpression node) {
426: _checkInterrupted(node);
427: return super .visit(node);
428: }
429:
430: public Object visit(InstanceOfExpression node) {
431: _checkInterrupted(node);
432: return super .visit(node);
433: }
434:
435: public Object visit(ConditionalExpression node) {
436: _checkInterrupted(node);
437: return super .visit(node);
438: }
439:
440: public Object visit(PostIncrement node) {
441: _checkInterrupted(node);
442: return super .visit(node);
443: }
444:
445: public Object visit(PreIncrement node) {
446: _checkInterrupted(node);
447: return super .visit(node);
448: }
449:
450: public Object visit(PostDecrement node) {
451: _checkInterrupted(node);
452: return super .visit(node);
453: }
454:
455: public Object visit(PreDecrement node) {
456: _checkInterrupted(node);
457: return super .visit(node);
458: }
459:
460: public Object visit(CastExpression node) {
461: _checkInterrupted(node);
462: return super .visit(node);
463: }
464:
465: public Object visit(BitAndExpression node) {
466: _checkInterrupted(node);
467: return super .visit(node);
468: }
469:
470: public Object visit(BitAndAssignExpression node) {
471: _checkInterrupted(node);
472: return super .visit(node);
473: }
474:
475: public Object visit(ExclusiveOrExpression node) {
476: _checkInterrupted(node);
477: return super .visit(node);
478: }
479:
480: public Object visit(ExclusiveOrAssignExpression node) {
481: _checkInterrupted(node);
482: return super .visit(node);
483: }
484:
485: public Object visit(BitOrExpression node) {
486: _checkInterrupted(node);
487: return super .visit(node);
488: }
489:
490: public Object visit(BitOrAssignExpression node) {
491: _checkInterrupted(node);
492: return super .visit(node);
493: }
494:
495: public Object visit(ShiftLeftExpression node) {
496: _checkInterrupted(node);
497: return super .visit(node);
498: }
499:
500: public Object visit(ShiftLeftAssignExpression node) {
501: _checkInterrupted(node);
502: return super .visit(node);
503: }
504:
505: public Object visit(ShiftRightExpression node) {
506: _checkInterrupted(node);
507: return super .visit(node);
508: }
509:
510: public Object visit(ShiftRightAssignExpression node) {
511: _checkInterrupted(node);
512: return super .visit(node);
513: }
514:
515: public Object visit(UnsignedShiftRightExpression node) {
516: _checkInterrupted(node);
517: return super .visit(node);
518: }
519:
520: public Object visit(UnsignedShiftRightAssignExpression node) {
521: _checkInterrupted(node);
522: return super .visit(node);
523: }
524:
525: public Object visit(AndExpression node) {
526: _checkInterrupted(node);
527: return super .visit(node);
528: }
529:
530: public Object visit(OrExpression node) {
531: _checkInterrupted(node);
532: return super .visit(node);
533: }
534:
535: public Object visit(FunctionCall node) {
536: _checkInterrupted(node);
537: // Method m = (Method) node.getProperty(NodeProperties.METHOD);
538: Object ret = super .visit(node);
539:
540: // workaround to not return null for void returns
541: if (Void.TYPE.equals(node.getProperty(NodeProperties.TYPE)))
542: return Interpreter.NO_RESULT;
543: else
544: return ret;
545: }
546:
547: public Object visit(PackageDeclaration node) {
548: return Interpreter.NO_RESULT;
549: }
550:
551: public Object visit(ImportDeclaration node) {
552: return Interpreter.NO_RESULT;
553: }
554:
555: public Object visit(EmptyStatement node) {
556: return Interpreter.NO_RESULT;
557: }
558:
559: public Object visit(ClassDeclaration node) {
560: return Interpreter.NO_RESULT;
561: }
562:
563: public Object visit(InterfaceDeclaration node) {
564: return Interpreter.NO_RESULT;
565: }
566:
567: public Object visit(MethodDeclaration node) {
568: return Interpreter.NO_RESULT;
569: }
570: }
|