1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver#!/usr/bin/ruby
2324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver# encoding: utf-8
3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin LICENSE
5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver[The "BSD licence"]
7324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverCopyright (c) 2009-2010 Kyle Yetter
8324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverAll rights reserved.
9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
10324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverRedistribution and use in source and binary forms, with or without
11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodification, are permitted provided that the following conditions
12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverare met:
13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1. Redistributions of source code must retain the above copyright
15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    notice, this list of conditions and the following disclaimer.
16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 2. Redistributions in binary form must reproduce the above copyright
17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    notice, this list of conditions and the following disclaimer in the
18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    documentation and/or other materials provided with the distribution.
19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 3. The name of the author may not be used to endorse or promote products
20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    derived from this software without specific prior written permission.
21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
22324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule ANTLR3
36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin rdoc ANTLR3::TokenRewriteStream
38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
39324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverTokenRewriteStream is a specialized form of CommonTokenStream that provides simple stream editing functionality. By creating <i>rewrite programs</i>, new text output can be created based upon the tokens in the stream. The basic token stream itself is preserved, and text output is rendered on demand using the #to_s method.
40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass TokenRewriteStream < CommonTokenStream
44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  unless defined?( RewriteOperation )
46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    RewriteOperation = Struct.new( :stream, :location, :text )
47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin rdoc ANTLR3::TokenRewriteStream::RewriteOperation
50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
51324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverRewiteOperation objects represent some particular editing command that should
52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverbe executed by a token rewrite stream at some time in future when the stream is
53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverrendering a rewritten stream.
54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
55324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverTo perform token stream rewrites safely and efficiently, the rewrites are
56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverexecuted lazily (that is, only when the rewritten text is explicitly requested).
57324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverRewrite streams implement lazy rewriting by storing the parameters of
58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruveredit-inducing methods like +delete+ and +insert+ as RewriteOperation objects in
59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvera rewrite program list.
60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
61324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverThe three subclasses of RewriteOperation, InsertBefore, Delete, and Replace,
62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverdefine specific implementations of stream edits.
63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  class RewriteOperation
67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    extend ClassMacros
68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @operation_name = ''
69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    class << self
71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ##
72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      # the printable name of operations represented by the class -- used for inspection
73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      attr_reader :operation_name
74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    ##
77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # :method: execute( buffer )
78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # run the rewrite operation represented by this object and append the output to +buffer+
79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    abstract :execute
80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    ##
82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # return the name of this operation as set by its class
83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def name
84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      self.class.operation_name
85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    ##
88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # return a compact, readable representation of this operation
89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def inspect
90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return "(%s @ %p : %p)" % [ name, location, text ]
91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin rdoc ANTLR3::TokenRewriteStream::InsertBefore
96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
97324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverRepresents rewrite operation:
98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruveradd string <tt>op.text</tt> to the rewrite output immediately before adding the
100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvertext content of the token at index <tt>op.index</tt>
101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  class InsertBefore < RewriteOperation
105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @operation_name = 'insert-before'.freeze
106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    alias index  location
108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    alias index= location=
109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def execute( buffer )
111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      buffer << text.to_s
112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      token = stream[ location ]
113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      buffer << token.text.to_s if token
114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return location + 1
115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin rdoc ANTLR3::TokenRewriteStream::Replace
119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
120324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverRepresents rewrite operation:
121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruveradd text <tt>op.text</tt> to the rewrite buffer in lieu of the text of tokens
123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverindexed within the range <tt>op.index .. op.last_index</tt>
124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  class Replace < RewriteOperation
128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @operation_name = 'replace'.freeze
130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def initialize( stream, location, text )
132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      super( stream, nil, text )
133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      self.location = location
134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def location=( val )
137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      case val
138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      when Range then super( val )
139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      else
140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        val = val.to_i
141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        super( val..val )
142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def execute( buffer )
146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      buffer << text.to_s unless text.nil?
147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return( location.end + 1 )
148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def index
151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      location.first
152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin rdoc ANTLR3::TokenRewriteStream::Delete
157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
158324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverRepresents rewrite operation:
159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverskip over the tokens indexed within the range <tt>op.index .. op.last_index</tt>
161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverand do not add any text to the rewrite buffer
162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  class Delete < Replace
166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @operation_name = 'delete'.freeze
167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def initialize( stream, location )
169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      super( stream, location, nil )
170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  class RewriteProgram
174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def initialize( stream, name = nil )
175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @stream = stream
176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @name = name
177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @operations = []
178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def replace( *range_arguments )
181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      range, text = cast_range( range_arguments, 1 )
182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      op = Replace.new( @stream, range, text )
184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @operations << op
185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return op
186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def insert_before( index, text )
189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      index = index.to_i
190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      index < 0 and index += @stream.length
191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      op = InsertBefore.new( @stream, index, text )
192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @operations << op
193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return op
194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def insert_after( index, text )
197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      index = index.to_i
198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      index < 0 and index += @stream.length
199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      op = InsertBefore.new( @stream, index + 1, text )
200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @operations << op
201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return op
202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def delete( *range_arguments )
205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      range, = cast_range( range_arguments )
206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      op = Delete.new( @stream, range )
207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @operations << op
208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return op
209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def reduce
212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      operations = @operations.reverse
213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      reduced = []
214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      until operations.empty?
216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        operation = operations.shift
217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        location = operation.location
218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        
219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        case operation
220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        when Replace
221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          operations.delete_if do |prior_operation|
222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            prior_location = prior_operation.location
223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            
224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            case prior_operation
225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            when InsertBefore
226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver              location.include?( prior_location )
227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            when Replace
228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver              if location.covers?( prior_location )
229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                true
230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver              elsif location.overlaps?( prior_location )
231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                conflict!( operation, prior_operation )
232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver              end
233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            end
234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          end
235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        when InsertBefore
236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          operations.delete_if do |prior_operation|
237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            prior_location = prior_operation.location
238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            
239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            case prior_operation
240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            when InsertBefore
241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver              if prior_location == location
242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                operation.text += prior_operation.text
243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                true
244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver              end
245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            when Replace
246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver              if location == prior_location.first
247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                prior_operation.text = operation.text << prior_operation.text.to_s
248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                operation = nil
249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                break( false )
250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver              elsif prior_location.include?( location )
251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                conflict!( operation, prior_operation )
252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver              end
253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            end
254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          end
255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        end
256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        
257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        reduced.unshift( operation ) if operation
258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @operations.replace( reduced )
261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @operations.inject( {} ) do |map, operation|
263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        other_operaiton = map[ operation.index ] and
264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          ANTLR3.bug!( Util.tidy( <<-END ) % [ self.class, operation, other_operaiton ] )
265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          | %s#reduce! should have left only one operation per index,
266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          | but %p conflicts with %p
267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          END
268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        map[ operation.index ] = operation
269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        map
270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def execute( *range_arguments )
274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      if range_arguments.empty?
275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        range = 0 ... @stream.length
276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      else
277324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        range, = cast_range( range_arguments )
278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      output = ''
281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      tokens = @stream.tokens
283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      operations = reduce
285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      cursor = range.first
287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      while range.include?( cursor )
288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if operation = operations.delete( cursor )
289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          cursor = operation.execute( output )
290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        else
291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          token = tokens[ cursor ]
292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          output << token.text if token
293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          cursor += 1
294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        end
295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      if operation = operations.delete( cursor ) and
297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         operation.is_a?( InsertBefore )
298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        # catch edge 'insert-after' operations
299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        operation.execute( output )
300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return output
303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def clear
306324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @operations.clear
307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def undo( number_of_operations = 1 )
310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @operations.pop( number_of_operations )
311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def conflict!( current, previous )
314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      message = 'operation %p overlaps with previous operation %p' % [ current, previous ]
315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      raise( RangeError, message, caller )
316324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def cast_range( args, extra = 0 )
319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      single, pair = extra + 1, extra + 2
320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      case check_arguments( args, single, pair )
321324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      when single
322324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        loc = args.shift
323324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        
324324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if loc.is_a?( Range )
325324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          first, last = loc.first.to_i, loc.last.to_i
326324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          loc.exclude_end? and last -= 1
327324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          return cast_range( args.unshift( first, last ), extra )
328324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        else
329324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          loc = loc.to_i
330324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          return cast_range( args.unshift( loc, loc ), extra )
331324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        end
332324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      when pair
333324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        first, last = args.shift( 2 ).map! { |arg| arg.to_i }
334324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if first < 0 and last < 0
335324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          first += @stream.length
336324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          last += @stream.length
337324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        else
338324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          last < 0 and last += @stream.length
339324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          first = first.at_least( 0 )
340324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        end
341324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return( args.unshift( first .. last ) )
342324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
343324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
344324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
345324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def check_arguments( args, min, max )
346324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      n = args.length
347324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      if n < min
348324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        raise ArgumentError,
349324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          "wrong number of arguments (#{ args.length } for #{ min })",
350324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          caller
351324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      elsif n > max
352324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        raise ArgumentError,
353324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          "wrong number of arguments (#{ args.length } for #{ max })",
354324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          caller
355324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      else return n
356324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
357324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
358324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
359324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    private :conflict!, :cast_range, :check_arguments
360324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
361324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
362324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  attr_reader :programs
363324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
364324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def initialize( token_source, options = {} )
365324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    super( token_source, options )
366324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
367324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @programs = Hash.new do |programs, name|
368324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      if name.is_a?( String )
369324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        programs[ name ] = RewriteProgram.new( self, name )
370324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      else programs[ name.to_s ]
371324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
372324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
373324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
374324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @last_rewrite_token_indexes = {}
375324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
376324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
377324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def rewrite( program_name = 'default', range = nil )
378324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    program = @programs[ program_name ]
379324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    if block_given?
380324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      yield( program )
381324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      program.execute( range )
382324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    else program
383324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
384324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
385324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
386324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def program( name = 'default' )
387324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return @programs[ name ]
388324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
389324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
390324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def delete_program( name = 'default' )
391324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @programs.delete( name )
392324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
393324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
394324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def original_string( start = 0, finish = size - 1 )
395324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @position == -1 and fill_buffer
396324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
397324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return( self[ start..finish ].map { |t| t.text }.join( '' ) )
398324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
399324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
400324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def insert_before( *args )
401324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @programs[ 'default' ].insert_before( *args )
402324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
403324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
404324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def insert_after( *args )
405324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @programs[ 'default' ].insert_after( *args )
406324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
407324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
408324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def replace( *args )
409324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @programs[ 'default' ].replace( *args )
410324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
411324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
412324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def delete( *args )
413324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @programs[ 'default' ].delete( *args )
414324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
415324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
416324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def render( *arguments )
417324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    case arguments.first
418324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    when String, Symbol then name = arguments.shift.to_s
419324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    else name = 'default'
420324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
421324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @programs[ name ].execute( *arguments )
422324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
423324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend
424324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend
425