/**
   * Auxiliary method that translates into Kitten bytecode all class members that are referenced
   * from the given block and the blocks reachable from it.
   *
   * @param block the block
   * @param done the class member signatures already translated
   * @param blocksDone the blocks that have been already processed
   */
  protected void translateReferenced(
      Block block, Set<ClassMemberSignature> done, Set<Block> blocksDone) {
    // if we already processed the block, we return immediately
    if (!blocksDone.add(block)) return;

    for (BytecodeList cursor = block.getBytecode(); cursor != null; cursor = cursor.getTail()) {
      Bytecode h = cursor.getHead();

      if (h instanceof GETFIELD) {
        FieldSignature field = ((GETFIELD) h).getField();
        this.process(field.getDefiningClass(), done);
        done.add(field);
      } else if (h instanceof PUTFIELD) {
        FieldSignature field = ((PUTFIELD) h).getField();
        this.process(field.getDefiningClass(), done);
        done.add(field);
      } else if (h instanceof CALL)
        for (CodeSignature callee : ((CALL) h).getDynamicTargets()) {
          this.process(callee.getDefiningClass(), done);
          callee.getAbstractSyntax().translate(done);
        }
    }

    // we continue with the following blocks
    for (Block follow : block.getFollows()) translateReferenced(follow, done, blocksDone);
  }
 protected void process(ClassType clazz, Set<ClassMemberSignature> done) {
   for (CodeSignature cs : clazz.fixturesLookup()) {
     cs.getAbstractSyntax().translate(done);
   }
   for (CodeSignature cs : clazz.getTests()) {
     cs.getAbstractSyntax().translate(done);
   }
 }
  /**
   * Translates this constructor or method into intermediate Kitten code. This amounts to
   * translating its body with a continuation containing a {@code return} bytecode. This way, if a
   * method does not have an explicit {@code return} statement, it is automatically put at its end.
   *
   * @param done the set of code signatures that have been already translated
   */
  public void translate(Set<ClassMemberSignature> done) {
    if (done.add(sig)) {
      this.process(sig.getDefiningClass(), done);
      // we translate the body of the constructor or
      // method with a block containing RETURN as continuation. This way,
      // all methods returning void and
      // with some missing return command are correctly
      // terminated anyway. If the method is not void, this
      // precaution is useless since we know that every execution path
      // ends with a return command, as guaranteed by
      // checkForDeadCode() (see typeCheck() in MethodDeclaration.java)
      sig.setCode(getBody().translate(sig, new Block(new RETURN(VoidType.INSTANCE))));

      // we translate all methods and constructors that are referenced
      // from the code we have generated
      translateReferenced(sig.getCode(), done, new HashSet<Block>());
    }
  }