@Override
  public void exitCertainDate(CertainDateContext ctx) {
    if (ctx.exception != null) return;

    Date latestDate = (Date) stack.pop();
    Date earliestDate = (Date) stack.pop();

    // Set null eras to the default.

    if (earliestDate.getEra() == null) {
      earliestDate.setEra(Date.DEFAULT_ERA);
    }

    if (latestDate.getEra() == null) {
      latestDate.setEra(Date.DEFAULT_ERA);
    }

    // Finalize any deferred calculations.

    if (latestDate instanceof DeferredDate) {
      ((DeferredDate) latestDate).resolveDate();
    }

    if (earliestDate instanceof DeferredDate) {
      ((DeferredDate) earliestDate).resolveDate();
    }

    stack.push(earliestDate);
    stack.push(latestDate);
  }
  @Override
  public void exitHyphenatedRange(HyphenatedRangeContext ctx) {
    if (ctx.exception != null) return;

    Date latestEndDate = (Date) stack.pop();
    stack.pop(); // latestStartDate
    stack.pop(); // earliestEndDate
    Date earliestStartDate = (Date) stack.pop();

    // If no era was explicitly specified for the first date,
    // make it inherit the era of the second date.

    if (earliestStartDate.getEra() == null && latestEndDate.getEra() != null) {
      earliestStartDate.setEra(latestEndDate.getEra());
    }

    // Finalize any deferred calculations.

    if (earliestStartDate instanceof DeferredDate) {
      ((DeferredDate) earliestStartDate).resolveDate();
    }

    if (latestEndDate instanceof DeferredDate) {
      ((DeferredDate) latestEndDate).resolveDate();
    }

    stack.push(earliestStartDate);
    stack.push(latestEndDate);
  }
  @Override
  public void exitBeforeOrAfterDate(BeforeOrAfterDateContext ctx) {
    if (ctx.exception != null) return;

    Date latestDate = (Date) stack.pop();
    Date earliestDate = (Date) stack.pop();

    // Set null eras to the default.

    if (earliestDate.getEra() == null) {
      earliestDate.setEra(Date.DEFAULT_ERA);
    }

    if (latestDate.getEra() == null) {
      latestDate.setEra(Date.DEFAULT_ERA);
    }

    // Finalize any deferred calculations.

    if (latestDate instanceof DeferredDate) {
      ((DeferredDate) latestDate).resolveDate();
    }

    if (earliestDate instanceof DeferredDate) {
      ((DeferredDate) earliestDate).resolveDate();
    }

    // Calculate the earliest date or end date.

    if (ctx.BEFORE() != null) {
      latestDate = earliestDate;
      earliestDate = DateUtils.getEarliestBeforeDate(earliestDate, latestDate);
    } else if (ctx.AFTER() != null) {
      earliestDate = latestDate;
      latestDate = DateUtils.getLatestAfterDate(earliestDate, latestDate);
    }

    stack.push(earliestDate);
    stack.push(latestDate);
  }