-
Notifications
You must be signed in to change notification settings - Fork 38
Expand file tree
/
Copy pathATN.js
More file actions
155 lines (142 loc) · 5.55 KB
/
ATN.js
File metadata and controls
155 lines (142 loc) · 5.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* Copyright (c) 2012-2022 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
import LL1Analyzer from './LL1Analyzer.js';
import IntervalSet from '../misc/IntervalSet.js';
import Token from '../Token.js';
export default class ATN {
constructor(grammarType , maxTokenType) {
/**
* Used for runtime deserialization of ATNs from strings
* The type of the ATN.
*/
this.grammarType = grammarType;
// The maximum value for any symbol recognized by a transition in the ATN.
this.maxTokenType = maxTokenType;
this.states = [];
/**
* Each subrule/rule is a decision point and we must track them so we
* can go back later and build DFA predictors for them. This includes
* all the rules, subrules, optional blocks, ()+, ()* etc...
*/
this.decisionToState = [];
// Maps from rule index to starting state number.
this.ruleToStartState = [];
// Maps from rule index to stop state number.
this.ruleToStopState = null;
this.modeNameToStartState = {};
/**
* For lexer ATNs, this maps the rule index to the resulting token type.
* For parser ATNs, this maps the rule index to the generated bypass token
* type if the {@link ATNDeserializationOptions//isGenerateRuleBypassTransitions}
* deserialization option was specified; otherwise, this is {@code null}
*/
this.ruleToTokenType = null;
/**
* For lexer ATNs, this is an array of {@link LexerAction} objects which may
* be referenced by action transitions in the ATN
*/
this.lexerActions = null;
this.modeToStartState = [];
}
/**
* Compute the set of valid tokens that can occur starting in state {@code s}.
* If {@code ctx} is null, the set of tokens will not include what can follow
* the rule surrounding {@code s}. In other words, the set will be
* restricted to tokens reachable staying within {@code s}'s rule
*/
nextTokensInContext(s, ctx) {
let anal = new LL1Analyzer(this);
return anal.LOOK(s, null, ctx);
}
/**
* Compute the set of valid tokens that can occur starting in {@code s} and
* staying in same rule. {@link Token//EPSILON} is in set if we reach end of
* rule
*/
nextTokensNoContext(s) {
if (s.nextTokenWithinRule !== null ) {
return s.nextTokenWithinRule;
}
s.nextTokenWithinRule = this.nextTokensInContext(s, null);
s.nextTokenWithinRule.readOnly = true;
return s.nextTokenWithinRule;
}
nextTokens(s, ctx) {
if ( ctx===undefined ) {
return this.nextTokensNoContext(s);
} else {
return this.nextTokensInContext(s, ctx);
}
}
addState(state) {
if ( state !== null ) {
state.atn = this;
state.stateNumber = this.states.length;
}
this.states.push(state);
}
removeState(state) {
this.states[state.stateNumber] = null; // just free mem, don't shift states in list
}
defineDecisionState(s) {
this.decisionToState.push(s);
s.decision = this.decisionToState.length-1;
return s.decision;
}
getDecisionState(decision) {
if (this.decisionToState.length===0) {
return null;
} else {
return this.decisionToState[decision];
}
}
/**
* Computes the set of input symbols which could follow ATN state number
* {@code stateNumber} in the specified full {@code context}. This method
* considers the complete parser context, but does not evaluate semantic
* predicates (i.e. all predicates encountered during the calculation are
* assumed true). If a path in the ATN exists from the starting state to the
* {@link RuleStopState} of the outermost context without matching any
* symbols, {@link Token//EOF} is added to the returned set.
*
* <p>If {@code context} is {@code null}, it is treated as
* {@link ParserRuleContext//EMPTY}.</p>
*
* @param stateNumber the ATN state number
* @param ctx the full parse context
*
* @return {IntervalSet} The set of potentially valid input symbols which could follow the
* specified state in the specified context.
*
* @throws IllegalArgumentException if the ATN does not contain a state with
* number {@code stateNumber}
*/
getExpectedTokens(stateNumber, ctx ) {
if ( stateNumber < 0 || stateNumber >= this.states.length ) {
throw("Invalid state number.");
}
let s = this.states[stateNumber];
let following = this.nextTokens(s);
if (!following.contains(Token.EPSILON)) {
return following;
}
let expected = new IntervalSet();
expected.addSet(following);
expected.removeOne(Token.EPSILON);
while (ctx !== null && ctx.invokingState >= 0 && following.contains(Token.EPSILON)) {
let invokingState = this.states[ctx.invokingState];
let rt = invokingState.transitions[0];
following = this.nextTokens(rt.followState);
expected.addSet(following);
expected.removeOne(Token.EPSILON);
ctx = ctx.parentCtx;
}
if (following.contains(Token.EPSILON)) {
expected.addOne(Token.EOF);
}
return expected;
}
}
ATN.INVALID_ALT_NUMBER = 0;