Code Search for Developers
 
 
  

EvaluationVisitor.java from DrJava at Krugle


Show EvaluationVisitor.java syntax highlighted

/*
 * DynamicJava - Copyright (C) 1999-2001
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the
 * following conditions:
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL DYADE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Dyade shall not be
 * used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization from
 * Dyade.
 *
 */

package koala.dynamicjava.interpreter;

import java.lang.reflect.*;
import java.util.*;

import koala.dynamicjava.interpreter.context.*;
import koala.dynamicjava.interpreter.error.*;
import koala.dynamicjava.interpreter.modifier.*;
import koala.dynamicjava.tree.*;
import koala.dynamicjava.tree.tiger.*;
import koala.dynamicjava.tree.visitor.*;
import koala.dynamicjava.util.*;

/**
 * This tree visitor evaluates each node of a syntax tree
 *
 * @author Stephane Hillion
 * @version 1.2 - 2001/01/23
 */

public class EvaluationVisitor extends VisitorObject<Object> {
  /**
   * The current context
   */
  private Context context;

  /**
   * Creates a new visitor
   * @param ctx the current context
   */
  public EvaluationVisitor(Context ctx) {
    context = ctx;
  }

  /**
   * Visits a WhileStatement
   * @param node the node to visit
   */
  public Object visit(WhileStatement node) {
    try {
      while (((Boolean)node.getCondition().acceptVisitor(this)).booleanValue()) {
        try {
          node.getBody().acceptVisitor(this);
        } catch (ContinueException e) {
          // 'continue' statement management
          if (e.isLabeled() && !node.hasLabel(e.getLabel())) {
            throw e;
          }
        }
      }
    } catch (BreakException e) {
      // 'break' statement management
      if (e.isLabeled() && !node.hasLabel(e.getLabel())) {
        throw e;
      }
    }
    return null;
  }

  /**
   * Visits a ForEachStatement
   * @param node the node to visit
   */
  public Object visit(ForEachStatement node){
    Set<AbstractVariable> vars = (Set<AbstractVariable>)node.getProperty(NodeProperties.VARIABLES);  /* Type erasure bites! */
      context.enterScope(vars);
        
    FormalParameter formalparam = node.getParameter();
    Expression collection = node.getCollection();
    Class<?> collTypeClass = NodeProperties.getType(collection);
    Node body = node.getBody();
    
    /*examples*/
    /*
     * Collection<String> c = ... ;
     * for(String s: c){
     *   ...
     * }
     * translates to:
     * for(Iterator<E> #i = Expression.iterator(); #i.hasNext(); ){
     *    FormalParameter = #i.next();
     *    statement...
     * }
     * Collection c = ... ;
     * for(Object o: c){
     *   String s = (String) o;
     *   ...
     * }
     * translates to:
     * for(Iterator #i = Expression.iterator(); #i.hasNext(); ){
     *    FormalParameter = #i.next();
     *    statement...
     * }
     * 
     * int sum(int[] a){
     *    int sum = 0;
     *    for(int i:a){
     *      sum+=i;
     *    return sum
     * }
     * translates to:
     * for(int #i=0; #i<a.length; #i++){
     *   FormalParameter=a[#i];
     *   statement...
     * }
     * ============================================================================
     */
    Method m;
    Class<?> c;
    Expression exp;
    /************************************************************************************/
    /**  create an initialization  ******************************************************/
    /************************************************************************************/

    VariableDeclaration init;
    if(collTypeClass.isArray()){
      exp = new IntegerLiteral("0");

      exp.setProperty(NodeProperties.TYPE, int.class);
      
      init = new VariableDeclaration(false,
                                     new IntTypeName(),
                                     node.getVars().get(0),
                                     exp);
      
      c = NodeProperties.getType(exp);
      init.setProperty(NodeProperties.TYPE, c);
      init.getType().setProperty(NodeProperties.TYPE, c);
    }else{
      exp = new ObjectMethodCall(node.getCollection(), "iterator", null,
                                                  "", 0, 0, 0, 0);
      /* these next fields refer to fileame and row/col of source
       * but there isn't any source, b/c i'm making it... */
      
      /* set properties of exp */
      m = null;
      try {
        m = context.lookupMethod(((ObjectMethodCall)exp).getExpression(), "iterator", Constants.EMPTY_CLASS_ARRAY);
      }catch(NoSuchMethodException e){
        /* this is very bad */
        /* should never happen, b/c everything has typechecked etc and been ok'd */
      }catch(MethodModificationError e){
        /* ths is very bad */
        /* should never happen, b/c everything has typechecked etc and been ok'd */
      } 
      exp.setProperty(NodeProperties.METHOD, m);
      exp.setProperty(NodeProperties.TYPE,   m.getReturnType());
      
      /* done setting properties */
      IdentifierToken javaId = new Identifier("java");
      IdentifierToken utilId = new Identifier("util");
      IdentifierToken iteratorId = new Identifier("Iterator");
      List<IdentifierToken> ids = new LinkedList<IdentifierToken>();
      ids.add(javaId); ids.add(utilId); ids.add(iteratorId);
      
      
      
      List<List<? extends koala.dynamicjava.tree.TypeName>> typeArgs = new LinkedList<List<? extends koala.dynamicjava.tree.TypeName>>();
      List<koala.dynamicjava.tree.TypeName> arg1 = new LinkedList<koala.dynamicjava.tree.TypeName>();
      arg1.add(formalparam.getType());
      typeArgs.add(arg1);
      init = new VariableDeclaration(false,
                                     new GenericReferenceTypeName(ids,typeArgs),
                                     node.getVars().get(0),
                                     exp);
      
      c = NodeProperties.getType(exp);
      init.setProperty(NodeProperties.TYPE, c);
      init.getType().setProperty(NodeProperties.TYPE, c);
      
    }
      
      
    /************************************************************************************/
    /**  visit initialization  **********************************************************/
    /************************************************************************************/
    init.acceptVisitor(this);
    //everything is initialzized
    

    
    
    
    
    
    
    /************************************************************************************/
    /**  create a condition  ************************************************************/
    /************************************************************************************/
    Node condition;
    if(collTypeClass.isArray()){
      // make lhs
      IdentifierToken newforcounter = new Identifier(node.getVars().get(0));
      List<IdentifierToken> listForQualifiedName = new LinkedList<IdentifierToken>();
      listForQualifiedName.add(newforcounter);
      QualifiedName lhs = new QualifiedName(listForQualifiedName);
      
      
      
      // make rhs
      LinkedList<Expression> argsToGetLength = new LinkedList<Expression>();
      argsToGetLength.add(collection);

      /*
      newforcounter = new Identifier("Array");
      listForQualifiedName = new LinkedList<IdentifierToken>();
      listForQualifiedName.add(newforcounter);
      QualifiedName qf = new QualifiedName(listForQualifiedName);
      qf.setProperty(NodeProperties.TYPE, Array.class);
      ObjectMethodCall rhs = new ObjectMethodCall(qf, "getLength", argsToGetLength,
                                       "", 0, 0, 0, 0);
      */

      
      /* since we're finding the length of the array, the dimension is always 1 */
      ArrayTypeName art = new ArrayTypeName(formalparam.getType(), 1);
      
      StaticMethodCall rhs = new StaticMethodCall(art, "getLength", argsToGetLength);
      
      
      m = null;
      try {
        Class<?>[] lookupArgs= {Object.class};
        m = Array.class.getMethod("getLength", lookupArgs);
      }catch(NoSuchMethodException e){
        /* this is very bad */
        /* should never happen, b/c everything has typechecked etc and been ok'd */
      }catch(MethodModificationError e){
        /* ths is very bad */
        /* should never happen, b/c everything has typechecked etc and been ok'd */
      } 
      
      rhs.setProperty(NodeProperties.METHOD, m);
      rhs.setProperty(NodeProperties.TYPE,   m.getReturnType());
      
      
      
      condition = new LessExpression(lhs, rhs);
      condition.setProperty(NodeProperties.TYPE,   new BooleanTypeName());
      
      /* 4-17-04 */
      /* maybe i need to set the type of hte condition node? */
      
      
      
    }else{
      IdentifierToken newforcounter = new Identifier(node.getVars().get(0));
      List<IdentifierToken> listForQualifiedName = new LinkedList<IdentifierToken>();
      listForQualifiedName.add(newforcounter);
      QualifiedName qf = new QualifiedName(listForQualifiedName);
      condition = new ObjectMethodCall(qf, "hasNext", null,
                                       "", 0, 0, 0, 0);
      /* these next fields refer to fileame and row/col of source
       * but there isn't any source, b/c i'm making it... */
      /* set properties of condition */
      Method m2 = null;
      try {
        m2 = context.lookupMethod(exp, "hasNext", Constants.EMPTY_CLASS_ARRAY);
      }catch(NoSuchMethodException e){
        /* this is very bad */
        /* should never happen, b/c everything has typechecked etc and been ok'd */
      }catch(MethodModificationError e){
        /* ths is very bad */
        /* should never happen, b/c everything has typechecked etc and been ok'd */
      }
      condition.setProperty(NodeProperties.METHOD, m2);
      condition.setProperty(NodeProperties.TYPE,   m2.getReturnType());
      /* done setting properties */
    }

    
    
    /************************************************************************************/
    /**  create an update statement  ****************************************************/
    /************************************************************************************/
    Node statement1;
    Expression assignment = null;
    if(collTypeClass.isArray()){
      Identifier counterName = new Identifier(node.getVars().get(0));
      LinkedList<IdentifierToken> listForQualifiedName = new LinkedList<IdentifierToken>();
      listForQualifiedName.add(counterName);
      QualifiedName arg = new QualifiedName(listForQualifiedName);
      VariableModifier mod = new VariableModifier(arg, int.class);
      arg.setProperty(NodeProperties.MODIFIER, mod);
      statement1 = new AddAssignExpression(arg, new IntegerLiteral("1"));
      statement1.setProperty(NodeProperties.TYPE, int.class);
      
      Expression arrayaccess = new ArrayAccess(collection, arg);

      listForQualifiedName = new LinkedList<IdentifierToken>();
      listForQualifiedName.add(new Identifier(formalparam.getName()));
      arg = new QualifiedName(listForQualifiedName);
      mod = new VariableModifier(arg, collTypeClass.getComponentType());
      arg.setProperty(NodeProperties.MODIFIER, mod);
      assignment  = new SimpleAssignExpression(arg, arrayaccess);
      assignment.setProperty(NodeProperties.TYPE, collTypeClass.getComponentType());
    }else{
      IdentifierToken newforcounter = new Identifier(node.getVars().get(0));
      List<IdentifierToken> listForQualifiedName = new LinkedList<IdentifierToken>();
      listForQualifiedName.add(newforcounter);
      QualifiedName qf = new QualifiedName(listForQualifiedName);
      ObjectMethodCall next = new ObjectMethodCall(qf, "next", null,
                                                   "", 0, 0, 0, 0);
      /* these next fields refer to fileame and row/col of source
       * but there isn't any source, b/c i'm making it... */
      /* set properties of next */
      Method m3 = null;
      try {
        m3 = context.lookupMethod(exp, "next", Constants.EMPTY_CLASS_ARRAY);
      }catch(NoSuchMethodException e){
        /* this is very bad */
        /* should never happen, b/c everything has typechecked etc and been ok'd */
      }catch(MethodModificationError e){
        /* ths is very bad */
        /* should never happen, b/c everything has typechecked etc and been ok'd */
      }
      next.setProperty(NodeProperties.METHOD, m3);
      next.setProperty(NodeProperties.TYPE,   m3.getReturnType());
      /* done setting properties */
      
      
      statement1 = new VariableDeclaration(formalparam.isFinal(), 
                                              formalparam.getType(), 
                                              formalparam.getName(), 
                                              next);
      statement1.setProperty(NodeProperties.TYPE, NodeProperties.getType(next));
      c = NodeProperties.getType(next);
      statement1.setProperty(NodeProperties.TYPE, c);
      ((VariableDeclaration)statement1).getType().setProperty(NodeProperties.TYPE, c);
    }
    
    
    
    
    /************************************************************************************/
    /**  evaluate the foreach  **********************************************************/
    /************************************************************************************/
    
    
    
    while(((Boolean)condition.acceptVisitor(this)).booleanValue()){
      /* if the foreach uses an array, then it will have an assignment instruction that must be run */
      /* otherwise it will be null */
      if(assignment != null){
        assignment.acceptVisitor(this);
      }
      statement1.acceptVisitor(this);
      body.acceptVisitor(this);
    }
    
    context.leaveScope();
    
    return null;
  }
  
  /**
   * Visits a ForStatement
   * @param node the node to visit
   */
  public Object visit(ForStatement node) {
    try {
      Set<AbstractVariable> vars = (Set<AbstractVariable>)node.getProperty(NodeProperties.VARIABLES); /* Type erasure bites! */
      context.enterScope(vars);

      // Interpret the initialization expressions
      if (node.getInitialization() != null) {
        Iterator<Node> it = node.getInitialization().iterator();
        while (it.hasNext()) {
          it.next().acceptVisitor(this);
        }
      }

      // Interpret the loop
      try {
        Expression cond   = node.getCondition();
        List<Node>  update = node.getUpdate();
        while (cond == null ||
               ((Boolean)cond.acceptVisitor(this)).booleanValue()) {
          try {
            node.getBody().acceptVisitor(this);
          } catch (ContinueException e) {
            // 'continue' statement management
            if (e.isLabeled() && !node.hasLabel(e.getLabel())) {
              throw e;
            }
          }
          // Interpret the update statements
          if (update != null) {
            Iterator<Node> it = update.iterator();
            while (it.hasNext()) {
              it.next().acceptVisitor(this);
            }
          }
        }
      } catch (BreakException e) {
        // 'break' statement management
        if (e.isLabeled() && !node.hasLabel(e.getLabel())) {
          throw e;
        }
      }
    } finally {
      // Always leave the current scope
      context.leaveScope();
    }
    return null;
  }

  /**
   * Visits a DoStatement
   * @param node the node to visit
   */
  public Object visit(DoStatement node) {
    try {
      // Interpret the loop
      do {
        try {
          node.getBody().acceptVisitor(this);
        } catch (ContinueException e) {
          // 'continue' statement management
          if (e.isLabeled() && !node.hasLabel(e.getLabel())) {
            throw e;
          }
        }
      } while (((Boolean)node.getCondition().acceptVisitor(this)).booleanValue());
    } catch (BreakException e) {
      // 'break' statement management
      if (e.isLabeled() && !node.hasLabel(e.getLabel())) {
        throw e;
      }
    }
    return null;
  }

  /**
   * Visits a SwitchStatement
   * @param node the node to visit
   */
  public Object visit(SwitchStatement node) {
    try {
      boolean processed = false;

      // Evaluate the choice expression
      Object o = node.getSelector().acceptVisitor(this);
      if (o instanceof Character) {
        o = new Integer(((Character)o).charValue());
      }
      
      Object sel; // an Enum or a Number - no common ancestor except Object :(
      // used to be n
      
      Class<?> EnumClass = (TigerUtilities.isTigerEnabled() ? Class.forName("java.lang.Enum") : null);
      if (TigerUtilities.isTigerEnabled() && o.getClass().getSuperclass() == EnumClass){
        sel = /*(Enum)*/ o;
      }
      else {
        sel = (Number)o;
      }

      // Search for the matching label
      ListIterator<SwitchBlock> it = node.getBindings().listIterator();
      ListIterator<SwitchBlock> dit = null;
      loop: while (it.hasNext()) {
        SwitchBlock sc = it.next();
        Object bind = null; // used to be 'l' (small L)
        if (sc.getExpression() != null) {
          o = sc.getExpression().acceptVisitor(this);
          if (o instanceof Character) {
            o = new Integer(((Character)o).charValue());
          }
          if(TigerUtilities.isTigerEnabled() && o.getClass().getSuperclass() == EnumClass){
            bind = /*(Enum)*/ o;
          }
          else {
            bind = (Number)o;
          }
        } else {
          dit = node.getBindings().listIterator(it.nextIndex() - 1);
        }

        if (bind != null && 
            ((sel instanceof Number) && ((Number)sel).intValue() == ((Number)bind).intValue()) || 
            (TigerUtilities.isTigerEnabled() && (sel.getClass().getSuperclass() == EnumClass) && (/*(Enum)*/sel).equals(/*(Enum)*/bind))
           ){
          processed = true;
          // When a matching label is found, interpret all the
          // remaining statements
          for(;;) {
            if (sc.getStatements() != null) {
              Iterator<Node> it2 = sc.getStatements().iterator();
               while (it2.hasNext()) {
                it2.next().acceptVisitor(this);
              }
            }
            if (it.hasNext()) {
              sc = it.next();
            } else {
              break loop;
            }
          }
        }
      }

      if (!processed && dit != null) {
        SwitchBlock sc = dit.next();
        for(;;) {
          if (sc.getStatements() != null) {
            Iterator<Node> it2 = sc.getStatements().iterator();
            while (it2.hasNext()) {
              it2.next().acceptVisitor(this);
            }
          }
          if (dit.hasNext()) {
            sc = dit.next();
          } else {
            break;
          }
        }
      }
    } catch (BreakException e) {
      // 'break' statement management
      if (e.isLabeled()) {
        throw e;
      }
    } catch(ClassNotFoundException e){
      throw new ExecutionError("Tiger is enabled, but cannot find class java.lang.Enum! Please contact the DynamicJava/DrJava team (javaplt@cs.rice.edu).");
    } catch(NoClassDefFoundError e){
      throw new ExecutionError("Tiger is enabled, but cannot find class java.lang.Enum! Please contact the DynamicJava/DrJava team (javaplt@cs.rice.edu).");
    }
    
    return null;
  }

  /**
   * Visits a LabeledStatement
   * @param node the node to visit
   */
  public Object visit(LabeledStatement node) {
    try {
      node.getStatement().acceptVisitor(this);
    } catch (BreakException e) {
      // 'break' statement management
      if (!e.isLabeled() || !e.getLabel().equals(node.getLabel())) {
        throw e;
      }
    }
    return null;
  }

  /**
   * Visits a SynchronizedStatement
   * @param node the node to visit
   */
  public Object visit(SynchronizedStatement node) {
    synchronized(node.getLock().acceptVisitor(this)) {
      node.getBody().acceptVisitor(this);
    }
    return null;
  }

  /**
   * Visits a BreakStatement
   * @param node the node to visit
   */
  public Object visit(BreakStatement node) {
    throw new BreakException("unexpected.break", node.getLabel());
  }

  /**
   * Visits a ContinueStatement
   * @param node the node to visit
   */
  public Object visit(ContinueStatement node) {
    throw new ContinueException("unexpected.continue", node.getLabel());
  }

  /**
   * Visits a TryStatement
   * @param node the node to visit
   */
  public Object visit(TryStatement node) {
    boolean handled = false;
    try {
      node.getTryBlock().acceptVisitor(this);
    } catch (Throwable e) {
      Throwable t = e;
      if (e instanceof ThrownException) {
        t = ((ThrownException)e).getException();
      } else if (e instanceof CatchedExceptionError) {
        t = ((CatchedExceptionError)e).getException();
      }

      // Find the exception handler
      Iterator<CatchStatement> it = node.getCatchStatements().iterator();
      while (it.hasNext()) {
        CatchStatement cs = it.next();
        Class<?> c = NodeProperties.getType(cs.getException().getType());
        if (c.isAssignableFrom(t.getClass())) {
          handled = true;

          // Define the exception in a new scope
          context.enterScope();
          context.define(cs.getException().getName(), t);

          // Interpret the handler
          cs.getBlock().acceptVisitor(this);
          break;
        }
      }

      if (!handled) {
        if (e instanceof Error) {
          throw (Error)e;
        } else if (e instanceof RuntimeException) {
          throw (RuntimeException)e;
        } else {
          throw new CatchedExceptionError((Exception)e, node);
        }
      }
    } finally {
      // Leave the current scope if entered
      if (handled) {
        context.leaveScope();
      }

      // Interpret the 'finally' block
      Node n;
      if ((n = node.getFinallyBlock()) != null) {
        n.acceptVisitor(this);
      }
    }
    return null;
  }

  /**
   * Visits a ThrowStatement
   * @param node the node to visit
   */
  public Object visit(ThrowStatement node) {
    throw new ThrownException((Throwable)node.getExpression().acceptVisitor(this));
  }

  /**
   * Visits a ReturnStatement
   * @param node the node to visit
   */
  public Object visit(ReturnStatement node) {
    if (node.getExpression() != null) {
      throw new ReturnException("return.statement",
                                node.getExpression().acceptVisitor(this),
                                node);
    } else {
      throw new ReturnException("return.statement", node);
    }
  }

  /**
   * Visits a IfThenStatement
   * @param node the node to visit
   */
  public Object visit(IfThenStatement node) {
    if (((Boolean)node.getCondition().acceptVisitor(this)).booleanValue()) {
      node.getThenStatement().acceptVisitor(this);
    }
    return null;
  }

  /**
   * Visits a IfThenElseStatement
   * @param node the node to visit
   */
  public Object visit(IfThenElseStatement node) {
    if (((Boolean)node.getCondition().acceptVisitor(this)).booleanValue()) {
      node.getThenStatement().acceptVisitor(this);
    } else {
      node.getElseStatement().acceptVisitor(this);
    }
    return null;
  }

  /**
   * Visits an AssertStatement
   * @param node the node to visit
   */
  public Object visit(AssertStatement node) {
    if (! (((Boolean)node.getCondition().acceptVisitor(this)).booleanValue())) {
      String toThrow = "";
      Expression n = node.getFailString();
      if(n != null) {
        toThrow = n.acceptVisitor(this).toString();
      }
      throw new AssertionError(toThrow);
    }
    return null;
  }
  
  /**
   * Visits a BlockStatement
   * @param node the node to visit
   */
  public Object visit(BlockStatement node) {
    try {
      // Enter a new scope and define the local variables
      Set<AbstractVariable> vars = (Set<AbstractVariable>)node.getProperty(NodeProperties.VARIABLES); /* Type erasure bites! */
      context.enterScope(vars);

      // Interpret the statements
      Iterator<Node> it = node.getStatements().iterator();
      while (it.hasNext()) {
        it.next().acceptVisitor(this);
      }
    } finally {
      // Always leave the current scope
      context.leaveScope();
    }
    return null;
  }

  /**
   * Visits a Literal
   * @param node the node to visit
   */
  public Object visit(Literal node) {
    return node.getValue();
  }

  /**
   * Visits a VariableDeclaration
   * @param node the node to visit
   */
  public Object visit(VariableDeclaration node) {
    Class<?> c = NodeProperties.getType(node.getType());

    if (node.getInitializer() != null) {
      Object o = performCast(c, node.getInitializer().acceptVisitor(this));

      if (node.isFinal()) {
        context.setConstant(node.getName(), o);
      } else {
        context.set(node.getName(), o);
      }
    } else {
      if (node.isFinal()) {
        context.setConstant(node.getName(), UninitializedObject.INSTANCE);
      } else {
        context.set(node.getName(), UninitializedObject.INSTANCE);
      }
    }
    return null;
  }

  /**
   * Visits an ObjectFieldAccess
   * @param node the node to visit
   */
  public Object visit(ObjectFieldAccess node) {
    Class<?> c = NodeProperties.getType(node.getExpression());

    // Evaluate the object
    Object obj  = node.getExpression().acceptVisitor(this);

    if (!c.isArray()) {
      Field f = (Field)node.getProperty(NodeProperties.FIELD);
      // Relax the protection for members
      if (context.getAccessible()) {
        f.setAccessible(true);
      }
      try {
        return f.get(obj);
      } catch (Exception e) {
        throw new CatchedExceptionError(e, node);
      }
    } else {
      // If the object is an array, the field must be 'length'.
      // This field is not a normal field and it is the only
      // way to get it
      return new Integer(Array.getLength(obj));
    }
  }

  /**
   * Private method that is used for evaluating (calling) all kinds of variable arguments method calls
   * @param typs       The types of the formal parameters
   * @param typs_len   The number of formal parameters in the method declaration
   * @param larg_size  The number of actual parameters passed to the method
   * @param it         An expression iterator that holds the values of the actual arguments, STANDING
   *                     AT THE FIRST ACTUAL PARAMETER TO BE PUT IN THE VARARGS ARRAY
   */
  private Object buildArrayOfRemainingArgs(Class<?>[] typs, int larg_size, Iterator<Expression> it) {
    if(! typs[typs.length-1].isArray())
      throw new RuntimeException("Last argument is not variable arguments");
        
    Class<?> componentType = typs[typs.length-1].getComponentType();
    Object argArray = Array.newInstance(componentType,new int[]{(larg_size-typs.length+1)});
    
    int n = larg_size-typs.length+1;
    for(int j = 0; j < n; j++){
      Object p  = it.next().acceptVisitor(this);
      Object casted = performCast(componentType, p);
      if (componentType.isPrimitive()) {
        if (componentType == boolean.class && casted instanceof Boolean) {
          Array.setBoolean(argArray, j, ((Boolean)casted).booleanValue());
        }
        else if (componentType == char.class && casted instanceof Character) {
          Array.setChar(argArray, j, ((Character)casted).charValue());
        }
        else if (casted instanceof Number) {
          if (componentType == char.class) { // just in case
            Array.setChar(argArray, j, (char)((Number)casted).intValue());
          }
          else if (componentType == byte.class) {
            Array.setByte(argArray, j, ((Number)casted).byteValue());
          }
          else if (componentType == short.class) {
            Array.setShort(argArray, j, ((Number)casted).shortValue());
          }
          else if (componentType == int.class) {
            Array.setInt(argArray, j, ((Number)casted).intValue());
          }
          else if (componentType == long.class) {
            Array.setLong(argArray, j, ((Number)casted).longValue());
          }
          else if (componentType == float.class) {
            Array.setFloat(argArray, j, ((Number)casted).floatValue());
          }
          else { // double
            Array.setDouble(argArray, j, ((Number)casted).doubleValue());
          }
        }
        else {
          throw new ClassCastException("Cannot insert object of type " + casted.getClass() + " into primitive array");
        }
      }
      else {
        Array.set(argArray, j, casted);
      }
    }
    return argArray;
  }
  
  
  /**
   * Visits an ObjectMethodCall.
   * This method expects that the argument list is compatible with
   * the declared method signature.
   * @param node the node to visit
   */
  public Object visit(ObjectMethodCall node) {
    Expression exp = node.getExpression();
    // Evaluate the receiver first
    Object obj  = exp.acceptVisitor(this);

    if (node.hasProperty(NodeProperties.METHOD)) {
      Method m    = (Method)node.getProperty(NodeProperties.METHOD);
      Class<?>[]  typs = m.getParameterTypes();

      // Relax the protection for members?
      if (context.getAccessible()) {
        m.setAccessible(true);
      }

      List<Expression> larg = node.getArguments();
      Object[] args = Constants.EMPTY_OBJECT_ARRAY;

      // Fill the arguments
      if (larg != null) {
        args = new Object[typs.length];
        ListIterator<Expression> it = larg.listIterator();
        int i  = 0;
        while (i < typs.length-1) {
          Object p  = it.next().acceptVisitor(this);
          args[i] = performCast(typs[i], p);
          i++;
        }
        if(typs.length > 0){
          Object last = null;
          if (it.hasNext()) {
            last = it.next().acceptVisitor(this);
          }
          
          if(!TigerUtilities.isVarArgs(m)) {
            args[i] = last;
          }
//          else if (last == null) {
//            Class<?> compType = typs[i].getComponentType();
//            args[i] = Array.newInstance(compType, 0);
//          }
          else if (last != null && typs[i].isAssignableFrom(last.getClass())){
            args[i] = last;
          }
          else { // Either more/less args given than expected or is of the component type
            it.previous(); // back up since we pulled the expression out a few lines above
            args[i] = buildArrayOfRemainingArgs(typs, larg.size(), it);
          }
        }
      }
      else { // larg == null, meaning that no args were given
        if (TigerUtilities.isVarArgs(m) && typs.length==1) {
            Class<?> compType = typs[0].getComponentType();
            args = new Object[]{Array.newInstance(compType, 0)};
        }
      }
      // Invoke the method
      try {
        return m.invoke(obj, args);
      }
      catch (InvocationTargetException e) {
        if (e.getTargetException() instanceof Error) {
          throw (Error)e.getTargetException();
        }
        else if (e.getTargetException() instanceof RuntimeException) {
          throw (RuntimeException)e.getTargetException();
        }
        throw new ThrownException(e.getTargetException(), node);
      }
      catch (Exception e) {
        throw new CatchedExceptionError(e, node);
      }
    }
    else {
      // If the 'method' property is not set, the object must be
      // an array and the called method must be 'clone'.
      // Since the 'clone' method of an array is not a normal
      // method, the only way to invoke it is to simulate its
      // behaviour.
      Class<?> c = NodeProperties.getType(exp);
      int len = Array.getLength(obj);
      Object result = Array.newInstance(c.getComponentType(), len);
      for (int i = 0; i < len; i++) {
        Array.set(result, i, Array.get(obj, i));
      }
      return result;
    }
  }

  /**
   * Visits a StaticFieldAccess
   * @param node the node to visit
   */
  public Object visit(StaticFieldAccess node) {
    Field f = (Field)node.getProperty(NodeProperties.FIELD);
    try {
      return f.get(null);
    } catch (Exception e) {
      throw new CatchedExceptionError(e, node);
    }
  }

  /**
   * Visits a SuperFieldAccess
   * @param node the node to visit
   */
  public Object visit(SuperFieldAccess node) {
    Field f = (Field)node.getProperty(NodeProperties.FIELD);
    try {
      return f.get(context.getHiddenArgument());
    } catch (Exception e) {
      throw new CatchedExceptionError(e, node);
    }
  }

  /**
   * Visits a SuperMethodCall
   * @param node the node to visit
   */
  public Object visit(SuperMethodCall node) {
    Method   m     = (Method)node.getProperty(NodeProperties.METHOD);
    List<Expression> larg  = node.getArguments();
    Object[] args  = Constants.EMPTY_OBJECT_ARRAY;

    Class<?>[] typs = m.getParameterTypes();
    
    // Fill the arguments
    if (larg != null) {
      ListIterator<Expression> it = larg.listIterator();
      int      i  = 0;
      args        = new Object[typs.length];
      while (i < typs.length-1) {
        args[i] = it.next().acceptVisitor(this);
        i++;
      }
      if(typs.length > 0){
        Object last = null;
        if (it.hasNext()) {
          last = it.next().acceptVisitor(this);
        }
        
        if(!TigerUtilities.isVarArgs(m)) {
          args[i] = last;
        }
        //          else if (last == null) {
        //            Class<?> compType = typs[i].getComponentType();
        //            args[i] = Array.newInstance(compType, 0);
        //          }
        else if (last != null && typs[i].isAssignableFrom(last.getClass())){
          args[i] = last;
        }
        else { // Either more/less args given than expected or is of the component type
          it.previous(); // back up since we pulled the expression out a few lines above
          args[i] = buildArrayOfRemainingArgs(typs, larg.size(), it);
        }
      }
    }
    else { // larg == null, meaning that no args were given
      if (TigerUtilities.isVarArgs(m) && typs.length==1) {
        Class<?> compType = typs[0].getComponentType();
        args = new Object[]{Array.newInstance(compType, 0)};
      }
    }

    // Invoke the method
    try {
      return m.invoke(context.getHiddenArgument(), args);
    } catch (InvocationTargetException e) {
      if (e.getTargetException() instanceof Error) {
        throw (Error)e.getTargetException();
      } else if (e.getTargetException() instanceof RuntimeException) {
        throw (RuntimeException)e.getTargetException();
      }
      throw new ThrownException(e.getTargetException());
    } catch (Exception e) {
      throw new CatchedExceptionError(e, node);
    }
  }

  /**
   * Visits a StaticMethodCall
   * @param node the node to visit
   */
  public Object visit(StaticMethodCall node) {
    Method   m    = (Method)node.getProperty(NodeProperties.METHOD);
    List<Expression> larg = node.getArguments();
    Object[] args = Constants.EMPTY_OBJECT_ARRAY;

    Class<?>[] typs = m.getParameterTypes();
    
    // Fill the arguments
    if (larg != null) {
      args = new Object[typs.length];
      ListIterator<Expression> it = larg.listIterator();
      int      i  = 0;
      while (i < typs.length-1) {
        args[i] = it.next().acceptVisitor(this);
        i++;
      }
      if(typs.length > 0){
        Object last = null;
        if (it.hasNext()) {
          last = it.next().acceptVisitor(this);
        }
        
        if(!TigerUtilities.isVarArgs(m)) {
          args[i] = last;
        }
        //          else if (last == null) {
        //            Class<?> compType = typs[i].getComponentType();
        //            args[i] = Array.newInstance(compType, 0);
        //          }
        else if (last != null && typs[i].isAssignableFrom(last.getClass())){
          args[i] = last;
        }
        else { // Either more/less args given than expected or is of the component type
          it.previous(); // back up since we pulled the expression out a few lines above
          args[i] = buildArrayOfRemainingArgs(typs, larg.size(), it);
        }
      }
    }
    else { // larg == null, meaning that no args were given
      if (TigerUtilities.isVarArgs(m) && typs.length==1) {
        Class<?> compType = typs[0].getComponentType();
        args = new Object[]{Array.newInstance(compType, 0)};
      }
    }

    // Invoke the method
    try {
      return m.invoke(null, args);
    } catch (InvocationTargetException e) {
      if (e.getTargetException() instanceof Error) {
        throw (Error)e.getTargetException();
      } else if (e.getTargetException() instanceof RuntimeException) {
        throw (RuntimeException)e.getTargetException();
      }
      throw new ThrownException(e.getTargetException());
    } catch (Exception e) {
      throw new CatchedExceptionError(e, node);
    }
  }

  /**
   * Visits a SimpleAssignExpression
   * @param node the node to visit
   */
  public Object visit(SimpleAssignExpression node) {
    Node ln = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(ln);
    mod.prepare(this, context);
    Object val  = node.getRightExpression().acceptVisitor(this);
    val = performCast(NodeProperties.getType(node), val);
    mod.modify(context, val);
    return val;
  }

  /**
   * Visits a QualifiedName
   * @param node the node to visit
   * @return the value of the local variable represented by this node
   */
  public Object visit(QualifiedName node) {
    Object result = context.get(node.getRepresentation());
    if (result == UninitializedObject.INSTANCE) {
      node.setProperty(NodeProperties.ERROR_STRINGS,
                       new String[] { node.getRepresentation() });
      throw new ExecutionError("uninitialized.variable", node);
    }
    return result;
  }

  /**
   * Visits a TypeExpression
   * @param node the node to visit
   */
  public Object visit(TypeExpression node) {
    return node.getProperty(NodeProperties.VALUE);
  }

  /**
   * Visits a SimpleAllocation
   * @param node the node to visit
   */
  public Object visit(SimpleAllocation node) {
    Constructor cons = (Constructor)node.getProperty(NodeProperties.CONSTRUCTOR);
    List<Expression> larg = node.getArguments();
    Object[] args = Constants.EMPTY_OBJECT_ARRAY;

    Class<?>[] typs = cons.getParameterTypes();

    // Fill the arguments
    if (larg != null) {
      args = new Object[typs.length];
      ListIterator<Expression> it = larg.listIterator();
      int      i  = 0;
      while (i < typs.length-1) {
        args[i++] = it.next().acceptVisitor(this);
      }
      if(typs.length > 0){
        Object last = null;
        if (it.hasNext()) {
          last = it.next().acceptVisitor(this);
        }
        
        if(!TigerUtilities.isVarArgs(cons)) {
          args[i] = last;
        }
        //          else if (last == null) {
        //            Class<?> compType = typs[i].getComponentType();
        //            args[i] = Array.newInstance(compType, 0);
        //          }
        else if (last != null && typs[i].isAssignableFrom(last.getClass())){
          args[i] = last;
        }
        else { // Either more/less args given than expected or is of the component type
          it.previous(); // back up since we pulled the expression out a few lines above
          args[i] = buildArrayOfRemainingArgs(typs, larg.size(), it);
        }
      }
    }
    else { // larg == null, meaning that no args were given
      if (TigerUtilities.isVarArgs(cons) && typs.length==1) {
        Class<?> compType = typs[0].getComponentType();
        args = new Object[]{Array.newInstance(compType, 0)};
      }
    }

    return context.invokeConstructor(node, args);
  }

  /**
   * Visits an ArrayAllocation
   * @param node the node to visit
   */
  public Object visit(ArrayAllocation node) {
    // Visits the initializer if one
    if (node.getInitialization() != null) {
      return node.getInitialization().acceptVisitor(this);
    }

    // Evaluate the size expressions
    int[]    dims = new int[node.getSizes().size()];
    Iterator<Expression> it = node.getSizes().iterator();
    int i  = 0;
    while (it.hasNext()) {
      Number n = (Number)it.next().acceptVisitor(this);
      dims[i++] = n.intValue();
    }

    // Create the array
    if (node.getDimension() != dims.length) {
      Class<?> c = NodeProperties.getComponentType(node);
      c = Array.newInstance(c, 0).getClass();
      return Array.newInstance(c, dims);
    } else {
      return Array.newInstance(NodeProperties.getComponentType(node), dims);
    }
  }

  /**
   * Visits a ArrayInitializer
   * @param node the node to visit
   */
  public Object visit(ArrayInitializer node) {
    Object result = Array.newInstance(NodeProperties.getType(node.getElementType()),
                                      node.getCells().size());

    Iterator<Expression> it = node.getCells().iterator();
    int      i  = 0;
    while (it.hasNext()) {
      Object o = it.next().acceptVisitor(this);
      Array.set(result, i++, o);
    }
    return result;
  }

  /**
   * Visits an ArrayAccess
   * @param node the node to visit
   */
  public Object visit(ArrayAccess node) {
    Object t = node.getExpression().acceptVisitor(this);
    Object o = node.getCellNumber().acceptVisitor(this);
    if (o instanceof Character) {
      o = new Integer(((Character)o).charValue());
    }
    return Array.get(t, ((Number)o).intValue());
  }

  /**
   * Visits a InnerAllocation
   * @param node the node to visit
   */
  public Object visit(InnerAllocation node) {
    Constructor cons = (Constructor)node.getProperty(NodeProperties.CONSTRUCTOR);
    Class<?>       c    = NodeProperties.getType(node);

    List<Expression> larg = node.getArguments();
    Object[]    args = null;

    Class<?>[] typs = cons.getParameterTypes();
    
    if (larg != null) {
      args = new Object[typs.length];
      args[0] = node.getExpression().acceptVisitor(this);

      ListIterator<Expression> it = larg.listIterator();
      int      i  = 1;
      while (i < typs.length-1) { // the +1 for the hidden parameter, and the -1 for the varargs
        args[i++] = it.next().acceptVisitor(this);
      }
      if(typs.length > 0){
        Object last = null;
        if (it.hasNext()) {
          last = it.next().acceptVisitor(this);
        }
        
        if(!TigerUtilities.isVarArgs(cons)) {
          args[i] = last;
        }
        //          else if (last == null) {
        //            Class<?> compType = typs[i].getComponentType();
        //            args[i] = Array.newInstance(compType, 0);
        //          }
        else if (last != null && typs[i].isAssignableFrom(last.getClass())){
          args[i] = last;
        }
        else { // Either more/less args given than expected or is of the component type
          it.previous(); // back up since we pulled the expression out a few lines above
          // Used larg.size()+1 to account for the hidden 1st parameter
          args[i] = buildArrayOfRemainingArgs(typs, larg.size()+1, it);
        }
      }
    } 
    else { // larg == null, meaning that no args were given
      if (TigerUtilities.isVarArgs(cons) && typs.length==1) {
        Class<?> compType = typs[0].getComponentType();
        args = new Object[]{node.getExpression().acceptVisitor(this), Array.newInstance(compType, 0)};
      }
      else {
        args = new Object[] { node.getExpression().acceptVisitor(this) };
      }
    }

    // Invoke the constructor
    try {
      return cons.newInstance(args);
    } catch (InvocationTargetException e) {
      if (e.getTargetException() instanceof Error) {
        throw (Error)e.getTargetException();
      }  else if (e.getTargetException() instanceof RuntimeException) {
        throw (RuntimeException)e.getTargetException();
      }
      throw new ThrownException(e.getTargetException());
    } catch (Exception e) {
      throw new CatchedExceptionError(e, node);
    }
  }

  /**
   * Visits a ClassAllocation
   * @param node the node to visit
   */
  public Object visit(ClassAllocation node) {
    Constructor cons = (Constructor)node.getProperty(NodeProperties.CONSTRUCTOR);
    List<Expression> larg = node.getArguments();
    Object[]    args = Constants.EMPTY_OBJECT_ARRAY;

    Class<?>[] typs = cons.getParameterTypes();
    
    // Fill the arguments
    if (larg != null) {
      args = new Object[typs.length];
      ListIterator<Expression> it = larg.listIterator();
      int      i  = 0;
      while (i < typs.length-1) {
        args[i++] = it.next().acceptVisitor(this);
      }
      if(typs.length > 0){
        Object last = null;
        if (it.hasNext()) {
          last = it.next().acceptVisitor(this);
        }
        
        if(!TigerUtilities.isVarArgs(cons)) {
          args[i] = last;
        }
        //          else if (last == null) {
        //            Class<?> compType = typs[i].getComponentType();
        //            args[i] = Array.newInstance(compType, 0);
        //          }
        else if (last != null && typs[i].isAssignableFrom(last.getClass())){
          args[i] = last;
        }
        else { // Either more/less args given than expected or is of the component type
          it.previous(); // back up since we pulled the expression out a few lines above
          args[i] = buildArrayOfRemainingArgs(typs, larg.size(), it);
        }
      }
    }
    else { // larg == null, meaning that no args were given
      if (TigerUtilities.isVarArgs(cons) && typs.length==1) {
        Class<?> compType = typs[0].getComponentType();
        args = new Object[]{Array.newInstance(compType, 0)};
      }
    }

    return context.invokeConstructor(node, args);
  }

  /**
   * Visits a NotExpression
   * @param node the node to visit
   */
  public Object visit(NotExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      Boolean b = (Boolean)node.getExpression().acceptVisitor(this);
      if (b.booleanValue()) {
        return Boolean.FALSE;
      } else {
        return Boolean.TRUE;
      }
    }
  }

  /**
   * Visits a ComplementExpression
   * @param node the node to visit
   */
  public Object visit(ComplementExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      Class<?>  c = NodeProperties.getType(node);
      Object o = node.getExpression().acceptVisitor(this);

      if (o instanceof Character) {
        o = new Integer(((Character)o).charValue());
      }
      if (c == int.class) {
        return new Integer(~((Number)o).intValue());
      } else {
        return new Long(~((Number)o).longValue());
      }
    }
  }

  /**
   * Visits a PlusExpression
   * @param node the node to visit
   */
  public Object visit(PlusExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.plus
        (NodeProperties.getType(node),
         node.getExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits a MinusExpression
   * @param node the node to visit
   */
  public Object visit(MinusExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.minus
        (NodeProperties.getType(node),
         node.getExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits a AddExpression
   * @param node the node to visit
   */
  public Object visit(AddExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.add
        (NodeProperties.getType(node),
         node.getLeftExpression().acceptVisitor(this),
         node.getRightExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits an AddAssignExpression
   * @param node the node to visit
   */
  public Object visit(AddAssignExpression node) {
    Node left = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(left);
    
    Object lhs = mod.prepare(this, context);
    Object rhs = node.getRightExpression().acceptVisitor(this);
    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.add(calcType, lhs,rhs);

    // Cast the result
    result = performCast(calcType, result);

    // Modify the variable and return
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits a SubtractExpression
   * @param node the node to visit
   */
  public Object visit(SubtractExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.subtract
        (NodeProperties.getType(node),
         node.getLeftExpression().acceptVisitor(this),
         node.getRightExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits an SubtractAssignExpression
   * @param node the node to visit
   */
  public Object visit(SubtractAssignExpression node) {
    Node   left = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(left);
  
    Object lhs = mod.prepare(this, context);
    Object rhs = node.getRightExpression().acceptVisitor(this);
    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.subtract(calcType, lhs, rhs);

    // Cast the result
    result = performCast(calcType, result);

    // Modify the variable and return
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits a MultiplyExpression
   * @param node the node to visit
   */
  public Object visit(MultiplyExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.multiply
        (NodeProperties.getType(node),
         node.getLeftExpression().acceptVisitor(this),
         node.getRightExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits an MultiplyAssignExpression
   * @param node the node to visit
   */
  public Object visit(MultiplyAssignExpression node) {
    Node   left = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(left);

    Object lhs = mod.prepare(this, context);
    Object rhs = node.getRightExpression().acceptVisitor(this);
    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.multiply(calcType, lhs, rhs);

    // Cast the result
    result = performCast(calcType, result);

    // Modify the variable and return
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits a DivideExpression
   * @param node the node to visit
   */
  public Object visit(DivideExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.divide
        (NodeProperties.getType(node),
         node.getLeftExpression().acceptVisitor(this),
         node.getRightExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits an DivideAssignExpression
   * @param node the node to visit
   */
  public Object visit(DivideAssignExpression node) {
    Node   left = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(left);

    Object lhs = mod.prepare(this, context);
    Object rhs = node.getRightExpression().acceptVisitor(this);
    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.divide(calcType, lhs, rhs);

    // Cast the result
    result = performCast(calcType, result);

    // Modify the variable and return
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits a RemainderExpression
   * @param node the node to visit
   */
  public Object visit(RemainderExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.remainder
        (NodeProperties.getType(node),
         node.getLeftExpression().acceptVisitor(this),
         node.getRightExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits an RemainderAssignExpression
   * @param node the node to visit
   */
  public Object visit(RemainderAssignExpression node) {
    Node   left = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(left);

    Object lhs = mod.prepare(this, context);
    Object rhs = node.getRightExpression().acceptVisitor(this);
    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.remainder(calcType, lhs, rhs);

    // Cast the result
    result = performCast(calcType, result);

    // Modify the variable and return
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits an EqualExpression
   * @param node the node to visit
   */
  public Object visit(EqualExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      Node ln = node.getLeftExpression();
      Node rn = node.getRightExpression();
      return InterpreterUtilities.equalTo(NodeProperties.getType(ln),
                                          NodeProperties.getType(rn),
                                          ln.acceptVisitor(this),
                                          rn.acceptVisitor(this));
    }
  }

  /**
   * Visits a NotEqualExpression
   * @param node the node to visit
   */
  public Object visit(NotEqualExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      Node ln = node.getLeftExpression();
      Node rn = node.getRightExpression();
      return InterpreterUtilities.notEqualTo(NodeProperties.getType(ln),
                                             NodeProperties.getType(rn),
                                             ln.acceptVisitor(this),
                                             rn.acceptVisitor(this));
    }
  }

  /**
   * Visits a LessExpression
   * @param node the node to visit
   */
  public Object visit(LessExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      Node ln = node.getLeftExpression();
      Node rn = node.getRightExpression();
      return InterpreterUtilities.lessThan(ln.acceptVisitor(this),
                                           rn.acceptVisitor(this));
    }
  }

  /**
   * Visits a LessOrEqualExpression
   * @param node the node to visit
   */
  public Object visit(LessOrEqualExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      Node ln = node.getLeftExpression();
      Node rn = node.getRightExpression();
      return InterpreterUtilities.lessOrEqual(ln.acceptVisitor(this),
                                              rn.acceptVisitor(this));
    }
  }

  /**
   * Visits a GreaterExpression
   * @param node the node to visit
   */
  public Object visit(GreaterExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      Node ln = node.getLeftExpression();
      Node rn = node.getRightExpression();
      return InterpreterUtilities.greaterThan(ln.acceptVisitor(this),
                                              rn.acceptVisitor(this));
    }
  }

  /**
   * Visits a GreaterOrEqualExpression
   * @param node the node to visit
   */
  public Object visit(GreaterOrEqualExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      Node ln = node.getLeftExpression();
      Node rn = node.getRightExpression();
      return InterpreterUtilities.greaterOrEqual(ln.acceptVisitor(this),
                                                 rn.acceptVisitor(this));
    }
  }

  /**
   * Visits a InstanceOfExpression
   * @param node the node to visit
   */
  public Object visit(InstanceOfExpression node) {
    Object v = node.getExpression().acceptVisitor(this);
    Class<?>  c = NodeProperties.getType(node.getReferenceType());

    return (c.isInstance(v)) ? Boolean.TRUE : Boolean.FALSE;
  }

  /**
   * Visits a ConditionalExpression
   * @param node the node to visit
   */
  public Object visit(ConditionalExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } 
    else {
      Boolean b = (Boolean)node.getConditionExpression().acceptVisitor(this);
      if (b.booleanValue()) {
        return node.getIfTrueExpression().acceptVisitor(this);
      } 
      else {
        return node.getIfFalseExpression().acceptVisitor(this);
      }
    }
  }

  /**
   * Visits a PostIncrement
   * @param node the node to visit
   */
  public Object visit(PostIncrement node) {
    Node exp = node.getExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(exp);
    Object v = mod.prepare(this, context);

    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.add(calcType, v, InterpreterUtilities.ONE);

    // Cast the result
    mod.modify(context, result);
    return v;
  }

  /**
   * Visits a PreIncrement
   * @param node the node to visit
   */
  public Object visit(PreIncrement node) {
    Node exp = node.getExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(exp);
    Object v = mod.prepare(this, context);

    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.add(calcType, v, InterpreterUtilities.ONE);

    // Cast the result
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits a PostDecrement
   * @param node the node to visit
   */
  public Object visit(PostDecrement node) {
    Node exp = node.getExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(exp);
    Object v = mod.prepare(this, context);

    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.subtract(calcType, v, InterpreterUtilities.ONE);

    // Cast the result
    mod.modify(context, result);
    return v;
  }

  /**
   * Visits a PreDecrement
   * @param node the node to visit
   */
  public Object visit(PreDecrement node) {
    Node exp = node.getExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(exp);
    Object v = mod.prepare(this, context);

    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.subtract(calcType, v, InterpreterUtilities.ONE);

    // Cast the result
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits a CastExpression
   * @param node the node to visit
   */
  public Object visit(CastExpression node) {
    return performCast(NodeProperties.getType(node),
                       node.getExpression().acceptVisitor(this));
  }

  /**
   * Visits a BitAndExpression
   * @param node the node to visit
   */
  public Object visit(BitAndExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.bitAnd
        (NodeProperties.getType(node),
         node.getLeftExpression().acceptVisitor(this),
         node.getRightExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits a BitAndAssignExpression
   * @param node the node to visit
   */
  public Object visit(BitAndAssignExpression node) {
    Node   left = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(left);

    Object lhs = mod.prepare(this, context);
    Object rhs = node.getRightExpression().acceptVisitor(this);
    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.bitAnd(calcType, lhs,rhs);

    // Cast the result
    result = performCast(calcType, result);


    // Modify the variable and return
    NodeProperties.getModifier(left).modify(context, result);
    return result;
  }

  /**
   * Visits a ExclusiveOrExpression
   * @param node the node to visit
   */
  public Object visit(ExclusiveOrExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.xOr
        (NodeProperties.getType(node),
         node.getLeftExpression().acceptVisitor(this),
         node.getRightExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits a ExclusiveOrAssignExpression
   * @param node the node to visit
   */
  public Object visit(ExclusiveOrAssignExpression node) {
    Node   left = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(left);

    Object lhs = mod.prepare(this, context);
    Object rhs = node.getRightExpression().acceptVisitor(this);
    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.xOr(calcType, lhs,rhs);

    // Cast the result
    result = performCast(calcType, result);

    // Modify the variable and return
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits a BitOrExpression
   * @param node the node to visit
   */
  public Object visit(BitOrExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.bitOr
        (NodeProperties.getType(node),
         node.getLeftExpression().acceptVisitor(this),
         node.getRightExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits a BitOrAssignExpression
   * @param node the node to visit
   */
  public Object visit(BitOrAssignExpression node) {
    Node   left = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(left);

    Object lhs = mod.prepare(this, context);
    Object rhs = node.getRightExpression().acceptVisitor(this);
    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.bitOr(calcType, lhs,rhs);

    // Cast the result
    result = performCast(calcType, result);

    // Modify the variable and return
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits a ShiftLeftExpression
   * @param node the node to visit
   */
  public Object visit(ShiftLeftExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.shiftLeft
        (NodeProperties.getType(node),
         node.getLeftExpression().acceptVisitor(this),
         node.getRightExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits a ShiftLeftAssignExpression
   * @param node the node to visit
   */
  public Object visit(ShiftLeftAssignExpression node) {
    Node   left = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(left);

    Object lhs = mod.prepare(this, context);
    Object rhs = node.getRightExpression().acceptVisitor(this);
    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.shiftLeft(calcType, lhs, rhs);

    // Cast the result
    result = performCast(calcType, result);

    // Modify the variable and return
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits a ShiftRightExpression
   * @param node the node to visit
   */
  public Object visit(ShiftRightExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.shiftRight
        (NodeProperties.getType(node),
         node.getLeftExpression().acceptVisitor(this),
         node.getRightExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits a ShiftRightAssignExpression
   * @param node the node to visit
   */
  public Object visit(ShiftRightAssignExpression node) {
    Node   left = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(left);

    Object lhs = mod.prepare(this, context);
    Object rhs = node.getRightExpression().acceptVisitor(this);
    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.shiftRight(calcType, lhs, rhs);

    // Cast the result
    result = performCast(calcType, result);

    // Modify the variable and return
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits a UnsignedShiftRightExpression
   * @param node the node to visit
   */
  public Object visit(UnsignedShiftRightExpression node) {
    if (node.hasProperty(NodeProperties.VALUE)) {
      // The expression is constant
      return node.getProperty(NodeProperties.VALUE);
    } else {
      return InterpreterUtilities.unsignedShiftRight
        (NodeProperties.getType(node),
         node.getLeftExpression().acceptVisitor(this),
         node.getRightExpression().acceptVisitor(this));
    }
  }

  /**
   * Visits a UnsignedShiftRightAssignExpression
   * @param node the node to visit
   */
  public Object visit(UnsignedShiftRightAssignExpression node) {
    Node   left = node.getLeftExpression();
    LeftHandSideModifier mod = NodeProperties.getModifier(left);

    Object lhs = mod.prepare(this, context);
    Object rhs = node.getRightExpression().acceptVisitor(this);
    Class<?> resType = NodeProperties.getType(node);
    Class<?> calcType = resType; // always a primitive type
    
    // This code facilitates autoboxing/unboxing
    if (TigerUtilities.isBoxingType(resType)) {
      calcType = TigerUtilities.correspondingPrimType(resType);
    }
    
    // Perform the operation
    Object result = InterpreterUtilities.unsignedShiftRight(calcType, lhs, rhs);

    // Cast the result
    result = performCast(calcType, result);

    // Modify the variable and return
    mod.modify(context, result);
    return result;
  }

  /**
   * Visits an AndExpression
   * @param node the node to visit
   */
  public Object visit(AndExpression node) {
    Expression exp = node.getLeftExpression();
    boolean b = ((Boolean)exp.acceptVisitor(this)).booleanValue();
    if (b) {
      exp = node.getRightExpression();
      b = ((Boolean)exp.acceptVisitor(this)).booleanValue();
      return (b) ? Boolean.TRUE : Boolean.FALSE;
    }
    return Boolean.FALSE;
  }

  /**
   * Visits an OrExpression
   * @param node the node to visit
   */
  public Object visit(OrExpression node) {
    Expression exp = node.getLeftExpression();
    boolean b = ((Boolean)exp.acceptVisitor(this)).booleanValue();
    if (!b) {
      exp = node.getRightExpression();
      b = ((Boolean)exp.acceptVisitor(this)).booleanValue();
      return (b) ? Boolean.TRUE : Boolean.FALSE;
    }
    return Boolean.TRUE;
  }

  /**
   * Visits a FunctionCall
   * @param node the node to visit
   */
  public Object visit(FunctionCall node) {
    MethodDeclaration md;
    md = (MethodDeclaration)node.getProperty(NodeProperties.FUNCTION);
    List<Expression> larg = node.getArguments();
    
    //If the invoked method is a varargs method the parameters must be packaged in an array
    if(md.isVarArgs())
    {
      if(larg == null) //A varargs function was called with no parameters
      {
        ArrayInitializer array = new ArrayInitializer(new LinkedList<Expression>());
        List<Expression> le = new LinkedList<Expression>();
        List<FormalParameter> lfp = md.getParameters();
        Iterator<FormalParameter> itfp = lfp.iterator();
        if(!itfp.hasNext())
          throw new IllegalStateException("Variable Arguments function does not have a formal parameter list");
        array.setElementType(itfp.next().getType());
        
        le.add(array);
        node.setArguments(le);
      }
      else //A varargs function was called with parameters
      {
        Iterator<FormalParameter> params = md.getParameters().iterator();
        Iterator<Expression> args = larg.iterator();
        LinkedList<Expression> le = new LinkedList<Expression>();
        FormalParameter fp = null;
        while(params.hasNext())
        {
         fp = params.next();
         if(params.hasNext())
           le.add(args.next());
        }
        
        LinkedList<Expression> cells = new LinkedList<Expression>();
        while(args.hasNext())
        {
          cells.add(args.next());
        }
        
        ArrayInitializer array = new ArrayInitializer(cells);
        koala.dynamicjava.tree.TypeName t = fp.getType();
        if(!(t instanceof ArrayTypeName))
          throw new IllegalStateException("Varargs method does not have an array type for its final parameter");
        array.setElementType(((ArrayTypeName)t).getElementType());
        le.add(array);
        node.setArguments(le);
      } 
    }

    // Enter a new scope and define the parameters as local variables
    Context c = new GlobalContext(context.getInterpreter());
    if (node.getArguments() != null) {
      Iterator<FormalParameter> it1  = md.getParameters().iterator();
      Iterator<Expression> it2 = node.getArguments().iterator();
      while (it1.hasNext()) {
        FormalParameter fp = it1.next();
        if (fp.isFinal()) {
          c.setConstant(fp.getName(), it2.next().acceptVisitor(this));
        } else {
          c.setVariable(fp.getName(), it2.next().acceptVisitor(this));
        }
      }
    }

    // Do the type checking of the body if needed
    Node body = md.getBody();
    if (!body.hasProperty("visited")) {
      body.setProperty("visited", null);
      ImportationManager im =
        (ImportationManager)md.getProperty(NodeProperties.IMPORTATION_MANAGER);
      Context ctx = new GlobalContext(context.getInterpreter());
      ctx.setImportationManager(im);

      NameVisitor nv = new NameVisitor(ctx,ctx);
      Iterator<FormalParameter> it = md.getParameters().iterator();
      while (it.hasNext()) {
        it.next().acceptVisitor(nv);
      }

      body.acceptVisitor(nv);

      ctx = new GlobalContext(context.getInterpreter());
      ctx.setImportationManager(im);
      ctx.setFunctions((List<MethodDeclaration>)md.getProperty(NodeProperties.FUNCTIONS)); /* Type erasure bites */

      AbstractTypeChecker tc = AbstractTypeChecker.makeTypeChecker(ctx);
      it = md.getParameters().iterator();
      while (it.hasNext()) {
        it.next().acceptVisitor(tc);
      }
      body.acceptVisitor(tc);
    }
    
    List<FormalParameter> params = md.getParameters();
    Iterator<FormalParameter> itParam = params.iterator();
    Class<?>[] typs = new Class<?>[params.size()];
    
    //Get the types of parameters that this function accepts
    int i = 0;
    while(itParam.hasNext()){
      typs[i++] = (Class<?>)itParam.next().getProperty(NodeProperties.TYPE);
    }
    
      
    // Interpret the body of the function
    try {
      body.acceptVisitor(new EvaluationVisitor(c));
    } catch (ReturnException e) {
      return e.getValue();
    }
    return null;
  }

  /**
   * Performs a dynamic cast. This method acts on primitive wrappers.
   * @param tc the target class
   * @param o  the object to cast
   */
  protected static Object performCast(Class<?> tc, Object o) {
    
    if (o == null || !tc.isPrimitive()) return o;
    
    /* oc is class of o */
    Class<?> oc = o.getClass();
      
    if (oc == Character.class) 
      return performCast(tc, new Integer(((Character)o).charValue()));
    
    else if (tc == byte.class) return new Byte(((Number)o).byteValue());
    
    else if (tc == short.class) return new Short(((Number)o).shortValue());
    
    else if (tc == int.class) return new Integer(((Number)o).intValue());
    
    else if (tc == long.class) return new Long(((Number)o).longValue());
    
    else if (tc == float.class) return new Float(((Number)o).floatValue());
    
    else if (tc == double.class) return new Double(((Number)o).doubleValue());
    
    else if (tc == char.class)
      return new Character((char)((Number)o).shortValue());
    
    else return o;
  }
}




See more files for this project here

DrJava

DrJava is a lightweight programming environment for Java designed to foster test-driven software development. It includes an intelligent program editor, an interactions pane for evaluating program text, a source level debugger, and a unit testing tool.

Project homepage: http://sourceforge.net/projects/drjava
Programming language(s): Java
License: other

  context/
    AbstractVariable.java
    Context.java
    GlobalContext.java
    MethodContext.java
    MethodModificationError.java
    NoSuchFunctionException.java
    NoSuchKeyException.java
    SimpleContext.java
    StaticContext.java
    VariableContext.java
    VariableContextTest.java
    package.html
  error/
    BreakException.java
    CatchedExceptionError.java
    ContinueException.java
    ExecutionError.java
    PossibleExecutionError.java
    ReturnException.java
    ThrownException.java
    WrongVersionException.java
    package.html
  modifier/
    ArrayModifier.java
    FinalVariableModifier.java
    InvalidModifier.java
    LeftHandSideModifier.java
    ObjectFieldModifier.java
    StaticFieldModifier.java
    SuperFieldModifier.java
    VariableModifier.java
    package.html
  resources/
    messages.properties
  AbstractTypeChecker.java
  ClassFactory.java
  ClassInfoCompiler.java
  ClassLoaderContainer.java
  ClassPool.java
  DynamicjavaTest.java
  EvaluationVisitor.java
  EvaluationVisitorTest.java
  ForEachNamingTest.java
  ForEachTypingTest.java
  Interpreter.java
  InterpreterException.java
  InterpreterUtilities.java
  Main.java
  NameVisitor.java
  NodeProperties.java
  TreeClassFinder.java
  TreeClassLoader.java
  TreeCompiler.java
  TreeInterpreter.java
  Type.ast
  TypeChecker14.java
  TypeChecker15.java
  TypeCheckerTest.java
  TypeVariable.java
  UninitializedObject.java
  package.html