xref: /aosp_15_r20/external/antlr/runtime/Ruby/lib/antlr3/debug.rb (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
1*16467b97STreehugger Robot#!/usr/bin/ruby
2*16467b97STreehugger Robot# encoding: utf-8
3*16467b97STreehugger Robot
4*16467b97STreehugger Robotrequire 'antlr3'
5*16467b97STreehugger Robot
6*16467b97STreehugger Robot=begin LICENSE
7*16467b97STreehugger Robot
8*16467b97STreehugger Robot[The "BSD licence"]
9*16467b97STreehugger RobotCopyright (c) 2009-2010 Kyle Yetter
10*16467b97STreehugger RobotAll rights reserved.
11*16467b97STreehugger Robot
12*16467b97STreehugger RobotRedistribution and use in source and binary forms, with or without
13*16467b97STreehugger Robotmodification, are permitted provided that the following conditions
14*16467b97STreehugger Robotare met:
15*16467b97STreehugger Robot
16*16467b97STreehugger Robot 1. Redistributions of source code must retain the above copyright
17*16467b97STreehugger Robot    notice, this list of conditions and the following disclaimer.
18*16467b97STreehugger Robot 2. Redistributions in binary form must reproduce the above copyright
19*16467b97STreehugger Robot    notice, this list of conditions and the following disclaimer in the
20*16467b97STreehugger Robot    documentation and/or other materials provided with the distribution.
21*16467b97STreehugger Robot 3. The name of the author may not be used to endorse or promote products
22*16467b97STreehugger Robot    derived from this software without specific prior written permission.
23*16467b97STreehugger Robot
24*16467b97STreehugger RobotTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25*16467b97STreehugger RobotIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26*16467b97STreehugger RobotOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27*16467b97STreehugger RobotIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28*16467b97STreehugger RobotINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29*16467b97STreehugger RobotNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30*16467b97STreehugger RobotDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31*16467b97STreehugger RobotTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32*16467b97STreehugger Robot(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33*16467b97STreehugger RobotTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*16467b97STreehugger Robot
35*16467b97STreehugger Robot=end
36*16467b97STreehugger Robot
37*16467b97STreehugger Robotmodule ANTLR3
38*16467b97STreehugger Robot
39*16467b97STreehugger Robot=begin rdoc ANTLR3::Debug
40*16467b97STreehugger Robot
41*16467b97STreehugger RobotNamespace for all debugging-related class and module definitions.
42*16467b97STreehugger Robot
43*16467b97STreehugger Robot=end
44*16467b97STreehugger Robot
45*16467b97STreehugger Robotmodule Debug
46*16467b97STreehugger Robot
47*16467b97STreehugger RobotDEFAULT_PORT = 49100
48*16467b97STreehugger Robot
49*16467b97STreehugger Robot# since there are many components to the debug-mode
50*16467b97STreehugger Robot# section of the antlr3 runtime library, most of which
51*16467b97STreehugger Robot# are not used simultaneously, debug.rb contains the
52*16467b97STreehugger Robot# base of the debug library and the various listeners
53*16467b97STreehugger Robot# and tree-related code are autloaded on-demand
54*16467b97STreehugger Robotautoload :EventSocketProxy, 'antlr3/debug/socket'
55*16467b97STreehugger Robotautoload :RemoteEventSocketListener, 'antlr3/debug/socket'
56*16467b97STreehugger Robotautoload :TraceEventListener, 'antlr3/debug/trace-event-listener'
57*16467b97STreehugger Robotautoload :RecordEventListener, 'antlr3/debug/record-event-listener'
58*16467b97STreehugger Robotautoload :RuleTracer, 'antlr3/debug/rule-tracer'
59*16467b97STreehugger Robotautoload :EventHub, 'antlr3/debug/event-hub'
60*16467b97STreehugger Robotautoload :TreeAdaptor, 'antlr3/tree/debug'
61*16467b97STreehugger Robotautoload :TreeNodeStream, 'antlr3/tree/debug'
62*16467b97STreehugger Robot
63*16467b97STreehugger RobotRecognizerSharedState = Struct.new(
64*16467b97STreehugger Robot  # the rule invocation depth
65*16467b97STreehugger Robot  :rule_invocation_stack,
66*16467b97STreehugger Robot  # a boolean flag to indicate whether or not the current decision is cyclic
67*16467b97STreehugger Robot  :cyclic_decision,
68*16467b97STreehugger Robot  # a stack that tracks follow sets for error recovery
69*16467b97STreehugger Robot  :following,
70*16467b97STreehugger Robot  # a flag indicating whether or not the recognizer is in error recovery mode
71*16467b97STreehugger Robot  :error_recovery,
72*16467b97STreehugger Robot  # the index in the input stream of the last error
73*16467b97STreehugger Robot  :last_error_index,
74*16467b97STreehugger Robot  # tracks the backtracking depth
75*16467b97STreehugger Robot  :backtracking,
76*16467b97STreehugger Robot  # if a grammar is compiled with the memoization option, this will
77*16467b97STreehugger Robot  # be set to a hash mapping previously parsed rules to cached indices
78*16467b97STreehugger Robot  :rule_memory,
79*16467b97STreehugger Robot  # tracks the number of syntax errors seen so far
80*16467b97STreehugger Robot  :syntax_errors,
81*16467b97STreehugger Robot  # holds newly constructed tokens for lexer rules
82*16467b97STreehugger Robot  :token,
83*16467b97STreehugger Robot  # the input stream index at which the token starts
84*16467b97STreehugger Robot  :token_start_position,
85*16467b97STreehugger Robot  # the input stream line number at which the token starts
86*16467b97STreehugger Robot  :token_start_line,
87*16467b97STreehugger Robot  # the input stream column at which the token starts
88*16467b97STreehugger Robot  :token_start_column,
89*16467b97STreehugger Robot  # the channel value of the target token
90*16467b97STreehugger Robot  :channel,
91*16467b97STreehugger Robot  # the type value of the target token
92*16467b97STreehugger Robot  :type,
93*16467b97STreehugger Robot  # the text of the target token
94*16467b97STreehugger Robot  :text
95*16467b97STreehugger Robot)
96*16467b97STreehugger Robot
97*16467b97STreehugger Robot=begin rdoc ANTLR3::Debug::RecognizerSharedState
98*16467b97STreehugger Robot
99*16467b97STreehugger RobotANTLR3::Debug::RecognizerSharedState is identical to
100*16467b97STreehugger RobotANTLR3::RecognizerSharedState, but adds additional fields used for recognizers
101*16467b97STreehugger Robotgenerated in debug or profiling mode.
102*16467b97STreehugger Robot
103*16467b97STreehugger Robot=end
104*16467b97STreehugger Robotclass RecognizerSharedState
105*16467b97STreehugger Robot  def initialize
106*16467b97STreehugger Robot    super( [], false, [], false, -1, 0, nil, 0, nil, -1 )
107*16467b97STreehugger Robot    # ^-- same as this --v
108*16467b97STreehugger Robot    # self.following = []
109*16467b97STreehugger Robot    # self.error_recovery = false
110*16467b97STreehugger Robot    # self.last_error_index = -1
111*16467b97STreehugger Robot    # self.backtracking = 0
112*16467b97STreehugger Robot    # self.syntax_errors = 0
113*16467b97STreehugger Robot    # self.rule_level = 0
114*16467b97STreehugger Robot    # self.token_start_position = -1
115*16467b97STreehugger Robot  end
116*16467b97STreehugger Robot
117*16467b97STreehugger Robot  def reset!
118*16467b97STreehugger Robot    self.following.clear
119*16467b97STreehugger Robot    self.error_recovery = false
120*16467b97STreehugger Robot    self.last_error_index = -1
121*16467b97STreehugger Robot    self.backtracking = 0
122*16467b97STreehugger Robot    self.rule_memory and rule_memory.clear
123*16467b97STreehugger Robot    self.syntax_errors = 0
124*16467b97STreehugger Robot    self.token = nil
125*16467b97STreehugger Robot    self.token_start_position = -1
126*16467b97STreehugger Robot    self.token_start_line = nil
127*16467b97STreehugger Robot    self.token_start_column = nil
128*16467b97STreehugger Robot    self.channel = nil
129*16467b97STreehugger Robot    self.type = nil
130*16467b97STreehugger Robot    self.text = nil
131*16467b97STreehugger Robot    self.rule_invocation_stack.clear
132*16467b97STreehugger Robot  end
133*16467b97STreehugger Robot
134*16467b97STreehugger Robotend
135*16467b97STreehugger Robot
136*16467b97STreehugger Robot=begin rdoc ANTLR3::Debug::ParserEvents
137*16467b97STreehugger Robot
138*16467b97STreehugger RobotParserEvents adds debugging event hook methods and functionality that is
139*16467b97STreehugger Robotrequired by the code ANTLR generated when called with the <tt>-debug</tt>
140*16467b97STreehugger Robotswitch.
141*16467b97STreehugger Robot
142*16467b97STreehugger Robot=end
143*16467b97STreehugger Robotmodule ParserEvents
144*16467b97STreehugger Robot  include ANTLR3::Error
145*16467b97STreehugger Robot
146*16467b97STreehugger Robot  def self.included( klass )
147*16467b97STreehugger Robot    super
148*16467b97STreehugger Robot    if klass.is_a?( ::Class )
149*16467b97STreehugger Robot      def klass.debug?
150*16467b97STreehugger Robot        true
151*16467b97STreehugger Robot      end
152*16467b97STreehugger Robot    end
153*16467b97STreehugger Robot  end
154*16467b97STreehugger Robot
155*16467b97STreehugger Robot
156*16467b97STreehugger Robot  attr_reader :debug_listener
157*16467b97STreehugger Robot
158*16467b97STreehugger Robot  def initialize( stream, options = {} )
159*16467b97STreehugger Robot    @debug_listener = options[ :debug_listener ] ||= begin
160*16467b97STreehugger Robot      EventSocketProxy.new( self, options ).handshake
161*16467b97STreehugger Robot    end
162*16467b97STreehugger Robot    options[ :state ] ||= Debug::RecognizerSharedState.new
163*16467b97STreehugger Robot    super( stream, options )
164*16467b97STreehugger Robot    if @input.is_a?( Debug::TokenStream )
165*16467b97STreehugger Robot      @input.debug_listener ||= @debug_listener
166*16467b97STreehugger Robot    else
167*16467b97STreehugger Robot      @input = Debug::TokenStream.wrap( @input, @debug_listener )
168*16467b97STreehugger Robot    end
169*16467b97STreehugger Robot  end
170*16467b97STreehugger Robot
171*16467b97STreehugger Robot  def rule_level
172*16467b97STreehugger Robot    @state.rule_invocation_stack.length
173*16467b97STreehugger Robot  end
174*16467b97STreehugger Robot
175*16467b97STreehugger Robot  def cyclic_decision?
176*16467b97STreehugger Robot    @state.cyclic_decision
177*16467b97STreehugger Robot  end
178*16467b97STreehugger Robot
179*16467b97STreehugger Robot  def cyclic_decision=( flag )
180*16467b97STreehugger Robot    @state.cyclic_decision = flag
181*16467b97STreehugger Robot  end
182*16467b97STreehugger Robot
183*16467b97STreehugger Robot  # custom attribute writer for debug_listener
184*16467b97STreehugger Robot  # propegates the change in listener to the
185*16467b97STreehugger Robot  # parser's debugging input stream
186*16467b97STreehugger Robot  def debug_listener=( dbg )
187*16467b97STreehugger Robot    @debug_listener = dbg
188*16467b97STreehugger Robot    @input.debug_listener = dbg rescue nil
189*16467b97STreehugger Robot  end
190*16467b97STreehugger Robot
191*16467b97STreehugger Robot  def begin_resync
192*16467b97STreehugger Robot    @debug_listener.begin_resync
193*16467b97STreehugger Robot    super
194*16467b97STreehugger Robot  end
195*16467b97STreehugger Robot
196*16467b97STreehugger Robot  def end_resync
197*16467b97STreehugger Robot    @debug_listener.end_resync
198*16467b97STreehugger Robot    super
199*16467b97STreehugger Robot  end
200*16467b97STreehugger Robot
201*16467b97STreehugger Robot  # TO-DO: is this pointless?
202*16467b97STreehugger Robot  def resync
203*16467b97STreehugger Robot    begin_resync
204*16467b97STreehugger Robot    yield( self )
205*16467b97STreehugger Robot  ensure
206*16467b97STreehugger Robot    end_resync
207*16467b97STreehugger Robot  end
208*16467b97STreehugger Robot
209*16467b97STreehugger Robot  def begin_backtrack
210*16467b97STreehugger Robot    @debug_listener.begin_backtrack( @state.backtracking )
211*16467b97STreehugger Robot  end
212*16467b97STreehugger Robot
213*16467b97STreehugger Robot  def end_backtrack( successful )
214*16467b97STreehugger Robot    @debug_listener.end_backtrack( @state.backtracking, successful )
215*16467b97STreehugger Robot  end
216*16467b97STreehugger Robot
217*16467b97STreehugger Robot  def backtrack
218*16467b97STreehugger Robot    @state.backtracking += 1
219*16467b97STreehugger Robot    @debug_listener.begin_backtrack( @state.backtracking )
220*16467b97STreehugger Robot    start = @input.mark
221*16467b97STreehugger Robot    success =
222*16467b97STreehugger Robot      begin yield
223*16467b97STreehugger Robot      rescue BacktrackingFailed then false
224*16467b97STreehugger Robot      else true
225*16467b97STreehugger Robot      end
226*16467b97STreehugger Robot    return success
227*16467b97STreehugger Robot  ensure
228*16467b97STreehugger Robot    @input.rewind( start )
229*16467b97STreehugger Robot    @debug_listener.end_backtrack( @state.backtracking, ( success rescue nil ) )
230*16467b97STreehugger Robot    @state.backtracking -= 1
231*16467b97STreehugger Robot  end
232*16467b97STreehugger Robot
233*16467b97STreehugger Robot  def report_error( exc )
234*16467b97STreehugger Robot    ANTLR3::RecognitionError === exc and
235*16467b97STreehugger Robot      @debug_listener.recognition_exception( exc )
236*16467b97STreehugger Robot    super
237*16467b97STreehugger Robot  end
238*16467b97STreehugger Robot
239*16467b97STreehugger Robot  def missing_symbol( error, expected_type, follow )
240*16467b97STreehugger Robot    symbol = super
241*16467b97STreehugger Robot    @debug_listener.consume_node( symbol )
242*16467b97STreehugger Robot    return( symbol )
243*16467b97STreehugger Robot  end
244*16467b97STreehugger Robot
245*16467b97STreehugger Robot  def in_rule( grammar_file, rule_name )
246*16467b97STreehugger Robot    @state.rule_invocation_stack.empty? and @debug_listener.commence
247*16467b97STreehugger Robot    @debug_listener.enter_rule( grammar_file, rule_name )
248*16467b97STreehugger Robot    @state.rule_invocation_stack.push( grammar_file, rule_name )
249*16467b97STreehugger Robot    yield
250*16467b97STreehugger Robot  ensure
251*16467b97STreehugger Robot    @state.rule_invocation_stack.pop( 2 )
252*16467b97STreehugger Robot    @debug_listener.exit_rule( grammar_file, rule_name )
253*16467b97STreehugger Robot    @state.rule_invocation_stack.empty? and @debug_listener.terminate
254*16467b97STreehugger Robot  end
255*16467b97STreehugger Robot
256*16467b97STreehugger Robot  def rule_invocation_stack
257*16467b97STreehugger Robot    @state.rule_invocation_stack.each_slice( 2 ).to_a
258*16467b97STreehugger Robot  end
259*16467b97STreehugger Robot
260*16467b97STreehugger Robot  def predicate?( description )
261*16467b97STreehugger Robot    result = yield
262*16467b97STreehugger Robot    @debug_listener.semantic_predicate( result, description )
263*16467b97STreehugger Robot    return result
264*16467b97STreehugger Robot  end
265*16467b97STreehugger Robot
266*16467b97STreehugger Robot  def in_alternative( alt_number )
267*16467b97STreehugger Robot    @debug_listener.enter_alternative( alt_number )
268*16467b97STreehugger Robot  end
269*16467b97STreehugger Robot
270*16467b97STreehugger Robot  def in_subrule( decision_number )
271*16467b97STreehugger Robot    @debug_listener.enter_subrule( decision_number )
272*16467b97STreehugger Robot    yield
273*16467b97STreehugger Robot  ensure
274*16467b97STreehugger Robot    @debug_listener.exit_subrule( decision_number )
275*16467b97STreehugger Robot  end
276*16467b97STreehugger Robot
277*16467b97STreehugger Robot  def in_decision( decision_number )
278*16467b97STreehugger Robot    @debug_listener.enter_decision( decision_number )
279*16467b97STreehugger Robot    yield
280*16467b97STreehugger Robot  ensure
281*16467b97STreehugger Robot    @debug_listener.exit_decision( decision_number )
282*16467b97STreehugger Robot  end
283*16467b97STreehugger Robotend
284*16467b97STreehugger Robot
285*16467b97STreehugger Robot
286*16467b97STreehugger Robot=begin rdoc ANTLR3::Debug::TokenStream
287*16467b97STreehugger Robot
288*16467b97STreehugger RobotA module that wraps token stream methods with debugging event code. A debuggable
289*16467b97STreehugger Robotparser will <tt>extend</tt> its input stream with this module if the stream is
290*16467b97STreehugger Robotnot already a Debug::TokenStream.
291*16467b97STreehugger Robot
292*16467b97STreehugger Robot=end
293*16467b97STreehugger Robotmodule TokenStream
294*16467b97STreehugger Robot
295*16467b97STreehugger Robot  def self.wrap( stream, debug_listener = nil )
296*16467b97STreehugger Robot    stream.extend( self )
297*16467b97STreehugger Robot    stream.instance_eval do
298*16467b97STreehugger Robot      @initial_stream_state = true
299*16467b97STreehugger Robot      @debug_listener = debug_listener
300*16467b97STreehugger Robot      @last_marker = nil
301*16467b97STreehugger Robot    end
302*16467b97STreehugger Robot    return( stream )
303*16467b97STreehugger Robot  end
304*16467b97STreehugger Robot  attr_reader :last_marker
305*16467b97STreehugger Robot  attr_accessor :debug_listener
306*16467b97STreehugger Robot
307*16467b97STreehugger Robot  def consume
308*16467b97STreehugger Robot    @initial_stream_state and consume_initial_hidden_tokens
309*16467b97STreehugger Robot    a = index + 1 # the next position IF there are no hidden tokens in between
310*16467b97STreehugger Robot    t = super
311*16467b97STreehugger Robot    b = index     # the actual position after consuming
312*16467b97STreehugger Robot    @debug_listener.consume_token( t ) if @debug_listener
313*16467b97STreehugger Robot
314*16467b97STreehugger Robot    # if b > a, report the consumption of hidden tokens
315*16467b97STreehugger Robot    for i in a...b
316*16467b97STreehugger Robot      @debug_listener.consume_hidden_token at( i )
317*16467b97STreehugger Robot    end
318*16467b97STreehugger Robot  end
319*16467b97STreehugger Robot
320*16467b97STreehugger Robot
321*16467b97STreehugger Robot  # after a token stream fills up its buffer
322*16467b97STreehugger Robot  # by exhausting its token source, it may
323*16467b97STreehugger Robot  # skip to an initial position beyond the first
324*16467b97STreehugger Robot  # actual token, if there are hidden tokens
325*16467b97STreehugger Robot  # at the beginning of the stream.
326*16467b97STreehugger Robot  #
327*16467b97STreehugger Robot  # This private method is used to
328*16467b97STreehugger Robot  # figure out if any hidden tokens
329*16467b97STreehugger Robot  # were skipped initially, and then
330*16467b97STreehugger Robot  # report their consumption to
331*16467b97STreehugger Robot  # the debug listener
332*16467b97STreehugger Robot  def consume_initial_hidden_tokens
333*16467b97STreehugger Robot    first_on_channel_token_index = self.index
334*16467b97STreehugger Robot    first_on_channel_token_index.times do |index|
335*16467b97STreehugger Robot      @debug_listener.consume_hidden_token at( index )
336*16467b97STreehugger Robot    end
337*16467b97STreehugger Robot    @initial_stream_state = false
338*16467b97STreehugger Robot  end
339*16467b97STreehugger Robot
340*16467b97STreehugger Robot  private :consume_initial_hidden_tokens
341*16467b97STreehugger Robot
342*16467b97STreehugger Robot  ############################################################################################
343*16467b97STreehugger Robot  ###################################### Stream Methods ######################################
344*16467b97STreehugger Robot  ############################################################################################
345*16467b97STreehugger Robot
346*16467b97STreehugger Robot  def look( steps = 1 )
347*16467b97STreehugger Robot    @initial_stream_state and consume_initial_hidden_tokens
348*16467b97STreehugger Robot    token = super( steps )
349*16467b97STreehugger Robot    @debug_listener.look( steps, token )
350*16467b97STreehugger Robot    return token
351*16467b97STreehugger Robot  end
352*16467b97STreehugger Robot
353*16467b97STreehugger Robot  def peek( steps = 1 )
354*16467b97STreehugger Robot    look( steps ).type
355*16467b97STreehugger Robot  end
356*16467b97STreehugger Robot
357*16467b97STreehugger Robot  def mark
358*16467b97STreehugger Robot    @last_marker = super
359*16467b97STreehugger Robot    @debug_listener.mark( @last_marker )
360*16467b97STreehugger Robot    return @last_marker
361*16467b97STreehugger Robot  end
362*16467b97STreehugger Robot
363*16467b97STreehugger Robot  def rewind( marker = nil, release = true )
364*16467b97STreehugger Robot    @debug_listener.rewind( marker )
365*16467b97STreehugger Robot    super
366*16467b97STreehugger Robot  end
367*16467b97STreehugger Robotend
368*16467b97STreehugger Robot
369*16467b97STreehugger Robot=begin rdoc ANTLR3::Debug::EventListener
370*16467b97STreehugger Robot
371*16467b97STreehugger RobotA listener that simply records text representations of the events. Useful for debugging the
372*16467b97STreehugger Robotdebugging facility ;) Subclasses can override the record() method (which defaults to printing
373*16467b97STreehugger Robotto stdout) to record the events in a different way.
374*16467b97STreehugger Robot
375*16467b97STreehugger Robot=end
376*16467b97STreehugger Robotmodule EventListener
377*16467b97STreehugger Robot  PROTOCOL_VERSION = '2'
378*16467b97STreehugger Robot  # The parser has just entered a rule. No decision has been made about
379*16467b97STreehugger Robot  # which alt is predicted.  This is fired AFTER init actions have been
380*16467b97STreehugger Robot  # executed.  Attributes are defined and available etc...
381*16467b97STreehugger Robot  # The grammarFileName allows composite grammars to jump around among
382*16467b97STreehugger Robot  # multiple grammar files.
383*16467b97STreehugger Robot
384*16467b97STreehugger Robot  def enter_rule( grammar_file, rule_name )
385*16467b97STreehugger Robot    # do nothing
386*16467b97STreehugger Robot  end
387*16467b97STreehugger Robot
388*16467b97STreehugger Robot  # Because rules can have lots of alternatives, it is very useful to
389*16467b97STreehugger Robot  # know which alt you are entering.  This is 1..n for n alts.
390*16467b97STreehugger Robot
391*16467b97STreehugger Robot  def enter_alternative( alt )
392*16467b97STreehugger Robot    # do nothing
393*16467b97STreehugger Robot  end
394*16467b97STreehugger Robot
395*16467b97STreehugger Robot  # This is the last thing executed before leaving a rule.  It is
396*16467b97STreehugger Robot  # executed even if an exception is thrown.  This is triggered after
397*16467b97STreehugger Robot  # error reporting and recovery have occurred (unless the exception is
398*16467b97STreehugger Robot  # not caught in this rule).  This implies an "exitAlt" event.
399*16467b97STreehugger Robot  # The grammarFileName allows composite grammars to jump around among
400*16467b97STreehugger Robot  # multiple grammar files.
401*16467b97STreehugger Robot
402*16467b97STreehugger Robot  def exit_rule( grammar_file, rule_name )
403*16467b97STreehugger Robot    # do nothing
404*16467b97STreehugger Robot  end
405*16467b97STreehugger Robot
406*16467b97STreehugger Robot  # Track entry into any (...) subrule other EBNF construct
407*16467b97STreehugger Robot
408*16467b97STreehugger Robot  def enter_subrule( decision_number )
409*16467b97STreehugger Robot    # do nothing
410*16467b97STreehugger Robot  end
411*16467b97STreehugger Robot
412*16467b97STreehugger Robot  def exit_subrule( decision_number )
413*16467b97STreehugger Robot    # do nothing
414*16467b97STreehugger Robot  end
415*16467b97STreehugger Robot
416*16467b97STreehugger Robot  # Every decision, fixed k or arbitrary, has an enter/exit event
417*16467b97STreehugger Robot  # so that a GUI can easily track what look/consume events are
418*16467b97STreehugger Robot  # associated with prediction.  You will see a single enter/exit
419*16467b97STreehugger Robot  # subrule but multiple enter/exit decision events, one for each
420*16467b97STreehugger Robot  # loop iteration.
421*16467b97STreehugger Robot
422*16467b97STreehugger Robot  def enter_decision( decision_number )
423*16467b97STreehugger Robot    # do nothing
424*16467b97STreehugger Robot  end
425*16467b97STreehugger Robot
426*16467b97STreehugger Robot  def exit_decision( decision_number )
427*16467b97STreehugger Robot    # do nothing
428*16467b97STreehugger Robot  end
429*16467b97STreehugger Robot
430*16467b97STreehugger Robot  # An input token was consumed; matched by any kind of element.
431*16467b97STreehugger Robot  # Trigger after the token was matched by things like match(), matchAny().
432*16467b97STreehugger Robot
433*16467b97STreehugger Robot  def consume_token( tree )
434*16467b97STreehugger Robot    # do nothing
435*16467b97STreehugger Robot  end
436*16467b97STreehugger Robot
437*16467b97STreehugger Robot  # An off-channel input token was consumed.
438*16467b97STreehugger Robot  # Trigger after the token was matched by things like match(), matchAny().
439*16467b97STreehugger Robot  # (unless of course the hidden token is first stuff in the input stream).
440*16467b97STreehugger Robot
441*16467b97STreehugger Robot  def consume_hidden_token( tree )
442*16467b97STreehugger Robot    # do nothing
443*16467b97STreehugger Robot  end
444*16467b97STreehugger Robot
445*16467b97STreehugger Robot  # Somebody (anybody) looked ahead.  Note that this actually gets
446*16467b97STreehugger Robot  # triggered by both peek and look calls.  The debugger will want to know
447*16467b97STreehugger Robot  # which Token object was examined.  Like consumeToken, this indicates
448*16467b97STreehugger Robot  # what token was seen at that depth.  A remote debugger cannot look
449*16467b97STreehugger Robot  # ahead into a file it doesn't have so look events must pass the token
450*16467b97STreehugger Robot  # even if the info is redundant.
451*16467b97STreehugger Robot
452*16467b97STreehugger Robot  def look( i, tree )
453*16467b97STreehugger Robot    # do nothing
454*16467b97STreehugger Robot  end
455*16467b97STreehugger Robot
456*16467b97STreehugger Robot  # The parser is going to look arbitrarily ahead; mark this location,
457*16467b97STreehugger Robot  # the token stream's marker is sent in case you need it.
458*16467b97STreehugger Robot
459*16467b97STreehugger Robot  def mark( marker )
460*16467b97STreehugger Robot    # do nothing
461*16467b97STreehugger Robot  end
462*16467b97STreehugger Robot
463*16467b97STreehugger Robot  # After an arbitrairly long look as with a cyclic DFA (or with
464*16467b97STreehugger Robot  # any backtrack), this informs the debugger that stream should be
465*16467b97STreehugger Robot  # rewound to the position associated with marker.
466*16467b97STreehugger Robot
467*16467b97STreehugger Robot  def rewind( marker = nil )
468*16467b97STreehugger Robot    # do nothing
469*16467b97STreehugger Robot  end
470*16467b97STreehugger Robot
471*16467b97STreehugger Robot  def begin_backtrack( level )
472*16467b97STreehugger Robot    # do nothing
473*16467b97STreehugger Robot  end
474*16467b97STreehugger Robot
475*16467b97STreehugger Robot  def end_backtrack( level, successful )
476*16467b97STreehugger Robot    # do nothing
477*16467b97STreehugger Robot  end
478*16467b97STreehugger Robot
479*16467b97STreehugger Robot  def backtrack( level )
480*16467b97STreehugger Robot    begin_backtrack( level )
481*16467b97STreehugger Robot    successful = yield( self )
482*16467b97STreehugger Robot    end_backtrack( level, successful )
483*16467b97STreehugger Robot  end
484*16467b97STreehugger Robot
485*16467b97STreehugger Robot  # To watch a parser move through the grammar, the parser needs to
486*16467b97STreehugger Robot  # inform the debugger what line/charPos it is passing in the grammar.
487*16467b97STreehugger Robot  # For now, this does not know how to switch from one grammar to the
488*16467b97STreehugger Robot  # other and back for island grammars etc...
489*16467b97STreehugger Robot  # This should also allow breakpoints because the debugger can stop
490*16467b97STreehugger Robot  # the parser whenever it hits this line/pos.
491*16467b97STreehugger Robot
492*16467b97STreehugger Robot  def location( line, position )
493*16467b97STreehugger Robot    # do nothing
494*16467b97STreehugger Robot  end
495*16467b97STreehugger Robot
496*16467b97STreehugger Robot  # A recognition exception occurred such as NoViableAltError.  I made
497*16467b97STreehugger Robot  # this a generic event so that I can alter the exception hierachy later
498*16467b97STreehugger Robot  # without having to alter all the debug objects.
499*16467b97STreehugger Robot  # Upon error, the stack of enter rule/subrule must be properly unwound.
500*16467b97STreehugger Robot  # If no viable alt occurs it is within an enter/exit decision, which
501*16467b97STreehugger Robot  # also must be rewound.  Even the rewind for each mark must be unwount.
502*16467b97STreehugger Robot  # In the Java target this is pretty easy using try/finally, if a bit
503*16467b97STreehugger Robot  # ugly in the generated code.  The rewind is generated in DFA.predict()
504*16467b97STreehugger Robot  # actually so no code needs to be generated for that.  For languages
505*16467b97STreehugger Robot  # w/o this "finally" feature (C++?), the target implementor will have
506*16467b97STreehugger Robot  # to build an event stack or something.
507*16467b97STreehugger Robot  # Across a socket for remote debugging, only the RecognitionError
508*16467b97STreehugger Robot  # data fields are transmitted.  The token object or whatever that
509*16467b97STreehugger Robot  # caused the problem was the last object referenced by look.  The
510*16467b97STreehugger Robot  # immediately preceding look event should hold the unexpected Token or
511*16467b97STreehugger Robot  # char.
512*16467b97STreehugger Robot  # Here is a sample event trace for grammar:
513*16467b97STreehugger Robot  # b : C ({;}A|B) // {;} is there to prevent A|B becoming a set
514*16467b97STreehugger Robot  # | D
515*16467b97STreehugger Robot  # ;
516*16467b97STreehugger Robot  # The sequence for this rule (with no viable alt in the subrule) for
517*16467b97STreehugger Robot  # input 'c c' (there are 3 tokens) is:
518*16467b97STreehugger Robot  # commence
519*16467b97STreehugger Robot  # look
520*16467b97STreehugger Robot  # enterRule b
521*16467b97STreehugger Robot  # location 7 1
522*16467b97STreehugger Robot  # enter decision 3
523*16467b97STreehugger Robot  # look
524*16467b97STreehugger Robot  # exit decision 3
525*16467b97STreehugger Robot  # enterAlt1
526*16467b97STreehugger Robot  # location 7 5
527*16467b97STreehugger Robot  # look
528*16467b97STreehugger Robot  # consumeToken [c/<4>,1:0]
529*16467b97STreehugger Robot  # location 7 7
530*16467b97STreehugger Robot  # enterSubRule 2
531*16467b97STreehugger Robot  # enter decision 2
532*16467b97STreehugger Robot  # look
533*16467b97STreehugger Robot  # look
534*16467b97STreehugger Robot  # recognitionError NoViableAltError 2 1 2
535*16467b97STreehugger Robot  # exit decision 2
536*16467b97STreehugger Robot  # exitSubRule 2
537*16467b97STreehugger Robot  # beginResync
538*16467b97STreehugger Robot  # look
539*16467b97STreehugger Robot  # consumeToken [c/<4>,1:1]
540*16467b97STreehugger Robot  # look
541*16467b97STreehugger Robot  # endResync
542*16467b97STreehugger Robot  # look(-1)
543*16467b97STreehugger Robot  # exitRule b
544*16467b97STreehugger Robot  # terminate
545*16467b97STreehugger Robot
546*16467b97STreehugger Robot  def recognition_exception( exception )
547*16467b97STreehugger Robot    # do nothing
548*16467b97STreehugger Robot  end
549*16467b97STreehugger Robot
550*16467b97STreehugger Robot  # Indicates the recognizer is about to consume tokens to resynchronize
551*16467b97STreehugger Robot  # the parser.  Any consume events from here until the recovered event
552*16467b97STreehugger Robot  # are not part of the parse--they are dead tokens.
553*16467b97STreehugger Robot
554*16467b97STreehugger Robot  def begin_resync()
555*16467b97STreehugger Robot    # do nothing
556*16467b97STreehugger Robot  end
557*16467b97STreehugger Robot
558*16467b97STreehugger Robot  # Indicates that the recognizer has finished consuming tokens in order
559*16467b97STreehugger Robot  # to resychronize.  There may be multiple beginResync/endResync pairs
560*16467b97STreehugger Robot  # before the recognizer comes out of errorRecovery mode (in which
561*16467b97STreehugger Robot  # multiple errors are suppressed).  This will be useful
562*16467b97STreehugger Robot  # in a gui where you want to probably grey out tokens that are consumed
563*16467b97STreehugger Robot  # but not matched to anything in grammar.  Anything between
564*16467b97STreehugger Robot  # a beginResync/endResync pair was tossed out by the parser.
565*16467b97STreehugger Robot
566*16467b97STreehugger Robot  def end_resync()
567*16467b97STreehugger Robot    # do nothing
568*16467b97STreehugger Robot  end
569*16467b97STreehugger Robot
570*16467b97STreehugger Robot  def resync
571*16467b97STreehugger Robot    begin_resync
572*16467b97STreehugger Robot    yield( self )
573*16467b97STreehugger Robot    end_resync
574*16467b97STreehugger Robot  end
575*16467b97STreehugger Robot
576*16467b97STreehugger Robot  # A semantic predicate was evaluate with this result and action text
577*16467b97STreehugger Robot
578*16467b97STreehugger Robot  def semantic_predicate( result, predicate )
579*16467b97STreehugger Robot    # do nothing
580*16467b97STreehugger Robot  end
581*16467b97STreehugger Robot
582*16467b97STreehugger Robot  # Announce that parsing has begun.  Not technically useful except for
583*16467b97STreehugger Robot  # sending events over a socket.  A GUI for example will launch a thread
584*16467b97STreehugger Robot  # to connect and communicate with a remote parser.  The thread will want
585*16467b97STreehugger Robot  # to notify the GUI when a connection is made.  ANTLR parsers
586*16467b97STreehugger Robot  # trigger this upon entry to the first rule (the ruleLevel is used to
587*16467b97STreehugger Robot  # figure this out).
588*16467b97STreehugger Robot
589*16467b97STreehugger Robot  def commence(  )
590*16467b97STreehugger Robot    # do nothing
591*16467b97STreehugger Robot  end
592*16467b97STreehugger Robot
593*16467b97STreehugger Robot  # Parsing is over; successfully or not.  Mostly useful for telling
594*16467b97STreehugger Robot  # remote debugging listeners that it's time to quit.  When the rule
595*16467b97STreehugger Robot  # invocation level goes to zero at the end of a rule, we are done
596*16467b97STreehugger Robot  # parsing.
597*16467b97STreehugger Robot
598*16467b97STreehugger Robot  def terminate(  )
599*16467b97STreehugger Robot    # do nothing
600*16467b97STreehugger Robot  end
601*16467b97STreehugger Robot
602*16467b97STreehugger Robot  # Input for a tree parser is an AST, but we know nothing for sure
603*16467b97STreehugger Robot  # about a node except its type and text (obtained from the adaptor).
604*16467b97STreehugger Robot  # This is the analog of the consumeToken method.  Again, the ID is
605*16467b97STreehugger Robot  # the hashCode usually of the node so it only works if hashCode is
606*16467b97STreehugger Robot  # not implemented.  If the type is UP or DOWN, then
607*16467b97STreehugger Robot  # the ID is not really meaningful as it's fixed--there is
608*16467b97STreehugger Robot  # just one UP node and one DOWN navigation node.
609*16467b97STreehugger Robot
610*16467b97STreehugger Robot  def consume_node( tree )
611*16467b97STreehugger Robot    # do nothing
612*16467b97STreehugger Robot  end
613*16467b97STreehugger Robot
614*16467b97STreehugger Robot  # A nil was created (even nil nodes have a unique ID...
615*16467b97STreehugger Robot  # they are not "null" per se).  As of 4/28/2006, this
616*16467b97STreehugger Robot  # seems to be uniquely triggered when starting a new subtree
617*16467b97STreehugger Robot  # such as when entering a subrule in automatic mode and when
618*16467b97STreehugger Robot  # building a tree in rewrite mode.
619*16467b97STreehugger Robot  # If you are receiving this event over a socket via
620*16467b97STreehugger Robot  # RemoteDebugEventSocketListener then only tree.ID is set.
621*16467b97STreehugger Robot
622*16467b97STreehugger Robot  def flat_node( tree )
623*16467b97STreehugger Robot    # do nothing
624*16467b97STreehugger Robot  end
625*16467b97STreehugger Robot
626*16467b97STreehugger Robot  # Upon syntax error, recognizers bracket the error with an error node
627*16467b97STreehugger Robot  # if they are building ASTs.
628*16467b97STreehugger Robot
629*16467b97STreehugger Robot  def error_node( tree )
630*16467b97STreehugger Robot    # do nothing
631*16467b97STreehugger Robot  end
632*16467b97STreehugger Robot
633*16467b97STreehugger Robot  # Announce a new node built from token elements such as type etc...
634*16467b97STreehugger Robot  # If you are receiving this event over a socket via
635*16467b97STreehugger Robot  # RemoteDebugEventSocketListener then only tree.ID, type, text are
636*16467b97STreehugger Robot  # set.
637*16467b97STreehugger Robot
638*16467b97STreehugger Robot  def create_node( node, token = nil )
639*16467b97STreehugger Robot    # do nothing
640*16467b97STreehugger Robot  end
641*16467b97STreehugger Robot
642*16467b97STreehugger Robot  # Make a node the new root of an existing root.
643*16467b97STreehugger Robot  # Note: the newRootID parameter is possibly different
644*16467b97STreehugger Robot  # than the TreeAdaptor.becomeRoot() newRoot parameter.
645*16467b97STreehugger Robot  # In our case, it will always be the result of calling
646*16467b97STreehugger Robot  # TreeAdaptor.becomeRoot() and not root_n or whatever.
647*16467b97STreehugger Robot  # The listener should assume that this event occurs
648*16467b97STreehugger Robot  # only when the current subrule (or rule) subtree is
649*16467b97STreehugger Robot  # being reset to newRootID.
650*16467b97STreehugger Robot  # If you are receiving this event over a socket via
651*16467b97STreehugger Robot  # RemoteDebugEventSocketListener then only IDs are set.
652*16467b97STreehugger Robot  # @see antlr3.tree.TreeAdaptor.becomeRoot()
653*16467b97STreehugger Robot
654*16467b97STreehugger Robot  def become_root( new_root, old_root )
655*16467b97STreehugger Robot    # do nothing
656*16467b97STreehugger Robot  end
657*16467b97STreehugger Robot
658*16467b97STreehugger Robot  # Make childID a child of rootID.
659*16467b97STreehugger Robot  # If you are receiving this event over a socket via
660*16467b97STreehugger Robot  # RemoteDebugEventSocketListener then only IDs are set.
661*16467b97STreehugger Robot  # @see antlr3.tree.TreeAdaptor.addChild()
662*16467b97STreehugger Robot
663*16467b97STreehugger Robot  def add_child( root, child )
664*16467b97STreehugger Robot    # do nothing
665*16467b97STreehugger Robot  end
666*16467b97STreehugger Robot
667*16467b97STreehugger Robot  # Set the token start/stop token index for a subtree root or node.
668*16467b97STreehugger Robot  # If you are receiving this event over a socket via
669*16467b97STreehugger Robot  # RemoteDebugEventSocketListener then only tree.ID is set.
670*16467b97STreehugger Robot
671*16467b97STreehugger Robot  def set_token_boundaries( tree, token_start_index, token_stop_index )
672*16467b97STreehugger Robot    # do nothing
673*16467b97STreehugger Robot  end
674*16467b97STreehugger Robot
675*16467b97STreehugger Robot  def examine_rule_memoization( rule )
676*16467b97STreehugger Robot    # do nothing
677*16467b97STreehugger Robot  end
678*16467b97STreehugger Robot
679*16467b97STreehugger Robot  def on( event_name, &block )
680*16467b97STreehugger Robot    sclass = class << self; self; end
681*16467b97STreehugger Robot    sclass.send( :define_method, event_name, &block )
682*16467b97STreehugger Robot  end
683*16467b97STreehugger Robot
684*16467b97STreehugger Robot  EVENTS = [
685*16467b97STreehugger Robot    :add_child, :backtrack, :become_root, :begin_backtrack,
686*16467b97STreehugger Robot    :begin_resync, :commence, :consume_hidden_token,
687*16467b97STreehugger Robot    :consume_node, :consume_token, :create_node, :end_backtrack,
688*16467b97STreehugger Robot    :end_resync, :enter_alternative, :enter_decision, :enter_rule,
689*16467b97STreehugger Robot    :enter_sub_rule, :error_node, :exit_decision, :exit_rule,
690*16467b97STreehugger Robot    :exit_sub_rule, :flat_node, :location, :look, :mark,
691*16467b97STreehugger Robot    :recognition_exception, :resync, :rewind,
692*16467b97STreehugger Robot    :semantic_predicate, :set_token_boundaries, :terminate
693*16467b97STreehugger Robot  ].freeze
694*16467b97STreehugger Robot
695*16467b97STreehugger Robotend
696*16467b97STreehugger Robotend
697*16467b97STreehugger Robotend
698