@Override
 public void compileIf(Label onElse, IEnvironmentMethod environment) {
   a.compile(true, environment);
   environment.getOutput().ifEQ(onElse);
   b.compile(true, environment);
   environment.getOutput().ifEQ(onElse);
 }
  @Override
  public void compile(boolean result, IEnvironmentMethod environment) {
    if (!result) return;

    Method method = interfaceClass.getMethods()[0];

    // generate class
    String clsName = environment.makeClassName();

    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
    cw.visit(
        Opcodes.V1_6,
        Opcodes.ACC_PUBLIC,
        clsName,
        null,
        "java/lang/Object",
        new String[] {internal(interfaceClass)});

    MethodOutput constructor =
        new MethodOutput(cw, Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
    constructor.start();
    constructor.loadObject(0);
    constructor.invokeSpecial("java/lang/Object", "<init>", "()V");
    constructor.ret();
    constructor.end();

    MethodOutput output =
        new MethodOutput(cw, Opcodes.ACC_PUBLIC, method.getName(), descriptor(method), null, null);

    IEnvironmentClass environmentClass = new EnvironmentClass(cw, environment);
    IEnvironmentMethod environmentMethod = new EnvironmentMethod(output, environmentClass);

    for (int i = 0; i < arguments.size(); i++) {
      environmentMethod.putValue(
          arguments.get(i).getName(),
          new SymbolArgument(i + 1, environment.getType(method.getGenericParameterTypes()[i])),
          getPosition());
    }

    output.start();
    for (Statement statement : statements) {
      statement.compile(environmentMethod);
    }
    output.ret();
    output.end();

    environment.putClass(clsName, cw.toByteArray());

    // make class instance
    environment.getOutput().newObject(clsName);
    environment.getOutput().dup();
    environment.getOutput().construct(clsName);
  }
  @Override
  public void compile(boolean result, IEnvironmentMethod environment) {
    // if not a: return false
    // if not b: return false
    // return true

    MethodOutput output = environment.getOutput();

    Label skip = new Label();
    a.compile(true, environment);
    output.ifEQ(skip);
    b.compile(true, environment);
    output.ifEQ(skip);
    output.iConst1();
    output.label(skip);

    if (!result) {
      output.pop();
    }
  }
 @Override
 public Expression call(
     ZenPosition position, IEnvironmentMethod environment, Expression... values) {
   environment.error(position, "value cannot be called");
   return new ExpressionInvalid(position);
 }