antlr3 1.8.0 → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 = {} )