antlr3 1.8.0 → 1.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +35 -0
- data/Manifest.txt +73 -0
- data/README.txt +6 -13
- data/java/RubyTarget.java +43 -19
- data/java/antlr-full-3.2.1.jar +0 -0
- data/lib/antlr3/debug.rb +2 -0
- data/lib/antlr3/debug/event-hub.rb +55 -55
- data/lib/antlr3/debug/record-event-listener.rb +2 -2
- data/lib/antlr3/debug/rule-tracer.rb +14 -14
- data/lib/antlr3/debug/socket.rb +47 -47
- data/lib/antlr3/debug/trace-event-listener.rb +8 -8
- data/lib/antlr3/main.rb +29 -9
- data/lib/antlr3/modes/ast-builder.rb +7 -7
- data/lib/antlr3/modes/filter.rb +19 -17
- data/lib/antlr3/profile.rb +34 -6
- data/lib/antlr3/recognizers.rb +50 -1
- data/lib/antlr3/streams.rb +19 -15
- data/lib/antlr3/streams/rewrite.rb +241 -229
- data/lib/antlr3/template/group-file-lexer.rb +6 -8
- data/lib/antlr3/template/group-file-parser.rb +16 -16
- data/lib/antlr3/template/group-file.rb +1 -1
- data/lib/antlr3/test/call-stack.rb +13 -13
- data/lib/antlr3/test/core-extensions.rb +69 -69
- data/lib/antlr3/test/functional.rb +0 -4
- data/lib/antlr3/test/grammar.rb +70 -70
- data/lib/antlr3/token.rb +41 -17
- data/lib/antlr3/tree.rb +11 -14
- data/lib/antlr3/tree/debug.rb +53 -53
- data/lib/antlr3/tree/visitor.rb +11 -11
- data/lib/antlr3/tree/wizard.rb +35 -35
- data/lib/antlr3/util.rb +18 -0
- data/lib/antlr3/version.rb +1 -1
- data/rakefile +1 -0
- data/samples/ANTLRv3Grammar.g +3 -3
- data/samples/JavaScript.g +702 -0
- data/samples/standard/C/C.g +543 -0
- data/samples/standard/C/C.tokens +175 -0
- data/samples/standard/C/C__testrig.st +0 -0
- data/samples/standard/C/c.rb +12 -0
- data/samples/standard/C/input +3479 -0
- data/samples/standard/C/output +171 -0
- data/samples/standard/LL-star/LLStar.g +101 -0
- data/samples/standard/LL-star/input +12 -0
- data/samples/standard/LL-star/ll-star.rb +12 -0
- data/samples/standard/LL-star/output +2 -0
- data/samples/standard/calc/Calculator.g +47 -0
- data/samples/standard/calc/Calculator.py +16 -0
- data/samples/standard/calc/Calculator.rb +28 -0
- data/samples/standard/cminus/CMinus.g +141 -0
- data/samples/standard/cminus/bytecode.group +80 -0
- data/samples/standard/cminus/cminus.rb +16 -0
- data/samples/standard/cminus/input +9 -0
- data/samples/standard/cminus/java.group +91 -0
- data/samples/standard/cminus/output +11 -0
- data/samples/standard/cminus/python.group +48 -0
- data/samples/standard/dynamic-scope/DynamicScopes.g +50 -0
- data/samples/standard/dynamic-scope/dynamic-scopes.rb +12 -0
- data/samples/standard/dynamic-scope/input +7 -0
- data/samples/standard/dynamic-scope/output +4 -0
- data/samples/standard/fuzzy/FuzzyJava.g +89 -0
- data/samples/standard/fuzzy/fuzzy.py +11 -0
- data/samples/standard/fuzzy/fuzzy.rb +9 -0
- data/samples/standard/fuzzy/input +13 -0
- data/samples/standard/fuzzy/output +12 -0
- data/samples/standard/hoisted-predicates/HoistedPredicates.g +40 -0
- data/samples/standard/hoisted-predicates/hoisted-predicates.rb +13 -0
- data/samples/standard/hoisted-predicates/input +1 -0
- data/samples/standard/hoisted-predicates/output +1 -0
- data/samples/standard/island-grammar/Javadoc.g +46 -0
- data/samples/standard/island-grammar/Simple.g +104 -0
- data/samples/standard/island-grammar/input +11 -0
- data/samples/standard/island-grammar/island.rb +12 -0
- data/samples/standard/island-grammar/output +16 -0
- data/samples/standard/java/Java.g +827 -0
- data/samples/standard/java/input +80 -0
- data/samples/standard/java/java.rb +13 -0
- data/samples/standard/java/output +1 -0
- data/samples/standard/python/Python.g +718 -0
- data/samples/standard/python/PythonTokenSource.rb +107 -0
- data/samples/standard/python/input +210 -0
- data/samples/standard/python/output +24 -0
- data/samples/standard/python/python.rb +14 -0
- data/samples/standard/rakefile +18 -0
- data/samples/standard/scopes/SymbolTable.g +66 -0
- data/samples/standard/scopes/input +12 -0
- data/samples/standard/scopes/output +3 -0
- data/samples/standard/scopes/scopes.rb +12 -0
- data/samples/standard/simplecTreeParser/SimpleC.g +113 -0
- data/samples/standard/simplecTreeParser/SimpleCWalker.g +64 -0
- data/samples/standard/simplecTreeParser/input +12 -0
- data/samples/standard/simplecTreeParser/output +1 -0
- data/samples/standard/simplecTreeParser/simplec.rb +18 -0
- data/samples/standard/treeparser/Lang.g +24 -0
- data/samples/standard/treeparser/LangDumpDecl.g +17 -0
- data/samples/standard/treeparser/input +1 -0
- data/samples/standard/treeparser/output +2 -0
- data/samples/standard/treeparser/treeparser.rb +18 -0
- data/samples/standard/tweak/Tweak.g +68 -0
- data/samples/standard/tweak/input +9 -0
- data/samples/standard/tweak/output +16 -0
- data/samples/standard/tweak/tweak.rb +13 -0
- data/samples/standard/xml/README +16 -0
- data/samples/standard/xml/XML.g +123 -0
- data/samples/standard/xml/input +21 -0
- data/samples/standard/xml/output +39 -0
- data/samples/standard/xml/xml.rb +9 -0
- data/templates/Ruby.stg +4 -4
- data/test/functional/ast-output/auto-ast.rb +0 -5
- data/test/functional/ast-output/rewrites.rb +4 -4
- data/test/unit/test-scope.rb +45 -0
- metadata +96 -8
data/lib/antlr3/profile.rb
CHANGED
@@ -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.
|
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.
|
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.
|
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
|
data/lib/antlr3/recognizers.rb
CHANGED
@@ -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
|
data/lib/antlr3/streams.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
#
|
196
|
+
# returns the current position of the stream
|
196
197
|
abstract :index
|
197
198
|
|
198
199
|
##
|
199
|
-
# :method: rewind(marker=last_marker)
|
200
|
-
#
|
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
|
-
#
|
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
|
-
#
|
211
|
+
# :method: seek( position )
|
212
|
+
# move the stream to the given absolute index given by +position+
|
211
213
|
abstract :seek
|
212
214
|
|
213
|
-
|
215
|
+
##
|
216
|
+
# the total number of symbols in the stream
|
214
217
|
attr_reader :size
|
215
|
-
|
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
|
-
#
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
class
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
super(
|
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
|
-
|
169
|
-
|
165
|
+
class Delete < Replace
|
166
|
+
@operation_name = 'delete'.freeze
|
170
167
|
|
171
|
-
|
172
|
-
|
173
|
-
|
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
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
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
|
-
|
204
|
-
|
205
|
-
location = operation.location
|
180
|
+
def replace( *range_arguments )
|
181
|
+
range, text = cast_range( range_arguments, 1 )
|
206
182
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
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
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
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
|
-
|
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
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
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
|
-
|
305
|
+
def clear
|
306
|
+
@operations.clear
|
307
|
+
end
|
269
308
|
|
270
|
-
|
309
|
+
def undo( number_of_operations = 1 )
|
310
|
+
@operations.pop( number_of_operations )
|
311
|
+
end
|
271
312
|
|
272
|
-
|
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
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
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
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
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 = {} )
|