private void remove(LinkableEvaluation eval) {
    LinkableEvaluation prev = eval.previous;
    LinkableEvaluation next = eval.next;

    if (prev != null) prev.next = next;
    else pendingEvaluationHead = next;

    if (next != null) next.previous = prev;
    else pendingEvaluationTail = prev;
  }
  @Override
  public void onHit(EventID eventID) {
    assert !finished : "getting events even after finish";

    final LocationExpression expression = this.expression;
    if (!lastStep) {
      if (eventID.isEmpty(expression.locationPath.steps[index + 1].axis)) return;
    }

    final Event event = this.event;

    if (positionTracker != null) {
      event.positionTrackerStack.addFirst(positionTracker);
      positionTracker.addEvaluation(event);
    }
    LinkableEvaluation childEval = null;

    Expression predicate = currentStep.predicateSet.getPredicate();
    Object predicateResult = predicate == null ? Boolean.TRUE : event.evaluate(predicate);
    if (predicateResult == Boolean.TRUE) {
      if (lastStep) consume(event);
      else childEval = new LocationEvaluation(expression, index + 1, event, eventID);
    } else if (predicateResult == null) {
      Evaluation predicateEvaluation = event.evaluation;
      if (lastStep) {
        childEval =
            new PredicateEvaluation(
                expression,
                event.order(),
                expression.getResultItem(event),
                event,
                predicate,
                predicateEvaluation);
        if (nodeSetListener != null) nodeSetListener.mayHit();
      } else
        childEval =
            new LocationEvaluation(
                expression, index + 1, event, eventID, predicate, predicateEvaluation);
    }

    if (childEval != null) {
      if (childEval instanceof LocationEvaluation)
        ((LocationEvaluation) childEval).nodeSetListener = nodeSetListener;
      else ((PredicateEvaluation) childEval).nodeSetListener = nodeSetListener;

      childEval.addListener(this);
      if (pendingEvaluationTail != null) {
        pendingEvaluationTail.next = childEval;
        childEval.previous = pendingEvaluationTail;
        pendingEvaluationTail = childEval;
      } else pendingEvaluationHead = pendingEvaluationTail = childEval;
      childEval.start();
    }

    if (positionTracker != null) {
      positionTracker.startEvaluation();
      event.positionTrackerStack.pollFirst();
    }
    if (exactPosition && predicateResult == Boolean.TRUE) {
      manuallyExpired = true;
      expired();
    }
  }