/** Extracts reference metrics from a single instruction. */
  public void extract(Instruction inst) {
    String name = null;
    if (inst == null) {
      return;
    }
    if (!(inst instanceof RootInst)) {
      refs.increment(inst);
    }
    switch (inst.getType()) {
      case TEXT:
        refs.textBytes += ((TextInst) inst).getView().length();
        break;

      case ALTERNATES_WITH:
        AlternatesWithInst alternatesWith = (AlternatesWithInst) inst;
        extractBlock(alternatesWith.getConsequent());
        extract(alternatesWith.getAlternative());
        break;

      case IF:
        {
          BlockInstruction blockInst = (BlockInstruction) inst;
          refs.addIfInstruction(blockInst);
          if (inst instanceof IfInst) {
            IfInst ifInst = (IfInst) inst;
            for (Object[] var : ifInst.getVariables()) {
              name = ReprEmitter.get(var);
              refs.addVariable(name);
            }
          } else {
            IfPredicateInst ifInst = (IfPredicateInst) inst;
            refs.increment(ifInst.getPredicate());
          }
          extractBlock(blockInst.getConsequent());
          extract(blockInst.getAlternative());
          break;
        }

      case OR_PREDICATE:
      case PREDICATE:
        PredicateInst predicateInst = (PredicateInst) inst;
        Predicate predicate = predicateInst.getPredicate();
        if (predicate != null) {
          refs.increment(predicate);

          List<String> varRefs = predicate.getVariableNames(predicateInst.getArguments());
          for (String varRef : varRefs) {
            refs.addVariable(varRef);
          }
        }

        extractBlock(predicateInst.getConsequent());
        extract(predicateInst.getAlternative());
        break;

      case REPEATED:
        RepeatedInst repeated = (RepeatedInst) inst;
        name = ReprEmitter.get(repeated.getVariable());
        refs.pushSection(name);
        extractBlock(repeated.getConsequent());
        extract(repeated.getAlternative());
        extract(repeated.getAlternatesWith());
        refs.popSection();
        break;

      case ROOT:
        extractBlock(((RootInst) inst).getConsequent());
        break;

      case SECTION:
        SectionInst section = (SectionInst) inst;
        name = ReprEmitter.get(section.getVariable());
        refs.pushSection(name);
        extractBlock(section.getConsequent());
        extract(section.getAlternative());
        refs.popSection();
        break;

      case VARIABLE:
        VariableInst variable = (VariableInst) inst;
        name = ReprEmitter.get(variable.getVariable());
        refs.addVariable(name);

        for (FormatterCall call : variable.getFormatters()) {
          refs.increment(call.getFormatter());
        }
        break;

      default:
        break;
    }
  }