add method

bool add(
  1. ATNConfig config, [
  2. Map<Pair<PredictionContext, PredictionContext>, PredictionContext>? mergeCache
])

Adding a new config means merging contexts with existing configs for {@code (s, i, pi, _)}, where s is the {@link ATNConfig#state}, i is the {@link ATNConfig#alt}, and pi is the {@link ATNConfig#semanticContext}. We use {@code (s,i,pi)} as key.

This method updates {@link #dipsIntoOuterContext} and {@link #hasSemanticContext} when necessary.

Implementation

bool add(
  ATNConfig config, [
  Map<Pair<PredictionContext, PredictionContext>, PredictionContext>?
      mergeCache,
]) {
  if (readOnly) throw StateError('This set is readonly');
  if (config.semanticContext != EmptySemanticContext.Instance) {
    hasSemanticContext = true;
  }
  if (config.outerContextDepth > 0) {
    dipsIntoOuterContext = true;
  }
  final existing = configLookup!.lookup(config) ?? config;
  if (identical(existing, config)) {
    // we added this new one
    cachedHashCode = -1;
    configLookup!.add(config);
    configs.add(config); // track order here
    return true;
  }
  // a previous (s,i,pi,_), merge with it and save result
  final rootIsWildcard = !fullCtx;
  final merged = PredictionContext.merge(
    existing.context!,
    config.context!,
    rootIsWildcard,
    mergeCache,
  );
  // no need to check for existing.context, config.context in cache
  // since only way to create new graphs is "call rule" and here. We
  // cache at both places.
  existing.reachesIntoOuterContext =
      max(existing.reachesIntoOuterContext, config.reachesIntoOuterContext);

  // make sure to preserve the precedence filter suppression during the merge
  if (config.isPrecedenceFilterSuppressed()) {
    existing.setPrecedenceFilterSuppressed(true);
  }

  existing.context = merged; // replace context; no need to alt mapping
  return true;
}