1 /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 * Use of this file is governed by the BSD 3-clause license that
3 * can be found in the LICENSE.txt file in the project root.
6 #include "atn/PredictionContext.h"
7 #include "atn/ATNConfig.h"
8 #include "atn/ATNSimulator.h"
9 #include "Exceptions.h"
10 #include "atn/SemanticContext.h"
11 #include "support/Arrays.h"
13 #include "atn/ATNConfigSet.h"
15 using namespace antlr4::atn;
16 using namespace antlrcpp;
18 ATNConfigSet::ATNConfigSet(bool fullCtx) : fullCtx(fullCtx) {
19 InitializeInstanceFields();
22 ATNConfigSet::ATNConfigSet(const Ref<ATNConfigSet> &old) : ATNConfigSet(old->fullCtx) {
24 uniqueAlt = old->uniqueAlt;
25 conflictingAlts = old->conflictingAlts;
26 hasSemanticContext = old->hasSemanticContext;
27 dipsIntoOuterContext = old->dipsIntoOuterContext;
30 ATNConfigSet::~ATNConfigSet() {
33 bool ATNConfigSet::add(const Ref<ATNConfig> &config) {
34 return add(config, nullptr);
37 bool ATNConfigSet::add(const Ref<ATNConfig> &config, PredictionContextMergeCache *mergeCache) {
39 throw IllegalStateException("This set is readonly");
41 if (config->semanticContext != SemanticContext::NONE) {
42 hasSemanticContext = true;
44 if (config->getOuterContextDepth() > 0) {
45 dipsIntoOuterContext = true;
48 size_t hash = getHash(config.get());
49 ATNConfig *existing = _configLookup[hash];
50 if (existing == nullptr) {
51 _configLookup[hash] = config.get();
53 configs.push_back(config); // track order here
58 // a previous (s,i,pi,_), merge with it and save result
59 bool rootIsWildcard = !fullCtx;
60 Ref<PredictionContext> merged = PredictionContext::merge(existing->context, config->context, rootIsWildcard, mergeCache);
61 // no need to check for existing.context, config.context in cache
62 // since only way to create new graphs is "call rule" and here. We
63 // cache at both places.
64 existing->reachesIntoOuterContext = std::max(existing->reachesIntoOuterContext, config->reachesIntoOuterContext);
66 // make sure to preserve the precedence filter suppression during the merge
67 if (config->isPrecedenceFilterSuppressed()) {
68 existing->setPrecedenceFilterSuppressed(true);
71 existing->context = merged; // replace context; no need to alt mapping
76 bool ATNConfigSet::addAll(const Ref<ATNConfigSet> &other) {
77 for (auto &c : other->configs) {
83 std::vector<ATNState*> ATNConfigSet::getStates() {
84 std::vector<ATNState*> states;
85 for (auto c : configs) {
86 states.push_back(c->state);
92 * Gets the complete set of represented alternatives for the configuration
95 * @return the set of represented alternatives in this configuration set
100 BitSet ATNConfigSet::getAlts() {
102 for (ATNConfig config : configs) {
103 alts.set(config.alt);
108 std::vector<Ref<SemanticContext>> ATNConfigSet::getPredicates() {
109 std::vector<Ref<SemanticContext>> preds;
110 for (auto c : configs) {
111 if (c->semanticContext != SemanticContext::NONE) {
112 preds.push_back(c->semanticContext);
118 Ref<ATNConfig> ATNConfigSet::get(size_t i) const {
122 void ATNConfigSet::optimizeConfigs(ATNSimulator *interpreter) {
124 throw IllegalStateException("This set is readonly");
126 if (_configLookup.empty())
129 for (auto &config : configs) {
130 config->context = interpreter->getCachedContext(config->context);
134 bool ATNConfigSet::operator == (const ATNConfigSet &other) {
135 if (&other == this) {
139 if (configs.size() != other.configs.size())
142 if (fullCtx != other.fullCtx || uniqueAlt != other.uniqueAlt ||
143 conflictingAlts != other.conflictingAlts || hasSemanticContext != other.hasSemanticContext ||
144 dipsIntoOuterContext != other.dipsIntoOuterContext) // includes stack context
147 return Arrays::equals(configs, other.configs);
150 size_t ATNConfigSet::hashCode() {
151 if (!isReadonly() || _cachedHashCode == 0) {
153 for (auto &i : configs) {
154 _cachedHashCode = 31 * _cachedHashCode + i->hashCode(); // Same as Java's list hashCode impl.
158 return _cachedHashCode;
161 size_t ATNConfigSet::size() {
162 return configs.size();
165 bool ATNConfigSet::isEmpty() {
166 return configs.empty();
169 void ATNConfigSet::clear() {
171 throw IllegalStateException("This set is readonly");
175 _configLookup.clear();
178 bool ATNConfigSet::isReadonly() {
182 void ATNConfigSet::setReadonly(bool readonly) {
183 _readonly = readonly;
184 _configLookup.clear();
187 std::string ATNConfigSet::toString() {
188 std::stringstream ss;
190 for (size_t i = 0; i < configs.size(); i++) {
191 ss << configs[i]->toString();
195 if (hasSemanticContext) {
196 ss << ",hasSemanticContext = " << hasSemanticContext;
198 if (uniqueAlt != ATN::INVALID_ALT_NUMBER) {
199 ss << ",uniqueAlt = " << uniqueAlt;
202 if (conflictingAlts.size() > 0) {
203 ss << ",conflictingAlts = ";
204 ss << conflictingAlts.toString();
207 if (dipsIntoOuterContext) {
208 ss << ", dipsIntoOuterContext";
213 size_t ATNConfigSet::getHash(ATNConfig *c) {
215 hashCode = 31 * hashCode + c->state->stateNumber;
216 hashCode = 31 * hashCode + c->alt;
217 hashCode = 31 * hashCode + c->semanticContext->hashCode();
221 void ATNConfigSet::InitializeInstanceFields() {
223 hasSemanticContext = false;
224 dipsIntoOuterContext = false;