/** * Adding a new config means merging contexts with existing configs for * {@code (s, i, pi, _)}, where {@code s} is the * {@link ATNConfig#state}, {@code i} is the {@link ATNConfig#alt}, and * {@code pi} is the {@link ATNConfig#semanticContext}. We use * {@code (s,i,pi)} as key. * * <p>This method updates {@link #dipsIntoOuterContext} and * {@link #hasSemanticContext} when necessary.</p> */ public bool Add(ATNConfig config, MergeCache mergeCache) { if (readOnly) { throw new Exception("This set is readonly"); } if (config.semanticContext != SemanticContext.NONE) { hasSemanticContext = true; } if (config.OuterContextDepth > 0) { dipsIntoOuterContext = true; } ATNConfig existing = configLookup.GetOrAdd(config); if (existing == config) { // we added this new one cachedHashCode = -1; configs.Add(config); // track order here return(true); } // a previous (s,i,pi,_), merge with it and save result bool rootIsWildcard = !fullCtx; PredictionContext 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 = Math.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); }