protected boolean testAllReadings()

in languagetool-core/src/main/java/org/languagetool/rules/patterns/AbstractPatternRulePerformer.java [169:268]


  protected boolean testAllReadings(AnalyzedTokenReadings[] tokens,
                                    PatternTokenMatcher matcher, PatternTokenMatcher prevElement,
                                    int tokenNo, int firstMatchToken, int prevSkipNext)
          throws IOException {
    boolean anyMatched = false;
    int numberOfReadings = tokens[tokenNo].getReadingsLength();
    matcher.prepareAndGroup(firstMatchToken, tokens, rule.getLanguage());

    List<AnalyzedToken> readingsToUnify = toUnify == null ? null : new ArrayList<>();

    for (int i = 0; i < numberOfReadings; i++) {
      AnalyzedToken matchToken = tokens[tokenNo].getAnalyzedToken(i);
      prevMatched = prevMatched || prevSkipNext > 0
          && prevElement != null
          && prevElement.isMatchedByScopeNextException(matchToken);

      // a workaround to allow exception with scope="next" without "skip" in previous token
      // this allows to check for exception in the next token even if the current one is the last one in the sentence
      prevMatched = prevMatched || prevSkipNext == 0
          && tokenNo <= tokens.length-2
          && matcher.isMatchedByScopeNextException(tokens[tokenNo+1].getAnalyzedToken(0));

      if (prevMatched) {
        return false;
      }

      boolean readingTested = false;
      boolean readingMatches = false;

      if (!anyMatched) {
        anyMatched = readingMatches = matcher.isMatched(matchToken);
        readingTested = true;
      }

      //short-circuit when the search cannot possibly match
      if (!anyMatched && (prevElement == null || !prevElement.getPatternToken().hasCurrentOrNextExceptions())) {
        if (matcher.getPatternToken().getPOStag() == null) {
          if (matcher.getPatternToken().isInflected()) {
            if (tokens[tokenNo].hasSameLemmas()) {
              return false; // same lemmas everywhere
            }
          } else {
            return false; // the token is the same, we will not get a match
          }
        } else if (!matcher.getPatternToken().getPOSNegation() // postag =! null
            && !tokens[tokenNo].isTagged()) {
          return false; // we won't find any postag here anyway
        }
      }
      if (rule.isGroupsOrUnification()) {
        if (!readingTested) {
          readingMatches = matcher.isMatched(matchToken);
        }

        boolean isLastReading = i + 1 == numberOfReadings;
        PatternToken elem = matcher.getPatternToken();
        if (readingMatches && readingsToUnify != null && elem.isUnified() && !elem.isUnificationNeutral()) {
          readingsToUnify.add(matchToken);
        }
        anyMatched &= testAndGroup(isLastReading, matchToken, matcher);
      }
    }
    if (anyMatched) {
      for (int i = 0; i < numberOfReadings; i++) {
        if (matcher.isExceptionMatchedCompletely(tokens[tokenNo].getAnalyzedToken(i))) {
          return false;
        }
      }
      if (tokenNo > 0 && matcher.hasPreviousException()) {
        if (matcher.isMatchedByPreviousException(tokens[tokenNo - 1])) {
          return false;
        }
      }
      if (matcher.getPatternToken().isUnificationNeutral() && neutralReadings != null) {
        neutralReadings.computeIfAbsent(matcher.getPatternToken(), __ -> new ArrayList<>()).add(tokens[tokenNo]);
      }
    }
    ChunkTag chunkTag = matcher.getPatternToken().getChunkTag();
    if (chunkTag != null) {
      if (chunkTag.isRegexp()) {
        anyMatched &= tokens[tokenNo].getChunkTags().stream().anyMatch(k -> k.getChunkTag().matches(chunkTag.getChunkTag()))
                        ^ matcher.getPatternToken().getNegation();
      } else {
        anyMatched &= tokens[tokenNo].getChunkTags().contains(chunkTag)
                        ^ matcher.getPatternToken().getNegation();
      }
    }
    if (matcher.getPatternToken().hasAndGroup()) {
      for (PatternToken e : matcher.getPatternToken().getAndGroup()) {
        if (e.getChunkTag() != null) {
          anyMatched &= tokens[tokenNo].getChunkTags().contains(e.getChunkTag())
              ^ e.getNegation();
        }
      }
    }
    if (anyMatched && readingsToUnify != null && !readingsToUnify.isEmpty()) {
      toUnify.computeIfAbsent(matcher.getPatternToken(), __ -> new ArrayList<>()).add(readingsToUnify);
    }
    return anyMatched;
  }