/**
   * 13.12.9 Runtime Semantics: CaseBlockEvaluation
   *
   * @param node the switch statement
   * @param type the switch statement type
   * @param lblExit the exit label
   * @param switchValue the variable which holds the switch value
   * @param mv the statement visitor
   * @return the completion value
   */
  private Completion CaseBlockEvaluation(
      SwitchStatement node,
      SwitchType type,
      Jump lblExit,
      Variable<?> switchValue,
      StatementVisitor mv) {
    List<SwitchClause> clauses = node.getClauses();
    Jump lblDefault = null;
    Jump[] labels = new Jump[clauses.size()];
    for (int i = 0, size = clauses.size(); i < size; ++i) {
      labels[i] = new Jump();
      if (clauses.get(i).isDefaultClause()) {
        assert lblDefault == null;
        lblDefault = labels[i];
      }
    }

    if (type == SwitchType.Int) {
      emitIntSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv);
    } else if (type == SwitchType.Char) {
      emitCharSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv);
    } else if (type == SwitchType.String) {
      emitStringSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv);
    } else if (type == SwitchType.Generic) {
      emitGenericSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv);
    } else {
      assert type == SwitchType.Default;
      assert switchValue == null;
      // Directly jump to default clause; since switch clauses before default clause are not
      // emitted, jump instruction can be elided as well, so we directly fall into the default
      // clause.
    }

    Completion result = Completion.Normal, lastResult = Completion.Normal;
    if (type == SwitchType.Default) {
      Iterator<SwitchClause> iter = clauses.iterator();
      // skip leading clauses until default clause found
      while (iter.hasNext()) {
        SwitchClause switchClause = iter.next();
        if (switchClause.isDefaultClause()) {
          lastResult = switchClause.accept(this, mv);
          break;
        }
      }
      // handle clauses following default clause until abrupt completion
      while (iter.hasNext() && !lastResult.isAbrupt()) {
        lastResult = iter.next().accept(this, mv);
      }
      result = lastResult;
    } else {
      int index = 0;
      for (SwitchClause switchClause : clauses) {
        Jump caseLabel = labels[index++];
        if (caseLabel != null) {
          mv.mark(caseLabel);
        } else if (lastResult.isAbrupt()) {
          // Ignore unreachable targets
          continue;
        }
        Completion innerResult = switchClause.accept(this, mv);
        if (innerResult.isAbrupt()) {
          // not fall-thru
          result = result.isAbrupt() ? result.select(innerResult) : innerResult;
        }
        lastResult = innerResult;
      }
    }
    return result.normal(lblDefault == null || !lastResult.isAbrupt());
  }