@SuppressWarnings({"unchecked", "rawtypes"})
  public List<TokenPatternMatchFeature<?>> parseDescriptor(FunctionDescriptor descriptor) {
    MONITOR.startTask("parseDescriptor");
    try {
      List<TokenPatternMatchFeature<?>> wrappedFeatures =
          new ArrayList<TokenPatternMatchFeature<?>>();

      List<Feature<TokenPatternMatch, ?>> tokenPatternMatchFeatures = this.parse(descriptor);

      for (Feature<TokenPatternMatch, ?> tokenPatternMatchFeature : tokenPatternMatchFeatures) {
        TokenPatternMatchFeature<?> wrappedFeature = null;
        if (tokenPatternMatchFeature instanceof TokenPatternMatchFeature) {
          wrappedFeature = (TokenPatternMatchFeature<?>) tokenPatternMatchFeature;
        } else {
          wrappedFeature = new TokenPatternMatchFeatureWrapper(tokenPatternMatchFeature);
        }
        wrappedFeatures.add(wrappedFeature);
      }

      return wrappedFeatures;
    } finally {
      MONITOR.endTask();
    }
  }
class TokenPatternMatchFeatureParser extends AbstractFeatureParser<TokenPatternMatch> {
  private static final PerformanceMonitor MONITOR =
      PerformanceMonitor.getMonitor(TokenPatternMatchFeatureParser.class);

  TokenFeatureParser tokenFeatureParser;

  public TokenPatternMatchFeatureParser(FeatureService featureService) {
    super(featureService);
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  public List<TokenPatternMatchFeature<?>> parseDescriptor(FunctionDescriptor descriptor) {
    MONITOR.startTask("parseDescriptor");
    try {
      List<TokenPatternMatchFeature<?>> wrappedFeatures =
          new ArrayList<TokenPatternMatchFeature<?>>();

      List<Feature<TokenPatternMatch, ?>> tokenPatternMatchFeatures = this.parse(descriptor);

      for (Feature<TokenPatternMatch, ?> tokenPatternMatchFeature : tokenPatternMatchFeatures) {
        TokenPatternMatchFeature<?> wrappedFeature = null;
        if (tokenPatternMatchFeature instanceof TokenPatternMatchFeature) {
          wrappedFeature = (TokenPatternMatchFeature<?>) tokenPatternMatchFeature;
        } else {
          wrappedFeature = new TokenPatternMatchFeatureWrapper(tokenPatternMatchFeature);
        }
        wrappedFeatures.add(wrappedFeature);
      }

      return wrappedFeatures;
    } finally {
      MONITOR.endTask();
    }
  }

  @Override
  public void addFeatureClasses(FeatureClassContainer container) {
    container.addFeatureClass("CurrentPattern", PatternNameFeature.class);
    container.addFeatureClass("CurrentGroup", PatternGroupNameFeature.class);
    container.addFeatureClass("PatternOffset", PatternMatchOffsetAddressFunction.class);
    container.addFeatureClass("PatternWordForm", PatternMatchWordFormFeature.class);
    container.addFeatureClass("PatternIndexInSentence", PatternMatchIndexInSentenceFeature.class);
    this.tokenFeatureParser.addFeatureClasses(container);
  }

  @Override
  public List<FunctionDescriptor> getModifiedDescriptors(FunctionDescriptor functionDescriptor) {
    return tokenFeatureParser.getModifiedDescriptors(functionDescriptor);
  }

  @SuppressWarnings({"rawtypes"})
  @Override
  public void injectDependencies(Feature feature) {
    this.tokenFeatureParser.injectDependencies(feature);
  }

  public TokenFeatureParser getTokenFeatureParser() {
    return tokenFeatureParser;
  }

  public void setTokenFeatureParser(TokenFeatureParser tokenFeatureParser) {
    this.tokenFeatureParser = tokenFeatureParser;
  }

  private static class TokenPatternMatchFeatureWrapper<T>
      extends AbstractFeature<TokenPatternMatch, T>
      implements TokenPatternMatchFeature<T>, FeatureWrapper<TokenPatternMatch, T> {
    private Feature<TokenPatternMatch, T> wrappedFeature = null;

    public TokenPatternMatchFeatureWrapper(Feature<TokenPatternMatch, T> wrappedFeature) {
      super();
      this.wrappedFeature = wrappedFeature;
      this.setName(wrappedFeature.getName());
      this.setCollectionName(wrappedFeature.getCollectionName());
    }

    @Override
    public FeatureResult<T> check(TokenPatternMatch context, RuntimeEnvironment env) {
      return wrappedFeature.check(context, env);
    }

    @Override
    public Feature<TokenPatternMatch, T> getWrappedFeature() {
      return wrappedFeature;
    }

    @SuppressWarnings("rawtypes")
    @Override
    public Class<? extends Feature> getFeatureType() {
      return wrappedFeature.getFeatureType();
    }
  }

  @Override
  protected boolean canConvert(Class<?> parameterType, Class<?> originalArgumentType) {
    return false;
  }

  @Override
  protected Feature<TokenPatternMatch, ?> convertArgument(
      Class<?> parameterType, Feature<TokenPatternMatch, ?> originalArgument) {
    return null;
  }

  @Override
  public Feature<TokenPatternMatch, ?> convertFeatureCustomType(
      Feature<TokenPatternMatch, ?> feature) {
    return null;
  }
}