antlr4 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +27 -0
  3. data/README.md +46 -0
  4. data/lib/antlr4.rb +262 -0
  5. data/lib/antlr4/BufferedTokenStream.rb +306 -0
  6. data/lib/antlr4/CommonTokenFactory.rb +53 -0
  7. data/lib/antlr4/CommonTokenStream.rb +56 -0
  8. data/lib/antlr4/FileStream.rb +14 -0
  9. data/lib/antlr4/InputStream.rb +82 -0
  10. data/lib/antlr4/IntervalSet.rb +341 -0
  11. data/lib/antlr4/LL1Analyzer.rb +177 -0
  12. data/lib/antlr4/Lexer.rb +335 -0
  13. data/lib/antlr4/ListTokenSource.rb +140 -0
  14. data/lib/antlr4/Parser.rb +562 -0
  15. data/lib/antlr4/ParserInterpreter.rb +149 -0
  16. data/lib/antlr4/ParserRuleContext.rb +162 -0
  17. data/lib/antlr4/PredictionContext.rb +690 -0
  18. data/lib/antlr4/Recognizer.rb +162 -0
  19. data/lib/antlr4/RuleContext.rb +226 -0
  20. data/lib/antlr4/Token.rb +124 -0
  21. data/lib/antlr4/TokenFactory.rb +3 -0
  22. data/lib/antlr4/TokenSource.rb +4 -0
  23. data/lib/antlr4/TokenStream.rb +3 -0
  24. data/lib/antlr4/TraceListener.rb +23 -0
  25. data/lib/antlr4/atn/ATN.rb +133 -0
  26. data/lib/antlr4/atn/ATNConfig.rb +146 -0
  27. data/lib/antlr4/atn/ATNConfigSet.rb +215 -0
  28. data/lib/antlr4/atn/ATNDeserializationOptions.rb +62 -0
  29. data/lib/antlr4/atn/ATNDeserializer.rb +604 -0
  30. data/lib/antlr4/atn/ATNSimulator.rb +43 -0
  31. data/lib/antlr4/atn/ATNState.rb +253 -0
  32. data/lib/antlr4/atn/ATNType.rb +22 -0
  33. data/lib/antlr4/atn/LexerATNSimulator.rb +612 -0
  34. data/lib/antlr4/atn/LexerAction.rb +311 -0
  35. data/lib/antlr4/atn/LexerActionExecutor.rb +134 -0
  36. data/lib/antlr4/atn/ParserATNSimulator.rb +1622 -0
  37. data/lib/antlr4/atn/PredictionMode.rb +525 -0
  38. data/lib/antlr4/atn/SemanticContext.rb +355 -0
  39. data/lib/antlr4/atn/Transition.rb +297 -0
  40. data/lib/antlr4/base.rb +60 -0
  41. data/lib/antlr4/dfa/DFA.rb +128 -0
  42. data/lib/antlr4/dfa/DFASerializer.rb +77 -0
  43. data/lib/antlr4/dfa/DFAState.rb +133 -0
  44. data/lib/antlr4/error.rb +151 -0
  45. data/lib/antlr4/error/DiagnosticErrorListener.rb +136 -0
  46. data/lib/antlr4/error/ErrorListener.rb +109 -0
  47. data/lib/antlr4/error/ErrorStrategy.rb +742 -0
  48. data/lib/antlr4/tree/Chunk.rb +31 -0
  49. data/lib/antlr4/tree/ParseTreeMatch.rb +105 -0
  50. data/lib/antlr4/tree/ParseTreePattern.rb +70 -0
  51. data/lib/antlr4/tree/ParseTreePatternMatcher.rb +334 -0
  52. data/lib/antlr4/tree/RuleTagToken.rb +39 -0
  53. data/lib/antlr4/tree/TokenTagToken.rb +38 -0
  54. data/lib/antlr4/tree/Tree.rb +204 -0
  55. data/lib/antlr4/tree/Trees.rb +111 -0
  56. data/lib/antlr4/version.rb +5 -0
  57. data/lib/antlr4/xpath/XPath.rb +354 -0
  58. data/lib/double_key_map.rb +78 -0
  59. data/lib/java_symbols.rb +24 -0
  60. data/lib/uuid.rb +87 -0
  61. data/test/test_intervalset.rb +664 -0
  62. data/test/test_tree.rb +140 -0
  63. data/test/test_uuid.rb +122 -0
  64. 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("&lt;ID&gt;+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&lt;String&gt; 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