class InterpretExpression extends BaseExpression {

  private static final long serialVersionUID = -3831400781523526582L;

  private List<IR> instruments;

  private boolean unboxObject;

  private Map<VariableMeta, AviatorJavaType> variables =
      new IdentityHashMap<VariableMeta, AviatorJavaType>();

  private Map<Token<?>, AviatorObject> constantPool = new IdentityHashMap<>();


  public InterpretExpression(final AviatorEvaluatorInstance instance, final List<VariableMeta> vars,
      final Set<Token<?>> constants, final SymbolTable symbolTable, final List<IR> instruments,
      final boolean unboxObject) {
    super(instance, vars, symbolTable);
    this.instruments = instruments;
    this.unboxObject = unboxObject;
    loadVars(vars);
    loadConstants(constants, instruments);
  }

  private void loadVars(final List<VariableMeta> vars) {
    for (VariableMeta v : vars) {
      this.variables.put(v, new AviatorJavaType(v.getName(), this.symbolTable));
    }
  }

  private void loadConstants(final Set<Token<?>> constants, final List<IR> instruments) {
    final Env env = new Env();
    env.setInstance(this.instance);
    InterpretContext ctx = new InterpretContext(this, instruments, env);
    for (Token<?> token : constants) {
      final LoadIR loadConstantIR = new LoadIR(this.sourceFile, token, null, false);
      loadConstantIR.evalWithoutDispatch(ctx);
      this.constantPool.put(token, ctx.pop());
    }
  }

  public AviatorJavaType loadVar(final VariableMeta v) {
    return this.variables.get(v);
  }

  public AviatorObject loadConstant(final Token<?> token) {
    return this.constantPool.get(token);
  }

  public void printInstruments() {
    traceInstruments(Collections.<String, Object>emptyMap(), null, true);
  }

  private void traceInstruments(final Map<String, Object> env, final String name,
      final boolean traceLambda) {
    int pc = 0;
    RuntimeUtils.printlnTrace(env, (name == null ? this.sourceFile : name) + " instruments: ");
    for (IR ir : this.instruments) {
      RuntimeUtils.printlnTrace(env, "    " + (pc++) + " " + ir.toString());
    }
    RuntimeUtils.printlnTrace(env, "    " + pc + " return");

    if (this.lambdaBootstraps != null) {
      final List<LambdaFunctionBootstrap> bootstraps =
          new ArrayList<>(this.lambdaBootstraps.values());
      Collections.sort(bootstraps);
      for (LambdaFunctionBootstrap bootstrap : bootstraps) {
        final Expression exp = bootstrap.getExpression();
        if (exp instanceof InterpretExpression) {
          InterpretExpression iexp = (InterpretExpression) exp;
          iexp.traceInstruments(env, bootstrap.getName(), traceLambda);
        } else {
          RuntimeUtils.printlnTrace(env, bootstrap.getName() + " instruments: " + exp);
        }
      }
    }
  }

  @Override
  public Object executeDirectly(final Map<String, Object> env) {<FILL_FUNCTION_BODY>}


  @SuppressWarnings("unchecked")
  private void readObject(ObjectInputStream input) throws ClassNotFoundException, IOException {
    super.customReadObject(input);
    this.instruments = (List<IR>) input.readObject();
    this.unboxObject = input.readBoolean();
    this.variables = (Map<VariableMeta, AviatorJavaType>) input.readObject();
    this.constantPool = (Map<Token<?>, AviatorObject>) input.readObject();
  }

  private void writeObject(ObjectOutputStream output) throws IOException {
    super.customWriteObject(output);
    output.writeObject(this.instruments);
    output.writeBoolean(this.unboxObject);
    output.writeObject(this.variables);
    output.writeObject(this.constantPool);
  }
}

    final boolean trace = RuntimeUtils.isTracedEval(env);
    if (trace) {
      traceInstruments(env, null, false);
      RuntimeUtils.printlnTrace(env, "Execute instruments: ");
    }

    InterpretContext ctx = new InterpretContext(this, this.instruments, (Env) env);
    ctx.dispatch(false);

    // while ((ir = ctx.getPc()) != null) {
    // if (trace) {
    // RuntimeUtils.printlnTrace(env, " " + ir + " " + ctx.descOperandsStack());
    // }
    // ir.eval(ctx);
    // if (ir instanceof JumpIR) {
    // if (ir != ctx.getPc()) {
    // // jump successfully, we don't move pc to next.
    // continue;
    // }
    // }
    // if (!ctx.next()) {
    // break;
    // }
    // }
    if (trace) {
      RuntimeUtils.printlnTrace(env, "    return    " + ctx.descOperandsStack());
    }


    assert (ctx.getOperands().size() <= 1);
    AviatorObject result = ctx.peek();
    if (result == null) {
      return null;
    }

    if (this.unboxObject) {
      return result.getValue(env);
    } else {
      return result.deref(env);
    }
  
<methods>public void <init>(com.googlecode.aviator.AviatorEvaluatorInstance, List<com.googlecode.aviator.parser.VariableMeta>, com.googlecode.aviator.lexer.SymbolTable) ,public java.lang.String addSymbol(java.lang.String) ,public void customReadObject(java.io.ObjectInputStream) throws java.lang.ClassNotFoundException, java.io.IOException,public void customWriteObject(java.io.ObjectOutputStream) throws java.io.IOException,public java.lang.Object execute(Map<java.lang.String,java.lang.Object>) ,public java.lang.Object execute() ,public abstract java.lang.Object executeDirectly(Map<java.lang.String,java.lang.Object>) ,public com.googlecode.aviator.utils.Env getCompileEnv() ,public java.lang.String getExpression() ,public Map<java.lang.String,com.googlecode.aviator.parser.VariableMeta> getFullNameMetas() ,public Map<java.lang.String,com.googlecode.aviator.runtime.LambdaFunctionBootstrap> getLambdaBootstraps() ,public java.lang.String getSourceFile() ,public com.googlecode.aviator.AviatorEvaluatorInstance.StringSegments getStringSegements(java.lang.String, int) ,public List<java.lang.String> getVariableFullNames() ,public List<java.lang.String> getVariableNames() ,public List<com.googlecode.aviator.parser.VariableMeta> getVars() ,public transient Map<java.lang.String,java.lang.Object> newEnv(java.lang.Object[]) ,public com.googlecode.aviator.runtime.function.LambdaFunction newLambda(com.googlecode.aviator.utils.Env, java.lang.String) ,public void setCompileEnv(com.googlecode.aviator.utils.Env) ,public void setExpression(java.lang.String) ,public void setFuncsArgs(Map<java.lang.Integer,List<com.googlecode.aviator.runtime.FunctionArgument>>) ,public void setInstance(com.googlecode.aviator.AviatorEvaluatorInstance) ,public void setLambdaBootstraps(Map<java.lang.String,com.googlecode.aviator.runtime.LambdaFunctionBootstrap>) ,public void setSourceFile(java.lang.String) <variables>public static final java.lang.String FUNC_PARAMS_VAR,private com.googlecode.aviator.utils.Env compileEnv,private java.lang.String expression,private Map<java.lang.Integer,List<com.googlecode.aviator.runtime.FunctionArgument>> funcsArgs,protected transient com.googlecode.aviator.AviatorEvaluatorInstance instance,protected Map<java.lang.String,com.googlecode.aviator.runtime.LambdaFunctionBootstrap> lambdaBootstraps,private static final long serialVersionUID,protected java.lang.String sourceFile,private transient ConcurrentHashMap<java.lang.String,FutureTask<com.googlecode.aviator.AviatorEvaluatorInstance.StringSegments>> stringSegs,protected com.googlecode.aviator.lexer.SymbolTable symbolTable,protected List<java.lang.String> varFullNames,protected List<java.lang.String> varNames,private List<com.googlecode.aviator.parser.VariableMeta> vars