docs: private List<MtasCRMParserFunctionOutput> processWordAnnotation(
        MtasTokenIdFactory mtasTokenIdFactory, String name, String text,
        Integer previousOffset, Integer currentOffset,
        MtasCRMAncestors unknownAncestors,
        Map<String, List<MtasParserObject>> currentList,
        Map<String, Map<Integer, Set<String>>> updateList,
        Map<String, Set<Integer>> idPositions, Map<String, Integer[]> idOffsets)
        throws MtasParserException, MtasConfigException {
      MtasParserType tmpCurrentType;
      MtasParserObject currentObject;
      List<MtasCRMParserFunctionOutput> functionOutputList = new ArrayList<>();
      if ((tmpCurrentType = wordAnnotationTypes.get(name)) != null) {
        // start word annotation
        currentObject = new MtasParserObject(tmpCurrentType);
        currentObject.setRealOffsetStart(previousOffset);
        currentObject.addPositions(currentList.get(MAPPING_TYPE_WORD)
            .get((currentList.get(MAPPING_TYPE_WORD).size() - 1)).getPositions());
        currentObject.setUnknownAncestorNumber(unknownAncestors.unknown);
        if (!prevalidateObject(currentObject, currentList)) {
          unknownAncestors.unknown++;
        } else {
          currentList.get(MAPPING_TYPE_WORD_ANNOTATION).add(currentObject);
          unknownAncestors.unknown = 0;
        }
        // finish word annotation
        if (unknownAncestors.unknown > 0) {
          unknownAncestors.unknown--;
        } else {
          currentObject = currentList.get(MAPPING_TYPE_WORD_ANNOTATION)
              .remove(currentList.get(MAPPING_TYPE_WORD_ANNOTATION).size() - 1);
          assert unknownAncestors.unknown == 0 : "error in administration "
              + currentObject.getType().getName();
          if (functions.containsKey(MAPPING_TYPE_WORD_ANNOTATION)
              && functions.get(MAPPING_TYPE_WORD_ANNOTATION).containsKey(name)
              && text != null) {
            MtasCRMParserFunction function = functions
                .get(MAPPING_TYPE_WORD_ANNOTATION).get(name);
            String[] value;
            if (function.split != null) {
              value = text.split(Pattern.quote(function.split));
            } else {
              value = new String[] { text };
            }
            for (int c = 0; c < value.length; c++) {
              if (function.output.containsKey(value[c])) {
                functionOutputList.addAll(function.output.get(value[c]));
              }
            }
          }
          currentObject.setText(text);
          currentObject.setRealOffsetEnd(currentOffset - 1);
          idPositions.put(currentObject.getId(), currentObject.getPositions());
          idOffsets.put(currentObject.getId(), currentObject.getOffset());
          // offset always null, so update later with word (should be possible)
          if ((currentObject.getId() != null)
              && (!currentList.get(MAPPING_TYPE_WORD).isEmpty())) {
            currentList.get(MAPPING_TYPE_WORD)
                .get((currentList.get(MAPPING_TYPE_WORD).size() - 1))
                .addUpdateableIdWithOffset(currentObject.getId());
          }
          currentObject.updateMappings(idPositions, idOffsets);
          unknownAncestors.unknown = currentObject.getUnknownAncestorNumber();
          computeMappingsFromObject(mtasTokenIdFactory, currentObject,
              currentList, updateList);
        }
      }
      return functionOutputList;
    }