antlr3 1.8.0 → 1.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. data/History.txt +35 -0
  2. data/Manifest.txt +73 -0
  3. data/README.txt +6 -13
  4. data/java/RubyTarget.java +43 -19
  5. data/java/antlr-full-3.2.1.jar +0 -0
  6. data/lib/antlr3/debug.rb +2 -0
  7. data/lib/antlr3/debug/event-hub.rb +55 -55
  8. data/lib/antlr3/debug/record-event-listener.rb +2 -2
  9. data/lib/antlr3/debug/rule-tracer.rb +14 -14
  10. data/lib/antlr3/debug/socket.rb +47 -47
  11. data/lib/antlr3/debug/trace-event-listener.rb +8 -8
  12. data/lib/antlr3/main.rb +29 -9
  13. data/lib/antlr3/modes/ast-builder.rb +7 -7
  14. data/lib/antlr3/modes/filter.rb +19 -17
  15. data/lib/antlr3/profile.rb +34 -6
  16. data/lib/antlr3/recognizers.rb +50 -1
  17. data/lib/antlr3/streams.rb +19 -15
  18. data/lib/antlr3/streams/rewrite.rb +241 -229
  19. data/lib/antlr3/template/group-file-lexer.rb +6 -8
  20. data/lib/antlr3/template/group-file-parser.rb +16 -16
  21. data/lib/antlr3/template/group-file.rb +1 -1
  22. data/lib/antlr3/test/call-stack.rb +13 -13
  23. data/lib/antlr3/test/core-extensions.rb +69 -69
  24. data/lib/antlr3/test/functional.rb +0 -4
  25. data/lib/antlr3/test/grammar.rb +70 -70
  26. data/lib/antlr3/token.rb +41 -17
  27. data/lib/antlr3/tree.rb +11 -14
  28. data/lib/antlr3/tree/debug.rb +53 -53
  29. data/lib/antlr3/tree/visitor.rb +11 -11
  30. data/lib/antlr3/tree/wizard.rb +35 -35
  31. data/lib/antlr3/util.rb +18 -0
  32. data/lib/antlr3/version.rb +1 -1
  33. data/rakefile +1 -0
  34. data/samples/ANTLRv3Grammar.g +3 -3
  35. data/samples/JavaScript.g +702 -0
  36. data/samples/standard/C/C.g +543 -0
  37. data/samples/standard/C/C.tokens +175 -0
  38. data/samples/standard/C/C__testrig.st +0 -0
  39. data/samples/standard/C/c.rb +12 -0
  40. data/samples/standard/C/input +3479 -0
  41. data/samples/standard/C/output +171 -0
  42. data/samples/standard/LL-star/LLStar.g +101 -0
  43. data/samples/standard/LL-star/input +12 -0
  44. data/samples/standard/LL-star/ll-star.rb +12 -0
  45. data/samples/standard/LL-star/output +2 -0
  46. data/samples/standard/calc/Calculator.g +47 -0
  47. data/samples/standard/calc/Calculator.py +16 -0
  48. data/samples/standard/calc/Calculator.rb +28 -0
  49. data/samples/standard/cminus/CMinus.g +141 -0
  50. data/samples/standard/cminus/bytecode.group +80 -0
  51. data/samples/standard/cminus/cminus.rb +16 -0
  52. data/samples/standard/cminus/input +9 -0
  53. data/samples/standard/cminus/java.group +91 -0
  54. data/samples/standard/cminus/output +11 -0
  55. data/samples/standard/cminus/python.group +48 -0
  56. data/samples/standard/dynamic-scope/DynamicScopes.g +50 -0
  57. data/samples/standard/dynamic-scope/dynamic-scopes.rb +12 -0
  58. data/samples/standard/dynamic-scope/input +7 -0
  59. data/samples/standard/dynamic-scope/output +4 -0
  60. data/samples/standard/fuzzy/FuzzyJava.g +89 -0
  61. data/samples/standard/fuzzy/fuzzy.py +11 -0
  62. data/samples/standard/fuzzy/fuzzy.rb +9 -0
  63. data/samples/standard/fuzzy/input +13 -0
  64. data/samples/standard/fuzzy/output +12 -0
  65. data/samples/standard/hoisted-predicates/HoistedPredicates.g +40 -0
  66. data/samples/standard/hoisted-predicates/hoisted-predicates.rb +13 -0
  67. data/samples/standard/hoisted-predicates/input +1 -0
  68. data/samples/standard/hoisted-predicates/output +1 -0
  69. data/samples/standard/island-grammar/Javadoc.g +46 -0
  70. data/samples/standard/island-grammar/Simple.g +104 -0
  71. data/samples/standard/island-grammar/input +11 -0
  72. data/samples/standard/island-grammar/island.rb +12 -0
  73. data/samples/standard/island-grammar/output +16 -0
  74. data/samples/standard/java/Java.g +827 -0
  75. data/samples/standard/java/input +80 -0
  76. data/samples/standard/java/java.rb +13 -0
  77. data/samples/standard/java/output +1 -0
  78. data/samples/standard/python/Python.g +718 -0
  79. data/samples/standard/python/PythonTokenSource.rb +107 -0
  80. data/samples/standard/python/input +210 -0
  81. data/samples/standard/python/output +24 -0
  82. data/samples/standard/python/python.rb +14 -0
  83. data/samples/standard/rakefile +18 -0
  84. data/samples/standard/scopes/SymbolTable.g +66 -0
  85. data/samples/standard/scopes/input +12 -0
  86. data/samples/standard/scopes/output +3 -0
  87. data/samples/standard/scopes/scopes.rb +12 -0
  88. data/samples/standard/simplecTreeParser/SimpleC.g +113 -0
  89. data/samples/standard/simplecTreeParser/SimpleCWalker.g +64 -0
  90. data/samples/standard/simplecTreeParser/input +12 -0
  91. data/samples/standard/simplecTreeParser/output +1 -0
  92. data/samples/standard/simplecTreeParser/simplec.rb +18 -0
  93. data/samples/standard/treeparser/Lang.g +24 -0
  94. data/samples/standard/treeparser/LangDumpDecl.g +17 -0
  95. data/samples/standard/treeparser/input +1 -0
  96. data/samples/standard/treeparser/output +2 -0
  97. data/samples/standard/treeparser/treeparser.rb +18 -0
  98. data/samples/standard/tweak/Tweak.g +68 -0
  99. data/samples/standard/tweak/input +9 -0
  100. data/samples/standard/tweak/output +16 -0
  101. data/samples/standard/tweak/tweak.rb +13 -0
  102. data/samples/standard/xml/README +16 -0
  103. data/samples/standard/xml/XML.g +123 -0
  104. data/samples/standard/xml/input +21 -0
  105. data/samples/standard/xml/output +39 -0
  106. data/samples/standard/xml/xml.rb +9 -0
  107. data/templates/Ruby.stg +4 -4
  108. data/test/functional/ast-output/auto-ast.rb +0 -5
  109. data/test/functional/ast-output/rewrites.rb +4 -4
  110. data/test/unit/test-scope.rb +45 -0
  111. metadata +96 -8
@@ -1,6 +1,37 @@
1
1
  #!/usr/bin/ruby
2
2
  # encoding: utf-8
3
3
 
4
+ =begin LICENSE
5
+
6
+ [The "BSD licence"]
7
+ Copyright (c) 2009-2010 Kyle Yetter
8
+ All rights reserved.
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions
12
+ are met:
13
+
14
+ 1. Redistributions of source code must retain the above copyright
15
+ notice, this list of conditions and the following disclaimer.
16
+ 2. Redistributions in binary form must reproduce the above copyright
17
+ notice, this list of conditions and the following disclaimer in the
18
+ documentation and/or other materials provided with the distribution.
19
+ 3. The name of the author may not be used to endorse or promote products
20
+ derived from this software without specific prior written permission.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+
33
+ =end
34
+
4
35
  module ANTLR3
5
36
  module Profile
6
37
  =begin rdoc ANTLR3::Profile::ParserEvents
@@ -52,9 +83,6 @@ class DataSet < ::Array
52
83
  end
53
84
 
54
85
 
55
-
56
-
57
-
58
86
  unless const_defined?( :Profile )
59
87
  Profile = Struct.new(
60
88
  :grammar_file, :parser_class, :top_rule,
@@ -231,7 +259,7 @@ class Profiler
231
259
 
232
260
  def enter_decision( decision_number )
233
261
  @decision_level += 1
234
- starting_look_index = @parser.token_stream.index
262
+ starting_look_index = @parser.input.index
235
263
  @look_stack << starting_look_index
236
264
  end
237
265
 
@@ -262,7 +290,7 @@ class Profiler
262
290
  def look( i, token )
263
291
  in_decision? or return
264
292
  starting_index = look_stack.last
265
- input = @parser.token_stream
293
+ input = @parser.input
266
294
  this_ref_index = input.index
267
295
  num_hidden = input.tokens( starting_index, this_ref_index ).count { |t| t.hidden? }
268
296
  depth = i + this_ref_index - starting_index - num_hidden
@@ -284,7 +312,7 @@ class Profiler
284
312
  end
285
313
 
286
314
  def terminate
287
- input = @parser.token_stream
315
+ input = @parser.input
288
316
  hidden_tokens = input.select { |token| token.hidden? }
289
317
  @profile.hidden_tokens = hidden_tokens.length
290
318
  @profile.tokens = input.tokens.length
@@ -124,6 +124,52 @@ end
124
124
 
125
125
  end # unless const_defined?( :RecognizerSharedState )
126
126
 
127
+ =begin rdoc ANTLR3::Recognizer
128
+
129
+ = Scope
130
+
131
+ Scope is used to represent instances of ANTLR's various attribute scopes.
132
+ It is identical to Ruby's built-in Struct class, but it takes string
133
+ attribute declarations from the ANTLR grammar as parameters, and overrides
134
+ the #initialize method to set the default values if any are present in
135
+ the scope declaration.
136
+
137
+ Block = Scope.new( "name", "depth = 0", "variables = {}" )
138
+ Block.new # => #<struct Block name=nil, depth=0, variables={}>
139
+ Block.new( "function" ) # => #<struct Block name="function", depth=0, variables={}>
140
+ Block.new( 'a', 1, :x => 3 ) # => #<struct Block name="a", depth=1, variables={ :x => 3 }>
141
+
142
+ =end
143
+
144
+ class Scope < ::Struct
145
+ def self.new( *declarations, &body )
146
+ names = []
147
+ defaults = {}
148
+ for decl in declarations
149
+ name, default = decl.to_s.split( /\s*=\s*/, 2 )
150
+ names << ( name = name.to_sym )
151
+ default and defaults[ name ] = default
152
+ end
153
+ super( *names ) do
154
+
155
+ # If no defaults, leave the initialize method the same as
156
+ # the struct's default initialize for speed. Otherwise,
157
+ # overwrite the initialize to populate with default values.
158
+ unless defaults.empty?
159
+ parameters = names.map do | name |
160
+ "#{ name } = " << defaults.fetch( name, 'nil' )
161
+ end.join( ', ' )
162
+ class_eval( <<-END )
163
+ def initialize( #{ parameters } )
164
+ super( #{ names.join( ', ' ) } )
165
+ end
166
+ END
167
+ end
168
+
169
+ body and class_eval( &body )
170
+ end
171
+ end
172
+ end
127
173
 
128
174
  =begin rdoc ANTLR3::Recognizer
129
175
 
@@ -158,7 +204,6 @@ class Recognizer
158
204
 
159
205
  # inherited class methods and hooks
160
206
  class << self
161
-
162
207
  attr_reader :grammar_file_name,
163
208
  :antlr_version,
164
209
  :antlr_version_string,
@@ -262,6 +307,10 @@ class Recognizer
262
307
  return false
263
308
  end
264
309
 
310
+ def Scope( *declarations, &body )
311
+ Scope.new( *declarations, &body )
312
+ end
313
+
265
314
  def token_class
266
315
  @token_class ||= begin
267
316
  self::Token rescue
@@ -173,46 +173,51 @@ module Stream
173
173
  abstract :consume
174
174
 
175
175
  ##
176
- # :method: peek(k=1)
176
+ # :method: peek( k = 1 )
177
177
  # used to quickly retreive the object of interest to a recognizer at lookahead
178
178
  # position specified by <tt>k</tt> (such as integer value of a character or an
179
179
  # integer token type)
180
180
  abstract :peek
181
181
 
182
182
  ##
183
- # :method: look(k=1)
183
+ # :method: look( k = 1 )
184
184
  # used to retreive the full object of interest at lookahead position specified
185
185
  # by <tt>k</tt> (such as a character string or a token structure)
186
186
  abstract :look
187
187
 
188
188
  ##
189
189
  # :method: mark
190
- # TODO: document
190
+ # saves the current position for the purposes of backtracking and
191
+ # returns a value to pass to #rewind at a later time
191
192
  abstract :mark
192
193
 
193
194
  ##
194
195
  # :method: index
195
- # TODO: document
196
+ # returns the current position of the stream
196
197
  abstract :index
197
198
 
198
199
  ##
199
- # :method: rewind(marker=last_marker)
200
- # TODO: document
200
+ # :method: rewind( marker = last_marker )
201
+ # restores the stream position using the state information previously saved
202
+ # by the given marker
201
203
  abstract :rewind
202
204
 
203
205
  ##
204
- # :method: release(marker = last_marker)
205
- # TODO: document
206
+ # :method: release( marker = last_marker )
207
+ # clears the saved state information associated with the given marker value
206
208
  abstract :release
207
209
 
208
210
  ##
209
- # :method: seek(position)
210
- # TODO: document
211
+ # :method: seek( position )
212
+ # move the stream to the given absolute index given by +position+
211
213
  abstract :seek
212
214
 
213
- # TODO: document
215
+ ##
216
+ # the total number of symbols in the stream
214
217
  attr_reader :size
215
- # TODO: document
218
+
219
+ ##
220
+ # indicates an identifying name for the stream -- usually the file path of the input
216
221
  attr_accessor :source_name
217
222
  end
218
223
 
@@ -252,7 +257,6 @@ module CharacterStream
252
257
  include Stream
253
258
  extend ClassMacros
254
259
  include Constants
255
- #EOF = -1
256
260
 
257
261
  ##
258
262
  # :method: substring(start,stop)
@@ -328,8 +332,8 @@ module TokenStream
328
332
  abstract :to_s
329
333
 
330
334
  ##
331
- # :method: at
332
- # TODO: document
335
+ # :method: at( i )
336
+ # return the stream symbol at index +i+
333
337
  abstract :at
334
338
  end
335
339
 
@@ -42,6 +42,10 @@ TokenRewriteStream is a specialized form of CommonTokenStream that provides simp
42
42
 
43
43
  class TokenRewriteStream < CommonTokenStream
44
44
 
45
+ unless defined?( RewriteOperation )
46
+ RewriteOperation = Struct.new( :stream, :location, :text )
47
+ end
48
+
45
49
  =begin rdoc ANTLR3::TokenRewriteStream::RewriteOperation
46
50
 
47
51
  RewiteOperation objects represent some particular editing command that should
@@ -59,29 +63,34 @@ define specific implementations of stream edits.
59
63
 
60
64
  =end
61
65
 
62
- unless defined?( RewriteOperation )
63
- RewriteOperation = Struct.new( :stream, :location, :text )
64
- end
65
-
66
- class RewriteOperation
67
- extend ClassMacros
68
- @operation_name = ''
69
- class << self
70
- # TODO: document
71
- attr_reader :operation_name
72
- end
73
- abstract :execute
74
-
75
- # TODO: document
76
- def name
77
- self.class.operation_name
66
+ class RewriteOperation
67
+ extend ClassMacros
68
+ @operation_name = ''
69
+
70
+ class << self
71
+ ##
72
+ # the printable name of operations represented by the class -- used for inspection
73
+ attr_reader :operation_name
74
+ end
75
+
76
+ ##
77
+ # :method: execute( buffer )
78
+ # run the rewrite operation represented by this object and append the output to +buffer+
79
+ abstract :execute
80
+
81
+ ##
82
+ # return the name of this operation as set by its class
83
+ def name
84
+ self.class.operation_name
85
+ end
86
+
87
+ ##
88
+ # return a compact, readable representation of this operation
89
+ def inspect
90
+ return "(%s @ %p : %p)" % [ name, location, text ]
91
+ end
78
92
  end
79
93
 
80
- # TODO: document
81
- def inspect
82
- return "(%s @ %p : %p)" % [ name, location, text ]
83
- end
84
- end
85
94
 
86
95
  =begin rdoc ANTLR3::TokenRewriteStream::InsertBefore
87
96
 
@@ -91,21 +100,21 @@ add string <tt>op.text</tt> to the rewrite output immediately before adding the
91
100
  text content of the token at index <tt>op.index</tt>
92
101
 
93
102
  =end
94
-
95
- class InsertBefore < RewriteOperation
96
- @operation_name = 'insert-before'.freeze
97
103
 
98
- alias index location
99
- alias index= location=
100
-
101
- def execute( buffer )
102
- buffer << text.to_s
103
- token = stream[ location ]
104
- buffer << token.text.to_s if token
105
- return location + 1
104
+ class InsertBefore < RewriteOperation
105
+ @operation_name = 'insert-before'.freeze
106
+
107
+ alias index location
108
+ alias index= location=
109
+
110
+ def execute( buffer )
111
+ buffer << text.to_s
112
+ token = stream[ location ]
113
+ buffer << token.text.to_s if token
114
+ return location + 1
115
+ end
106
116
  end
107
- end
108
-
117
+
109
118
  =begin rdoc ANTLR3::TokenRewriteStream::Replace
110
119
 
111
120
  Represents rewrite operation:
@@ -114,34 +123,36 @@ add text <tt>op.text</tt> to the rewrite buffer in lieu of the text of tokens
114
123
  indexed within the range <tt>op.index .. op.last_index</tt>
115
124
 
116
125
  =end
117
-
118
- class Replace < RewriteOperation
119
- @operation_name = 'replace'.freeze
120
- def initialize( stream, location, text )
121
- super( stream, nil, text )
122
- self.location = location
123
- end
124
126
 
125
- def location=( val )
126
- case val
127
- when Range then super( val )
128
- else
129
- val = val.to_i
130
- super( val..val )
127
+ class Replace < RewriteOperation
128
+
129
+ @operation_name = 'replace'.freeze
130
+
131
+ def initialize( stream, location, text )
132
+ super( stream, nil, text )
133
+ self.location = location
131
134
  end
135
+
136
+ def location=( val )
137
+ case val
138
+ when Range then super( val )
139
+ else
140
+ val = val.to_i
141
+ super( val..val )
142
+ end
143
+ end
144
+
145
+ def execute( buffer )
146
+ buffer << text.to_s unless text.nil?
147
+ return( location.end + 1 )
148
+ end
149
+
150
+ def index
151
+ location.first
152
+ end
153
+
132
154
  end
133
155
 
134
- def execute( buffer )
135
- buffer << text.to_s unless text.nil?
136
- return( location.end + 1 )
137
- end
138
-
139
- def index
140
- location.first
141
- end
142
-
143
- end
144
-
145
156
  =begin rdoc ANTLR3::TokenRewriteStream::Delete
146
157
 
147
158
  Represents rewrite operation:
@@ -150,203 +161,204 @@ skip over the tokens indexed within the range <tt>op.index .. op.last_index</tt>
150
161
  and do not add any text to the rewrite buffer
151
162
 
152
163
  =end
153
-
154
- class Delete < Replace
155
- @operation_name = 'delete'.freeze
156
- def initialize( stream, location )
157
- super( stream, location, nil )
158
- end
159
- end
160
-
161
- class RewriteProgram
162
- def initialize( stream, name = nil )
163
- @stream = stream
164
- @name = name
165
- @operations = []
166
- end
167
164
 
168
- def replace( *range_arguments )
169
- range, text = cast_range( range_arguments, 1 )
165
+ class Delete < Replace
166
+ @operation_name = 'delete'.freeze
170
167
 
171
- op = Replace.new( @stream, range, text )
172
- @operations << op
173
- return op
174
- end
175
-
176
- def insert_before( index, text )
177
- index = index.to_i
178
- index < 0 and index += @stream.length
179
- op = InsertBefore.new( @stream, index, text )
180
- @operations << op
181
- return op
182
- end
183
-
184
- def insert_after( index, text )
185
- index = index.to_i
186
- index < 0 and index += @stream.length
187
- op = InsertBefore.new( @stream, index + 1, text )
188
- @operations << op
189
- return op
168
+ def initialize( stream, location )
169
+ super( stream, location, nil )
170
+ end
190
171
  end
191
172
 
192
- def delete( *range_arguments )
193
- range, = cast_range( range_arguments )
194
- op = Delete.new( @stream, range )
195
- @operations << op
196
- return op
197
- end
198
-
199
- def reduce
200
- operations = @operations.reverse
201
- reduced = []
173
+ class RewriteProgram
174
+ def initialize( stream, name = nil )
175
+ @stream = stream
176
+ @name = name
177
+ @operations = []
178
+ end
202
179
 
203
- until operations.empty?
204
- operation = operations.shift
205
- location = operation.location
180
+ def replace( *range_arguments )
181
+ range, text = cast_range( range_arguments, 1 )
206
182
 
207
- case operation
208
- when Replace
209
- operations.delete_if do |prior_operation|
210
- prior_location = prior_operation.location
211
-
212
- case prior_operation
213
- when InsertBefore
214
- location.include?( prior_location )
215
- when Replace
216
- if location.covers?( prior_location )
217
- true
218
- elsif location.overlaps?( prior_location )
219
- conflict!( operation, prior_operation )
183
+ op = Replace.new( @stream, range, text )
184
+ @operations << op
185
+ return op
186
+ end
187
+
188
+ def insert_before( index, text )
189
+ index = index.to_i
190
+ index < 0 and index += @stream.length
191
+ op = InsertBefore.new( @stream, index, text )
192
+ @operations << op
193
+ return op
194
+ end
195
+
196
+ def insert_after( index, text )
197
+ index = index.to_i
198
+ index < 0 and index += @stream.length
199
+ op = InsertBefore.new( @stream, index + 1, text )
200
+ @operations << op
201
+ return op
202
+ end
203
+
204
+ def delete( *range_arguments )
205
+ range, = cast_range( range_arguments )
206
+ op = Delete.new( @stream, range )
207
+ @operations << op
208
+ return op
209
+ end
210
+
211
+ def reduce
212
+ operations = @operations.reverse
213
+ reduced = []
214
+
215
+ until operations.empty?
216
+ operation = operations.shift
217
+ location = operation.location
218
+
219
+ case operation
220
+ when Replace
221
+ operations.delete_if do |prior_operation|
222
+ prior_location = prior_operation.location
223
+
224
+ case prior_operation
225
+ when InsertBefore
226
+ location.include?( prior_location )
227
+ when Replace
228
+ if location.covers?( prior_location )
229
+ true
230
+ elsif location.overlaps?( prior_location )
231
+ conflict!( operation, prior_operation )
232
+ end
220
233
  end
221
234
  end
222
- end
223
- when InsertBefore
224
- operations.delete_if do |prior_operation|
225
- prior_location = prior_operation.location
226
-
227
- case prior_operation
228
- when InsertBefore
229
- if prior_location == location
230
- operation.text += prior_operation.text
231
- true
232
- end
233
- when Replace
234
- if location == prior_location.first
235
- prior_operation.text = operation.text << prior_operation.text.to_s
236
- operation = nil
237
- break( false )
238
- elsif prior_location.include?( location )
239
- conflict!( operation, prior_operation )
235
+ when InsertBefore
236
+ operations.delete_if do |prior_operation|
237
+ prior_location = prior_operation.location
238
+
239
+ case prior_operation
240
+ when InsertBefore
241
+ if prior_location == location
242
+ operation.text += prior_operation.text
243
+ true
244
+ end
245
+ when Replace
246
+ if location == prior_location.first
247
+ prior_operation.text = operation.text << prior_operation.text.to_s
248
+ operation = nil
249
+ break( false )
250
+ elsif prior_location.include?( location )
251
+ conflict!( operation, prior_operation )
252
+ end
240
253
  end
241
254
  end
242
255
  end
256
+
257
+ reduced.unshift( operation ) if operation
243
258
  end
244
259
 
245
- reduced.unshift( operation ) if operation
260
+ @operations.replace( reduced )
261
+
262
+ @operations.inject( {} ) do |map, operation|
263
+ other_operaiton = map[ operation.index ] and
264
+ ANTLR3.bug!( Util.tidy( <<-END ) % [ self.class, operation, other_operaiton ] )
265
+ | %s#reduce! should have left only one operation per index,
266
+ | but %p conflicts with %p
267
+ END
268
+ map[ operation.index ] = operation
269
+ map
270
+ end
246
271
  end
247
272
 
248
- @operations.replace( reduced )
249
-
250
- @operations.inject( {} ) do |map, operation|
251
- other_operaiton = map[ operation.index ] and
252
- ANTLR3.bug!( Util.tidy( <<-END ) % [ self.class, operation, other_operaiton ] )
253
- | %s#reduce! should have left only one operation per index,
254
- | but %p conflicts with %p
255
- END
256
- map[ operation.index ] = operation
257
- map
258
- end
259
- end
260
-
261
- def execute( *range_arguments )
262
- if range_arguments.empty?
263
- range = 0 ... @stream.length
264
- else
265
- range, = cast_range( range_arguments )
273
+ def execute( *range_arguments )
274
+ if range_arguments.empty?
275
+ range = 0 ... @stream.length
276
+ else
277
+ range, = cast_range( range_arguments )
278
+ end
279
+
280
+ output = ''
281
+
282
+ tokens = @stream.tokens
283
+
284
+ operations = reduce
285
+
286
+ cursor = range.first
287
+ while range.include?( cursor )
288
+ if operation = operations.delete( cursor )
289
+ cursor = operation.execute( output )
290
+ else
291
+ token = tokens[ cursor ]
292
+ output << token.text if token
293
+ cursor += 1
294
+ end
295
+ end
296
+ if operation = operations.delete( cursor ) and
297
+ operation.is_a?( InsertBefore )
298
+ # catch edge 'insert-after' operations
299
+ operation.execute( output )
300
+ end
301
+
302
+ return output
266
303
  end
267
304
 
268
- output = ''
305
+ def clear
306
+ @operations.clear
307
+ end
269
308
 
270
- tokens = @stream.tokens
309
+ def undo( number_of_operations = 1 )
310
+ @operations.pop( number_of_operations )
311
+ end
271
312
 
272
- operations = reduce
313
+ def conflict!( current, previous )
314
+ message = 'operation %p overlaps with previous operation %p' % [ current, previous ]
315
+ raise( RangeError, message, caller )
316
+ end
273
317
 
274
- cursor = range.first
275
- while range.include?( cursor )
276
- if operation = operations.delete( cursor )
277
- cursor = operation.execute( output )
278
- else
279
- token = tokens[ cursor ]
280
- output << token.text if token
281
- cursor += 1
318
+ def cast_range( args, extra = 0 )
319
+ single, pair = extra + 1, extra + 2
320
+ case check_arguments( args, single, pair )
321
+ when single
322
+ loc = args.shift
323
+
324
+ if loc.is_a?( Range )
325
+ first, last = loc.first.to_i, loc.last.to_i
326
+ loc.exlude_end? and last -= 1
327
+ return cast_range( args.unshift( first, last ), extra )
328
+ else
329
+ loc = loc.to_i
330
+ return cast_range( args.unshift( loc, loc ), extra )
331
+ end
332
+ when pair
333
+ first, last = args.shift( 2 ).map! { |arg| arg.to_i }
334
+ if first < 0 and last < 0
335
+ first += @stream.length
336
+ last += @stream.length
337
+ else
338
+ last < 0 and last += @stream.length
339
+ first = first.at_least( 0 )
340
+ end
341
+ return( args.unshift( first .. last ) )
282
342
  end
283
343
  end
284
- if operation = operations.delete( cursor ) and
285
- operation.is_a?( InsertBefore )
286
- # catch edge 'insert-after' operations
287
- operation.execute( output )
288
- end
289
344
 
290
- return output
291
- end
292
-
293
- def clear
294
- @operations.clear
295
- end
296
-
297
- def undo( number_of_operations = 1 )
298
- @operations.pop( number_of_operations )
299
- end
300
-
301
- def conflict!( current, previous )
302
- message = 'operation %p overlaps with previous operation %p' % [ current, previous ]
303
- raise( RangeError, message, caller )
304
- end
305
-
306
- def cast_range( args, extra = 0 )
307
- single, pair = extra + 1, extra + 2
308
- case check_arguments( args, single, pair )
309
- when single
310
- loc = args.shift
311
-
312
- if loc.is_a?( Range )
313
- first, last = loc.first.to_i, loc.last.to_i
314
- loc.exlude_end? and last -= 1
315
- return cast_range( args.unshift( first, last ), extra )
316
- else
317
- loc = loc.to_i
318
- return cast_range( args.unshift( loc, loc ), extra )
345
+ def check_arguments( args, min, max )
346
+ n = args.length
347
+ if n < min
348
+ raise ArgumentError,
349
+ "wrong number of arguments (#{ args.length } for #{ min })",
350
+ caller
351
+ elsif n > max
352
+ raise ArgumentError,
353
+ "wrong number of arguments (#{ args.length } for #{ max })",
354
+ caller
355
+ else return n
319
356
  end
320
- when pair
321
- first, last = args.shift( 2 ).map! { |arg| arg.to_i }
322
- if first < 0 and last < 0
323
- first += @stream.length
324
- last += @stream.length
325
- else
326
- last < 0 and last += @stream.length
327
- first = first.at_least( 0 )
328
- end
329
- return( args.unshift( first .. last ) )
330
- end
331
- end
332
-
333
- def check_arguments( args, min, max )
334
- n = args.length
335
- if n < min
336
- raise ArgumentError,
337
- "wrong number of arguments (#{ args.length } for #{ min })",
338
- caller
339
- elsif n > max
340
- raise ArgumentError,
341
- "wrong number of arguments (#{ args.length } for #{ max })",
342
- caller
343
- else return n
344
357
  end
358
+
359
+ private :conflict!, :cast_range, :check_arguments
345
360
  end
346
-
347
- private :conflict!, :cast_range, :check_arguments
348
- end
349
-
361
+
350
362
  attr_reader :programs
351
363
 
352
364
  def initialize( token_source, options = {} )