antlr4 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +27 -0
- data/README.md +46 -0
- data/lib/antlr4.rb +262 -0
- data/lib/antlr4/BufferedTokenStream.rb +306 -0
- data/lib/antlr4/CommonTokenFactory.rb +53 -0
- data/lib/antlr4/CommonTokenStream.rb +56 -0
- data/lib/antlr4/FileStream.rb +14 -0
- data/lib/antlr4/InputStream.rb +82 -0
- data/lib/antlr4/IntervalSet.rb +341 -0
- data/lib/antlr4/LL1Analyzer.rb +177 -0
- data/lib/antlr4/Lexer.rb +335 -0
- data/lib/antlr4/ListTokenSource.rb +140 -0
- data/lib/antlr4/Parser.rb +562 -0
- data/lib/antlr4/ParserInterpreter.rb +149 -0
- data/lib/antlr4/ParserRuleContext.rb +162 -0
- data/lib/antlr4/PredictionContext.rb +690 -0
- data/lib/antlr4/Recognizer.rb +162 -0
- data/lib/antlr4/RuleContext.rb +226 -0
- data/lib/antlr4/Token.rb +124 -0
- data/lib/antlr4/TokenFactory.rb +3 -0
- data/lib/antlr4/TokenSource.rb +4 -0
- data/lib/antlr4/TokenStream.rb +3 -0
- data/lib/antlr4/TraceListener.rb +23 -0
- data/lib/antlr4/atn/ATN.rb +133 -0
- data/lib/antlr4/atn/ATNConfig.rb +146 -0
- data/lib/antlr4/atn/ATNConfigSet.rb +215 -0
- data/lib/antlr4/atn/ATNDeserializationOptions.rb +62 -0
- data/lib/antlr4/atn/ATNDeserializer.rb +604 -0
- data/lib/antlr4/atn/ATNSimulator.rb +43 -0
- data/lib/antlr4/atn/ATNState.rb +253 -0
- data/lib/antlr4/atn/ATNType.rb +22 -0
- data/lib/antlr4/atn/LexerATNSimulator.rb +612 -0
- data/lib/antlr4/atn/LexerAction.rb +311 -0
- data/lib/antlr4/atn/LexerActionExecutor.rb +134 -0
- data/lib/antlr4/atn/ParserATNSimulator.rb +1622 -0
- data/lib/antlr4/atn/PredictionMode.rb +525 -0
- data/lib/antlr4/atn/SemanticContext.rb +355 -0
- data/lib/antlr4/atn/Transition.rb +297 -0
- data/lib/antlr4/base.rb +60 -0
- data/lib/antlr4/dfa/DFA.rb +128 -0
- data/lib/antlr4/dfa/DFASerializer.rb +77 -0
- data/lib/antlr4/dfa/DFAState.rb +133 -0
- data/lib/antlr4/error.rb +151 -0
- data/lib/antlr4/error/DiagnosticErrorListener.rb +136 -0
- data/lib/antlr4/error/ErrorListener.rb +109 -0
- data/lib/antlr4/error/ErrorStrategy.rb +742 -0
- data/lib/antlr4/tree/Chunk.rb +31 -0
- data/lib/antlr4/tree/ParseTreeMatch.rb +105 -0
- data/lib/antlr4/tree/ParseTreePattern.rb +70 -0
- data/lib/antlr4/tree/ParseTreePatternMatcher.rb +334 -0
- data/lib/antlr4/tree/RuleTagToken.rb +39 -0
- data/lib/antlr4/tree/TokenTagToken.rb +38 -0
- data/lib/antlr4/tree/Tree.rb +204 -0
- data/lib/antlr4/tree/Trees.rb +111 -0
- data/lib/antlr4/version.rb +5 -0
- data/lib/antlr4/xpath/XPath.rb +354 -0
- data/lib/double_key_map.rb +78 -0
- data/lib/java_symbols.rb +24 -0
- data/lib/uuid.rb +87 -0
- data/test/test_intervalset.rb +664 -0
- data/test/test_tree.rb +140 -0
- data/test/test_uuid.rb +122 -0
- metadata +109 -0
@@ -0,0 +1,140 @@
|
|
1
|
+
#
|
2
|
+
# Provides an implementation of {@link TokenSource} as a wrapper around a list
|
3
|
+
# of {@link Token} objects.
|
4
|
+
#
|
5
|
+
# <p>If the final token in the list is an {@link Token#EOF} token, it will be used
|
6
|
+
# as the EOF token for every call to {@link #nextToken} after the end of the
|
7
|
+
# list is reached. Otherwise, an EOF token will be created.</p>
|
8
|
+
|
9
|
+
class ListTokenSource < TokenSource
|
10
|
+
|
11
|
+
# Constructs a new {@link ListTokenSource} instance from the specified
|
12
|
+
# collection of {@link Token} objects and source name.
|
13
|
+
#
|
14
|
+
# @param tokens The collection of {@link Token} objects to provide as a
|
15
|
+
# {@link TokenSource}.
|
16
|
+
# @param sourceName The name of the {@link TokenSource}. If this value is
|
17
|
+
# {@code null}, {@link #getSourceName} will attempt to infer the name from
|
18
|
+
# the next {@link Token} (or the previous token if the end of the input has
|
19
|
+
# been reached).
|
20
|
+
#
|
21
|
+
# @exception NullPointerException if {@code tokens} is {@code null}
|
22
|
+
attr_accessor :tokens, :sourceName, :pos, :eofToken, :factory
|
23
|
+
def initialize(_tokens, source_name=nil)
|
24
|
+
raise ReferenceError.new("tokens cannot be null") if tokens.nil?
|
25
|
+
@tokens = _tokens
|
26
|
+
@sourceName = source_name
|
27
|
+
# The index into {@link #tokens} of token to return by the next call to
|
28
|
+
# {@link #nextToken}. The end of the input is indicated by this value
|
29
|
+
# being greater than or equal to the number of items in {@link #tokens}.
|
30
|
+
@pos = 0
|
31
|
+
# This field caches the EOF token for the token source.
|
32
|
+
@eofToken = nil
|
33
|
+
# This is the backing field for {@link #getTokenFactory} and
|
34
|
+
@factory = CommonTokenFactory.DEFAULT
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
#
|
39
|
+
# {@inheritDoc}
|
40
|
+
#
|
41
|
+
def column
|
42
|
+
if self.pos < self.tokens.length
|
43
|
+
return self.tokens[self.pos].column
|
44
|
+
elsif not self.eofToken.nil?
|
45
|
+
return self.eofToken.column
|
46
|
+
elsif self.tokens.length > 0
|
47
|
+
# have to calculate the result from the line/column of the previous
|
48
|
+
# token, along with the text of the token.
|
49
|
+
lastToken = self.tokens[-1]
|
50
|
+
tokenText = lastToken.getText()
|
51
|
+
if not tokenText.nil? then
|
52
|
+
lastNewLine = tokenText.rfind('\n')
|
53
|
+
if lastNewLine >= 0
|
54
|
+
return tokenText.length - lastNewLine - 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
return lastToken.column + lastToken.stopIndex - lastToken.startIndex + 1
|
58
|
+
end
|
59
|
+
# only reach this if tokens is empty, meaning EOF occurs at the first
|
60
|
+
# position in the input
|
61
|
+
return 0
|
62
|
+
end
|
63
|
+
#
|
64
|
+
# {@inheritDoc}
|
65
|
+
#
|
66
|
+
def nextToken
|
67
|
+
if self.pos >= self.tokens.length then
|
68
|
+
if self.eofToken.nil? then
|
69
|
+
start = -1
|
70
|
+
if self.tokens.length > 0 then
|
71
|
+
previousStop = self.tokens[-1].stopIndex
|
72
|
+
if previousStop != -1 then
|
73
|
+
start = previousStop + 1
|
74
|
+
end
|
75
|
+
end
|
76
|
+
stop = [-1, start - 1].max
|
77
|
+
self.eofToken = self.factory.create([self, self.getInputStream()],
|
78
|
+
Token::EOF, "EOF", Token::DEFAULT_CHANNEL, start, stop, self.line, self.column)
|
79
|
+
stop = [-1, start - 1].max
|
80
|
+
end
|
81
|
+
return self.eofToken
|
82
|
+
end
|
83
|
+
t = self.tokens[self.pos]
|
84
|
+
if self.pos == self.tokens.length - 1 and t.type == Token::EOF
|
85
|
+
eofToken = t
|
86
|
+
end
|
87
|
+
self.pos = self.pos + 1
|
88
|
+
return t
|
89
|
+
end
|
90
|
+
def line
|
91
|
+
if self.pos < self.tokens.length
|
92
|
+
return self.tokens[self.pos].line
|
93
|
+
elsif not self.eofToken.nil?
|
94
|
+
return self.eofToken.line
|
95
|
+
elsif self.tokens.length > 0
|
96
|
+
# have to calculate the result from the line/column of the previous
|
97
|
+
# token, along with the text of the token.
|
98
|
+
lastToken = self.tokens[-1]
|
99
|
+
line = lastToken.line
|
100
|
+
tokenText = lastToken.text
|
101
|
+
if not tokenText.nil? then
|
102
|
+
for c in tokenText do
|
103
|
+
if c == '\n'
|
104
|
+
line = line + 1
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
# if no text is available, assume the token did not contain any newline characters.
|
109
|
+
return line
|
110
|
+
end
|
111
|
+
# only reach this if tokens is empty, meaning EOF occurs at the first
|
112
|
+
# position in the input
|
113
|
+
return 1
|
114
|
+
end
|
115
|
+
#
|
116
|
+
# {@inheritDoc}
|
117
|
+
#
|
118
|
+
def getInputStream
|
119
|
+
if self.pos < self.tokens.length
|
120
|
+
return self.tokens[self.pos].getInputStream()
|
121
|
+
elsif not self.eofToken.nil?
|
122
|
+
return self.eofToken.getInputStream()
|
123
|
+
elsif self.tokens.length > 0
|
124
|
+
return self.tokens[-1].getInputStream()
|
125
|
+
else
|
126
|
+
# no input stream information is available
|
127
|
+
return nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def getSourceName
|
132
|
+
return self.sourceName unless self.sourceName.nil?
|
133
|
+
inputStream = self.getInputStream()
|
134
|
+
if not inputStream.nil?
|
135
|
+
return inputStream.getSourceName()
|
136
|
+
else
|
137
|
+
return "List"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,562 @@
|
|
1
|
+
# self is all the parsing support code essentially; most of it is error recovery stuff.#
|
2
|
+
class Parser < Recognizer
|
3
|
+
|
4
|
+
# self field maps from the serialized ATN string to the deserialized {@link ATN} with
|
5
|
+
# bypass alternatives.
|
6
|
+
#
|
7
|
+
# @see ATNDeserializationOptions#isGenerateRuleBypassTransitions()
|
8
|
+
#
|
9
|
+
@@bypassAltsAtnCache = Hash.new
|
10
|
+
|
11
|
+
attr_accessor :input,:errHandler,:precedenceStack ,:ctx, :buildParseTrees
|
12
|
+
attr_accessor :tracer, :parseListeners, :syntaxErrors
|
13
|
+
attr_accessor :tokenNames
|
14
|
+
def initialize(input)
|
15
|
+
super()
|
16
|
+
# The input stream.
|
17
|
+
self.input = nil
|
18
|
+
# The error handling strategy for the parser. The default value is a new
|
19
|
+
# instance of {@link DefaultErrorStrategy}.
|
20
|
+
self.errHandler = DefaultErrorStrategy.new()
|
21
|
+
@precedenceStack = Array.new()
|
22
|
+
@precedenceStack.push(0)
|
23
|
+
# The {@link ParserRuleContext} object for the currently executing rule.
|
24
|
+
# self is always non-null during the parsing process.
|
25
|
+
@ctx = nil
|
26
|
+
# Specifies whether or not the parser should construct a parse tree during
|
27
|
+
# the parsing process. The default value is {@code true}.
|
28
|
+
@buildParseTrees = true
|
29
|
+
# When {@link #setTrace}{@code (true)} is called, a reference to the
|
30
|
+
# {@link TraceListener} is stored here so it can be easily removed in a
|
31
|
+
# later call to {@link #setTrace}{@code (false)}. The listener itself is
|
32
|
+
# implemented as a parser listener so self field is not directly used by
|
33
|
+
# other parser methods.
|
34
|
+
@tracer = nil
|
35
|
+
# The list of {@link ParseTreeListener} listeners registered to receive
|
36
|
+
# events during the parse.
|
37
|
+
@parseListeners = Array.new()
|
38
|
+
# The number of syntax errors reported during parsing. self value is
|
39
|
+
# incremented each time {@link #notifyErrorListeners} is called.
|
40
|
+
@syntaxErrors = 0
|
41
|
+
self.setInputStream(input)
|
42
|
+
end
|
43
|
+
|
44
|
+
# reset the parser's state#
|
45
|
+
def reset()
|
46
|
+
self.input.seek(0) unless @input.nil?
|
47
|
+
@errHandler.reset(self)
|
48
|
+
@ctx = nil
|
49
|
+
@syntaxErrors = 0
|
50
|
+
self.setTrace(false)
|
51
|
+
@precedenceStack = Array.new
|
52
|
+
@precedenceStack.push(0)
|
53
|
+
@interp.reset() unless @interp.nil?
|
54
|
+
end
|
55
|
+
|
56
|
+
# Match current input symbol against {@code ttype}. If the symbol type
|
57
|
+
# matches, {@link ANTLRErrorStrategy#reportMatch} and {@link #consume} are
|
58
|
+
# called to complete the match process.
|
59
|
+
#
|
60
|
+
# <p>If the symbol type does not match,
|
61
|
+
# {@link ANTLRErrorStrategy#recoverInline} is called on the current error
|
62
|
+
# strategy to attempt recovery. If {@link #getBuildParseTree} is
|
63
|
+
# {@code true} and the token index of the symbol returned by
|
64
|
+
# {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
|
65
|
+
# the parse tree by calling {@link ParserRuleContext#addErrorNode}.</p>
|
66
|
+
#
|
67
|
+
# @param ttype the token type to match
|
68
|
+
# @return the matched symbol
|
69
|
+
# @throws RecognitionException if the current input symbol did not match
|
70
|
+
# {@code ttype} and the error strategy could not recover from the
|
71
|
+
# mismatched symbol
|
72
|
+
|
73
|
+
def match(ttype)
|
74
|
+
t = self.getCurrentToken()
|
75
|
+
if t.type==ttype
|
76
|
+
self.errHandler.reportMatch(self)
|
77
|
+
self.consume()
|
78
|
+
else
|
79
|
+
t = self.errHandler.recoverInline(self)
|
80
|
+
if self.buildParseTrees and t.tokenIndex==-1
|
81
|
+
# we must have conjured up a new token during single token insertion
|
82
|
+
# if it's not the current symbol
|
83
|
+
self.ctx.addErrorNode(t)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
return t
|
87
|
+
end
|
88
|
+
|
89
|
+
# Match current input symbol as a wildcard. If the symbol type matches
|
90
|
+
# (i.e. has a value greater than 0), {@link ANTLRErrorStrategy#reportMatch}
|
91
|
+
# and {@link #consume} are called to complete the match process.
|
92
|
+
#
|
93
|
+
# <p>If the symbol type does not match,
|
94
|
+
# {@link ANTLRErrorStrategy#recoverInline} is called on the current error
|
95
|
+
# strategy to attempt recovery. If {@link #getBuildParseTree} is
|
96
|
+
# {@code true} and the token index of the symbol returned by
|
97
|
+
# {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
|
98
|
+
# the parse tree by calling {@link ParserRuleContext#addErrorNode}.</p>
|
99
|
+
#
|
100
|
+
# @return the matched symbol
|
101
|
+
# @throws RecognitionException if the current input symbol did not match
|
102
|
+
# a wildcard and the error strategy could not recover from the mismatched
|
103
|
+
# symbol
|
104
|
+
|
105
|
+
def matchWildcard()
|
106
|
+
t = self.getCurrentToken()
|
107
|
+
if t.type > 0 then
|
108
|
+
self.errHandler.reportMatch(self)
|
109
|
+
self.consume()
|
110
|
+
else
|
111
|
+
t = self.errHandler.recoverInline(self)
|
112
|
+
if self.buildParseTrees and t.tokenIndex == -1 then
|
113
|
+
# we must have conjured up a new token during single token insertion
|
114
|
+
# if it's not the current symbol
|
115
|
+
self.ctx.addErrorNode(t)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
return t
|
119
|
+
end
|
120
|
+
|
121
|
+
def getParseListeners
|
122
|
+
self.parseListeners
|
123
|
+
end
|
124
|
+
|
125
|
+
# Registers {@code listener} to receive events during the parsing process.
|
126
|
+
#
|
127
|
+
# <p>To support output-preserving grammar transformations (including but not
|
128
|
+
# limited to left-recursion removal, automated left-factoring, and
|
129
|
+
# optimized code generation), calls to listener methods during the parse
|
130
|
+
# may differ substantially from calls made by
|
131
|
+
# {@link ParseTreeWalker#DEFAULT} used after the parse is complete. In
|
132
|
+
# particular, rule entry and exit events may occur in a different order
|
133
|
+
# during the parse than after the parser. In addition, calls to certain
|
134
|
+
# rule entry methods may be omitted.</p>
|
135
|
+
#
|
136
|
+
# <p>With the following specific exceptions, calls to listener events are
|
137
|
+
# <em>deterministic</em>, i.e. for identical input the calls to listener
|
138
|
+
# methods will be the same.</p>
|
139
|
+
#
|
140
|
+
# <ul>
|
141
|
+
# <li>Alterations to the grammar used to generate code may change the
|
142
|
+
# behavior of the listener calls.</li>
|
143
|
+
# <li>Alterations to the command line options passed to ANTLR 4 when
|
144
|
+
# generating the parser may change the behavior of the listener calls.</li>
|
145
|
+
# <li>Changing the version of the ANTLR Tool used to generate the parser
|
146
|
+
# may change the behavior of the listener calls.</li>
|
147
|
+
# </ul>
|
148
|
+
#
|
149
|
+
# @param listener the listener to add
|
150
|
+
#
|
151
|
+
# @throws NullPointerException if {@code} listener is {@code null}
|
152
|
+
#
|
153
|
+
def addParseListener(listener)
|
154
|
+
raise ReferenceError.new("listener is nil") if listener.nil?
|
155
|
+
# @parseListeners = Array.new if @parseListeners.nil?
|
156
|
+
self.parseListeners.push(listener)
|
157
|
+
end
|
158
|
+
|
159
|
+
#
|
160
|
+
# Remove {@code listener} from the list of parse listeners.
|
161
|
+
#
|
162
|
+
# <p>If {@code listener} is {@code null} or has not been added as a parse
|
163
|
+
# listener, self method does nothing.</p>
|
164
|
+
# @param listener the listener to remove
|
165
|
+
#
|
166
|
+
def removeParseListener(listener)
|
167
|
+
# return if self.parseListeners.nil?
|
168
|
+
self.parseListeners.delete(listener)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Remove all parse listeners.
|
172
|
+
def removeParseListeners
|
173
|
+
@parseListeners = Array.new
|
174
|
+
end
|
175
|
+
|
176
|
+
# Notify any parse listeners of an enter rule event.
|
177
|
+
def triggerEnterRuleEvent
|
178
|
+
self.parseListeners do |listener|
|
179
|
+
listener.enterEveryRule(self.ctx)
|
180
|
+
self.ctx.enterRule(listener)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
#
|
185
|
+
# Notify any parse listeners of an exit rule event.
|
186
|
+
#
|
187
|
+
# @see #addParseListener
|
188
|
+
#
|
189
|
+
def triggerExitRuleEvent
|
190
|
+
# reverse order walk of listeners
|
191
|
+
self.parseListeners.reverse do |listener|
|
192
|
+
self.ctx.exitRule(listener)
|
193
|
+
listener.exitEveryRule(self.ctx)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
def getTokenFactory
|
199
|
+
return self.input.tokenSource.factory
|
200
|
+
end
|
201
|
+
|
202
|
+
# Tell our token source and error strategy about a new way to create tokens.#
|
203
|
+
def setTokenFactory(factory)
|
204
|
+
self.input.tokenSource.factory = factory
|
205
|
+
end
|
206
|
+
|
207
|
+
# The ATN with bypass alternatives is expensive to create so we create it
|
208
|
+
# lazily.
|
209
|
+
#
|
210
|
+
# @throws UnsupportedOperationException if the current parser does not
|
211
|
+
# implement the {@link #getSerializedATN()} method.
|
212
|
+
#
|
213
|
+
def getATNWithBypassAlts()
|
214
|
+
serializedAtn = self.getSerializedATN()
|
215
|
+
if serializedAtn.nil?
|
216
|
+
raise UnsupportedOperationException.new("The current parser does not support an ATN with bypass alternatives.")
|
217
|
+
end
|
218
|
+
result = self.bypassAltsAtnCache.get(serializedAtn)
|
219
|
+
if result.nil? then
|
220
|
+
deserializationOptions = ATNDeserializationOptions.new()
|
221
|
+
deserializationOptions.generateRuleBypassTransitions = true
|
222
|
+
result = ATNDeserializer(deserializationOptions).deserialize(serializedAtn)
|
223
|
+
self.bypassAltsAtnCache[serializedAtn] = result
|
224
|
+
end
|
225
|
+
return result
|
226
|
+
end
|
227
|
+
|
228
|
+
# The preferred method of getting a tree pattern. For example, here's a
|
229
|
+
# sample use:
|
230
|
+
#
|
231
|
+
# <pre>
|
232
|
+
# ParseTree t = parser.expr();
|
233
|
+
# ParseTreePattern p = parser.compileParseTreePattern("<ID>+0", MyParser.RULE_expr);
|
234
|
+
# ParseTreeMatch m = p.match(t);
|
235
|
+
# String id = m.get("ID");
|
236
|
+
# </pre>
|
237
|
+
#
|
238
|
+
def compileParseTreePattern(pattern, patternRuleIndex, lexer=nil)
|
239
|
+
if lexer.nil? then
|
240
|
+
if not self.getTokenStream().nil? then
|
241
|
+
tokenSource = self.getTokenStream().getTokenSource()
|
242
|
+
end
|
243
|
+
lexer = tokenSource if tokenSource.kind_of? Lexer
|
244
|
+
end
|
245
|
+
if lexer.nil?
|
246
|
+
raise UnsupportedOperationException.new("Parser can't discover a lexer to use")
|
247
|
+
end
|
248
|
+
m = ParseTreePatternMatcher.new(lexer, self)
|
249
|
+
return m.compile(pattern, patternRuleIndex)
|
250
|
+
end
|
251
|
+
|
252
|
+
def getInputStream()
|
253
|
+
return self.getTokenStream()
|
254
|
+
end
|
255
|
+
|
256
|
+
def setInputStream(input)
|
257
|
+
self.setTokenStream(input)
|
258
|
+
end
|
259
|
+
|
260
|
+
def getTokenStream()
|
261
|
+
return self.input
|
262
|
+
end
|
263
|
+
|
264
|
+
# Set the token stream and reset the parser.#
|
265
|
+
def setTokenStream(input)
|
266
|
+
self.input = nil
|
267
|
+
self.reset()
|
268
|
+
self.input = input
|
269
|
+
end
|
270
|
+
# Match needs to return the current input symbol, which gets put
|
271
|
+
# into the label for the associated token ref; e.g., x=ID.
|
272
|
+
#
|
273
|
+
def getCurrentToken()
|
274
|
+
return self.input.LT(1)
|
275
|
+
end
|
276
|
+
|
277
|
+
def notifyErrorListeners(msg, offendingToken=nil ,e=nil) #RecognitionException
|
278
|
+
if offendingToken.nil?
|
279
|
+
offendingToken = self.getCurrentToken()
|
280
|
+
end
|
281
|
+
@syntaxErrors = @syntaxErrors + 1
|
282
|
+
line = offendingToken.line
|
283
|
+
column = offendingToken.column
|
284
|
+
listener = self.getErrorListenerDispatch()
|
285
|
+
listener.syntaxError(self, offendingToken, line, column, msg, e)
|
286
|
+
end
|
287
|
+
#
|
288
|
+
# Consume and return the {@linkplain #getCurrentToken current symbol}.
|
289
|
+
#
|
290
|
+
# <p>E.g., given the following input with {@code A} being the current
|
291
|
+
# lookahead symbol, self function moves the cursor to {@code B} and returns
|
292
|
+
# {@code A}.</p>
|
293
|
+
#
|
294
|
+
# <pre>
|
295
|
+
# A B
|
296
|
+
# ^
|
297
|
+
# </pre>
|
298
|
+
#
|
299
|
+
# If the parser is not in error recovery mode, the consumed symbol is added
|
300
|
+
# to the parse tree using {@link ParserRuleContext#addChild(Token)}, and
|
301
|
+
# {@link ParseTreeListener#visitTerminal} is called on any parse listeners.
|
302
|
+
# If the parser <em>is</em> in error recovery mode, the consumed symbol is
|
303
|
+
# added to the parse tree using
|
304
|
+
# {@link ParserRuleContext#addErrorNode(Token)}, and
|
305
|
+
# {@link ParseTreeListener#visitErrorNode} is called on any parse
|
306
|
+
# listeners.
|
307
|
+
#
|
308
|
+
def consume()
|
309
|
+
o = self.getCurrentToken()
|
310
|
+
if o.type != Token::EOF then
|
311
|
+
self.getInputStream().consume()
|
312
|
+
end
|
313
|
+
hasListener = ! self.parseListeners.empty?
|
314
|
+
if self.buildParseTrees or hasListener then
|
315
|
+
if self.errHandler.inErrorRecoveryMode(self) then
|
316
|
+
node = self.ctx.addErrorNode(o)
|
317
|
+
else
|
318
|
+
node = self.ctx.addTokenNode(o)
|
319
|
+
end
|
320
|
+
self.parseListeners.each {|listener| listener.visitTerminal(node) }
|
321
|
+
end
|
322
|
+
return o
|
323
|
+
end
|
324
|
+
|
325
|
+
def addContextToParseTree()
|
326
|
+
# add current context to parent if we have a parent
|
327
|
+
if self.ctx.parentCtx then
|
328
|
+
self.ctx.parentCtx.addChild(self.ctx)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
# Always called by generated parsers upon entry to a rule. Access field
|
332
|
+
# {@link #ctx} get the current context.
|
333
|
+
#
|
334
|
+
def enterRule(localctx, state, ruleIndex)
|
335
|
+
self.state = state
|
336
|
+
self.ctx = localctx
|
337
|
+
self.ctx.start = self.input.LT(1)
|
338
|
+
self.addContextToParseTree() if self.buildParseTrees
|
339
|
+
self.triggerEnterRuleEvent()
|
340
|
+
end
|
341
|
+
|
342
|
+
def exitRule()
|
343
|
+
self.ctx.stop = self.input.LT(-1)
|
344
|
+
# trigger event on ctx, before it reverts to parent
|
345
|
+
self.triggerExitRuleEvent()
|
346
|
+
self.state = self.ctx.invokingState
|
347
|
+
self.ctx = self.ctx.parentCtx
|
348
|
+
end
|
349
|
+
|
350
|
+
def enterOuterAlt(localctx, altNum)
|
351
|
+
# if we have new localctx, make sure we replace existing ctx
|
352
|
+
# that is previous child of parse tree
|
353
|
+
if self.buildParseTrees and self.ctx != localctx
|
354
|
+
if not self.ctx.parentCtx.nil? then
|
355
|
+
self.ctx.parentCtx.removeLastChild()
|
356
|
+
self.ctx.parentCtx.addChild(localctx)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
self.ctx = localctx
|
360
|
+
end
|
361
|
+
|
362
|
+
# Get the precedence level for the top-most precedence rule.
|
363
|
+
#
|
364
|
+
# @return The precedence level for the top-most precedence rule, or -1 if
|
365
|
+
# the parser context is not nested within a precedence rule.
|
366
|
+
#
|
367
|
+
def getPrecedence()
|
368
|
+
if @precedenceStack.length==0
|
369
|
+
return -1
|
370
|
+
else
|
371
|
+
return @precedenceStack[-1]
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def enterRecursionRule(localctx, state, ruleIndex, precedence)
|
376
|
+
self.state = state
|
377
|
+
self.precedenceStack.push(precedence)
|
378
|
+
self.ctx = localctx
|
379
|
+
self.ctx.start = self.input.LT(1)
|
380
|
+
self.triggerEnterRuleEvent() # simulates rule entry for left-recursive rules
|
381
|
+
end
|
382
|
+
|
383
|
+
#
|
384
|
+
# Like {@link #enterRule} but for recursive rules.
|
385
|
+
#
|
386
|
+
def pushNewRecursionContext(localctx, state, ruleIndex)
|
387
|
+
previous = self.ctx
|
388
|
+
previous.parentCtx = localctx
|
389
|
+
previous.invokingState = state
|
390
|
+
previous.stop = self.input.LT(-1)
|
391
|
+
|
392
|
+
self.ctx = localctx
|
393
|
+
self.ctx.start = previous.start
|
394
|
+
self.ctx.addChild(previous) if self.buildParseTrees
|
395
|
+
self.triggerEnterRuleEvent() # simulates rule entry for left-recursive rules
|
396
|
+
end
|
397
|
+
|
398
|
+
def unrollRecursionContexts(parentCtx)
|
399
|
+
self.precedenceStack.pop()
|
400
|
+
self.ctx.stop = self.input.LT(-1)
|
401
|
+
retCtx = self.ctx # save current ctx (return value)
|
402
|
+
# unroll so ctx is as it was before call to recursive method
|
403
|
+
if not self.parseListeners.empty? then
|
404
|
+
while self.ctx != parentCtx do
|
405
|
+
self.triggerExitRuleEvent()
|
406
|
+
self.ctx = self.ctx.parentCtx
|
407
|
+
end
|
408
|
+
else
|
409
|
+
self.ctx = parentCtx
|
410
|
+
end
|
411
|
+
# hook into tree
|
412
|
+
retCtx.parentCtx = parentCtx
|
413
|
+
|
414
|
+
if self.buildParseTrees and parentCtx then
|
415
|
+
# add return ctx into invoking rule's tree
|
416
|
+
parentCtx.addChild(retCtx)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
def getInvokingContext(ruleIndex)
|
420
|
+
ctx = self.ctx
|
421
|
+
while not ctx.nil? do
|
422
|
+
if ctx.ruleIndex == ruleIndex
|
423
|
+
return ctx
|
424
|
+
end
|
425
|
+
ctx = ctx.parentCtx
|
426
|
+
end
|
427
|
+
return nil
|
428
|
+
end
|
429
|
+
|
430
|
+
|
431
|
+
def precpred(localctx, precedence)
|
432
|
+
return precedence >= self.precedenceStack[-1]
|
433
|
+
end
|
434
|
+
|
435
|
+
def inContext(context)
|
436
|
+
# TODO: useful in parser?
|
437
|
+
return false
|
438
|
+
end
|
439
|
+
|
440
|
+
#
|
441
|
+
# Checks whether or not {@code symbol} can follow the current state in the
|
442
|
+
# ATN. The behavior of self method is equivalent to the following, but is
|
443
|
+
# implemented such that the complete context-sensitive follow set does not
|
444
|
+
# need to be explicitly constructed.
|
445
|
+
#
|
446
|
+
# <pre>
|
447
|
+
# return getExpectedTokens().contains(symbol);
|
448
|
+
# </pre>
|
449
|
+
#
|
450
|
+
# @param symbol the symbol type to check
|
451
|
+
# @return {@code true} if {@code symbol} can follow the current state in
|
452
|
+
# the ATN, otherwise {@code false}.
|
453
|
+
#
|
454
|
+
def isExpectedToken(symbol)
|
455
|
+
atn = self.interp.atn
|
456
|
+
ctx = self.ctx
|
457
|
+
s = atn.states[self.state]
|
458
|
+
following = atn.nextTokens(s)
|
459
|
+
# print "\nisExpectedToken: #{following.toString(tokenNames)}: #{s}"
|
460
|
+
if following.member?(symbol) then
|
461
|
+
# puts " true "
|
462
|
+
return true
|
463
|
+
end
|
464
|
+
if not following.member? Token::EPSILON then
|
465
|
+
# puts " FAIL "
|
466
|
+
return false
|
467
|
+
end
|
468
|
+
while ctx and ctx.invokingState >= 0 and following.member?(Token::EPSILON) do
|
469
|
+
invokingState = atn.states[ctx.invokingState]
|
470
|
+
rt = invokingState.transitions[0]
|
471
|
+
following = atn.nextTokens(rt.followState)
|
472
|
+
return true if following.member?(symbol)
|
473
|
+
ctx = ctx.parentCtx
|
474
|
+
end
|
475
|
+
if following.member?( Token::EPSILON) and symbol == Token::EOF
|
476
|
+
return true
|
477
|
+
else
|
478
|
+
return false
|
479
|
+
end
|
480
|
+
end
|
481
|
+
# Computes the set of input symbols which could follow the current parser
|
482
|
+
# state and context, as given by {@link #getState} and {@link #getContext},
|
483
|
+
# respectively.
|
484
|
+
#
|
485
|
+
# @see ATN#getExpectedTokens(int, RuleContext)
|
486
|
+
#
|
487
|
+
def getExpectedTokens()
|
488
|
+
return self.interp.atn.getExpectedTokens(self.state, self.ctx)
|
489
|
+
end
|
490
|
+
|
491
|
+
def getExpectedTokensWithinCurrentRule()
|
492
|
+
atn = self.interp.atn
|
493
|
+
s = atn.states[self.state]
|
494
|
+
return atn.nextTokens(s)
|
495
|
+
end
|
496
|
+
|
497
|
+
# Get a rule's index (i.e., {@code RULE_ruleName} field) or -1 if not found.#
|
498
|
+
def getRuleIndex(ruleName)
|
499
|
+
ruleIndex = self.getRuleIndexMap().get(ruleName)
|
500
|
+
if ruleIndex then
|
501
|
+
return ruleIndex
|
502
|
+
else
|
503
|
+
return -1
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
# Return List<String> of the rule names in your parser instance
|
508
|
+
# leading up to a call to the current rule. You could override if
|
509
|
+
# you want more details such as the file/line info of where
|
510
|
+
# in the ATN a rule is invoked.
|
511
|
+
#
|
512
|
+
# this is very useful for error messages.
|
513
|
+
#
|
514
|
+
def getRuleInvocationStack(p=nil)
|
515
|
+
p = self.ctx if p.nil?
|
516
|
+
stack = Array.new
|
517
|
+
while p do
|
518
|
+
# compute what follows who invoked us
|
519
|
+
ruleIndex = p.getRuleIndex()
|
520
|
+
if ruleIndex<0
|
521
|
+
stack.push("n/a")
|
522
|
+
else
|
523
|
+
stack.push(self.ruleNames[ruleIndex])
|
524
|
+
end
|
525
|
+
p = p.parentCtx
|
526
|
+
end
|
527
|
+
return stack
|
528
|
+
end
|
529
|
+
# For debugging and other purposes.#
|
530
|
+
def getDFAStrings
|
531
|
+
self.interp.decisionToDFA.map {|dfa| dfa.to_s }
|
532
|
+
end
|
533
|
+
# For debugging and other purposes.#
|
534
|
+
def dumpDFA()
|
535
|
+
seenOne = false
|
536
|
+
self.interp.decisionToDFA.each {|dfa|
|
537
|
+
if dfa.states.length > 0
|
538
|
+
puts "Decision #{dfa.decision}:"
|
539
|
+
puts dfa.toString(self.tokenNames)
|
540
|
+
end
|
541
|
+
}
|
542
|
+
end
|
543
|
+
def getSourceName
|
544
|
+
return self.input.sourceName
|
545
|
+
end
|
546
|
+
|
547
|
+
# During a parse is sometimes useful to listen in on the rule entry and exit
|
548
|
+
# events as well as token matches. self is for quick and dirty debugging.
|
549
|
+
#
|
550
|
+
def setTrace(trace)
|
551
|
+
if not trace then
|
552
|
+
self.removeParseListener(self.tracer)
|
553
|
+
self.tracer = nil
|
554
|
+
else
|
555
|
+
if self.tracer
|
556
|
+
self.removeParseListener(self.tracer)
|
557
|
+
end
|
558
|
+
self.tracer = TraceListener.new(self)
|
559
|
+
self.addParseListener(self.tracer)
|
560
|
+
end
|
561
|
+
end
|
562
|
+
end
|