parser 2.1.9 → 2.2.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +6 -1
- data/CHANGELOG.md +471 -0
- data/Gemfile +0 -5
- data/README.md +1 -1
- data/Rakefile +13 -2
- data/doc/AST_FORMAT.md +3 -3
- data/lib/parser.rb +1 -0
- data/lib/parser/all.rb +1 -0
- data/lib/parser/clobbering_error.rb +11 -0
- data/lib/parser/current.rb +5 -0
- data/lib/parser/lexer.rl +12 -0
- data/lib/parser/ruby22.y +2327 -0
- data/lib/parser/runner.rb +13 -4
- data/lib/parser/source/rewriter.rb +73 -9
- data/lib/parser/version.rb +1 -1
- data/parser.gemspec +2 -2
- data/test/parse_helper.rb +3 -2
- data/test/test_current.rb +3 -1
- data/test/test_parser.rb +47 -0
- data/test/test_source_rewriter.rb +85 -1
- metadata +14 -7
- data/.rubocop.yml +0 -25
data/lib/parser/runner.rb
CHANGED
@@ -67,16 +67,21 @@ module Parser
|
|
67
67
|
@parser_class = Parser::Ruby19
|
68
68
|
end
|
69
69
|
|
70
|
-
@slop.on '20', 'Parse as Ruby 2.0
|
70
|
+
@slop.on '20', 'Parse as Ruby 2.0 would' do
|
71
71
|
require 'parser/ruby20'
|
72
72
|
@parser_class = Parser::Ruby20
|
73
73
|
end
|
74
74
|
|
75
|
-
@slop.on '21', 'Parse as Ruby 2.1
|
75
|
+
@slop.on '21', 'Parse as Ruby 2.1 would' do
|
76
76
|
require 'parser/ruby21'
|
77
77
|
@parser_class = Parser::Ruby21
|
78
78
|
end
|
79
79
|
|
80
|
+
@slop.on '22', 'Parse as Ruby 2.2 would' do
|
81
|
+
require 'parser/ruby22'
|
82
|
+
@parser_class = Parser::Ruby22
|
83
|
+
end
|
84
|
+
|
80
85
|
@slop.on 'w', 'warnings', 'Enable warnings'
|
81
86
|
|
82
87
|
@slop.on 'B', 'benchmark', 'Benchmark the processor'
|
@@ -140,7 +145,9 @@ module Parser
|
|
140
145
|
|
141
146
|
def process_fragments
|
142
147
|
@fragments.each_with_index do |fragment, index|
|
143
|
-
|
148
|
+
if fragment.respond_to? :force_encoding
|
149
|
+
fragment = fragment.dup.force_encoding(@parser.default_encoding)
|
150
|
+
end
|
144
151
|
|
145
152
|
buffer = Source::Buffer.new("(fragment:#{index})")
|
146
153
|
buffer.source = fragment
|
@@ -152,7 +159,9 @@ module Parser
|
|
152
159
|
def process_files
|
153
160
|
@files.each do |filename|
|
154
161
|
source = File.read(filename)
|
155
|
-
source.force_encoding
|
162
|
+
if source.respond_to? :force_encoding
|
163
|
+
source.force_encoding(@parser.default_encoding)
|
164
|
+
end
|
156
165
|
|
157
166
|
buffer = Parser::Source::Buffer.new(filename)
|
158
167
|
|
@@ -44,7 +44,7 @@ module Parser
|
|
44
44
|
#
|
45
45
|
# @param [Range] range
|
46
46
|
# @return [Rewriter] self
|
47
|
-
# @raise [
|
47
|
+
# @raise [ClobberingError] when clobbering is detected
|
48
48
|
#
|
49
49
|
def remove(range)
|
50
50
|
append Rewriter::Action.new(range, '')
|
@@ -56,7 +56,7 @@ module Parser
|
|
56
56
|
# @param [Range] range
|
57
57
|
# @param [String] content
|
58
58
|
# @return [Rewriter] self
|
59
|
-
# @raise [
|
59
|
+
# @raise [ClobberingError] when clobbering is detected
|
60
60
|
#
|
61
61
|
def insert_before(range, content)
|
62
62
|
append Rewriter::Action.new(range.begin, content)
|
@@ -68,7 +68,7 @@ module Parser
|
|
68
68
|
# @param [Range] range
|
69
69
|
# @param [String] content
|
70
70
|
# @return [Rewriter] self
|
71
|
-
# @raise [
|
71
|
+
# @raise [ClobberingError] when clobbering is detected
|
72
72
|
#
|
73
73
|
def insert_after(range, content)
|
74
74
|
append Rewriter::Action.new(range.end, content)
|
@@ -80,7 +80,7 @@ module Parser
|
|
80
80
|
# @param [Range] range
|
81
81
|
# @param [String] content
|
82
82
|
# @return [Rewriter] self
|
83
|
-
# @raise [
|
83
|
+
# @raise [ClobberingError] when clobbering is detected
|
84
84
|
#
|
85
85
|
def replace(range, content)
|
86
86
|
append Rewriter::Action.new(range, content)
|
@@ -93,6 +93,10 @@ module Parser
|
|
93
93
|
# @return [String]
|
94
94
|
#
|
95
95
|
def process
|
96
|
+
if in_transaction?
|
97
|
+
raise "Do not call #{self.class}##{__method__} inside a transaction"
|
98
|
+
end
|
99
|
+
|
96
100
|
adjustment = 0
|
97
101
|
source = @source_buffer.source.dup
|
98
102
|
|
@@ -112,6 +116,46 @@ module Parser
|
|
112
116
|
source
|
113
117
|
end
|
114
118
|
|
119
|
+
##
|
120
|
+
# Provides a protected block where a sequence of multiple rewrite actions
|
121
|
+
# are handled atomic. If any of the action failed by clobbering,
|
122
|
+
# all the actions are rolled back.
|
123
|
+
#
|
124
|
+
# @example
|
125
|
+
# begin
|
126
|
+
# rewriter.transaction do
|
127
|
+
# rewriter.insert_before(range_of_something, '(')
|
128
|
+
# rewriter.insert_after(range_of_something, ')')
|
129
|
+
# end
|
130
|
+
# rescue Parser::ClobberingError
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# @raise [RuntimeError] when no block is passed
|
134
|
+
# @raise [RuntimeError] when already in a transaction
|
135
|
+
#
|
136
|
+
def transaction
|
137
|
+
unless block_given?
|
138
|
+
raise "#{self.class}##{__method__} requires block"
|
139
|
+
end
|
140
|
+
|
141
|
+
if in_transaction?
|
142
|
+
raise 'Nested transaction is not supported'
|
143
|
+
end
|
144
|
+
|
145
|
+
@pending_queue = @queue.dup
|
146
|
+
@pending_clobber = @clobber
|
147
|
+
|
148
|
+
yield
|
149
|
+
|
150
|
+
@queue = @pending_queue
|
151
|
+
@clobber = @pending_clobber
|
152
|
+
|
153
|
+
self
|
154
|
+
ensure
|
155
|
+
@pending_queue = nil
|
156
|
+
@pending_clobber = nil
|
157
|
+
end
|
158
|
+
|
115
159
|
private
|
116
160
|
|
117
161
|
def append(action)
|
@@ -130,27 +174,47 @@ module Parser
|
|
130
174
|
clobber_action.range)
|
131
175
|
@diagnostics.process(diagnostic)
|
132
176
|
|
133
|
-
raise
|
177
|
+
raise ClobberingError, "Parser::Source::Rewriter detected clobbering"
|
134
178
|
else
|
135
179
|
clobber(action.range)
|
136
180
|
|
137
|
-
|
181
|
+
active_queue << action
|
138
182
|
end
|
139
183
|
|
140
184
|
self
|
141
185
|
end
|
142
186
|
|
143
187
|
def clobber(range)
|
144
|
-
|
188
|
+
self.active_clobber = active_clobber | (2 ** range.size - 1) << range.begin_pos
|
145
189
|
end
|
146
190
|
|
147
191
|
def clobbered?(range)
|
148
|
-
if
|
149
|
-
|
192
|
+
if active_clobber & ((2 ** range.size - 1) << range.begin_pos) != 0
|
193
|
+
active_queue.find do |action|
|
150
194
|
action.range.to_a & range.to_a
|
151
195
|
end
|
152
196
|
end
|
153
197
|
end
|
198
|
+
|
199
|
+
def in_transaction?
|
200
|
+
!@pending_queue.nil?
|
201
|
+
end
|
202
|
+
|
203
|
+
def active_queue
|
204
|
+
@pending_queue || @queue
|
205
|
+
end
|
206
|
+
|
207
|
+
def active_clobber
|
208
|
+
@pending_clobber || @clobber
|
209
|
+
end
|
210
|
+
|
211
|
+
def active_clobber=(value)
|
212
|
+
if @pending_clobber
|
213
|
+
@pending_clobber = value
|
214
|
+
else
|
215
|
+
@clobber = value
|
216
|
+
end
|
217
|
+
end
|
154
218
|
end
|
155
219
|
|
156
220
|
end
|
data/lib/parser/version.rb
CHANGED
data/parser.gemspec
CHANGED
@@ -21,14 +21,14 @@ Gem::Specification.new do |spec|
|
|
21
21
|
lib/parser/ruby21.rb
|
22
22
|
)
|
23
23
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
24
|
-
spec.test_files = spec.files.grep(%r{^
|
24
|
+
spec.test_files = spec.files.grep(%r{^test/})
|
25
25
|
spec.require_paths = ['lib']
|
26
26
|
|
27
27
|
spec.add_dependency 'ast', ['>= 1.1', '< 3.0']
|
28
28
|
spec.add_dependency 'slop', ['~> 3.4', '>= 3.4.5']
|
29
29
|
|
30
30
|
spec.add_development_dependency 'bundler', '~> 1.2'
|
31
|
-
spec.add_development_dependency 'rake', '
|
31
|
+
spec.add_development_dependency 'rake', ['>= 0.9', '< 11.0']
|
32
32
|
spec.add_development_dependency 'racc', '= 1.4.9' # update to 1.4.11 when it's done
|
33
33
|
spec.add_development_dependency 'cliver', '~> 0.3.0'
|
34
34
|
|
data/test/parse_helper.rb
CHANGED
@@ -7,9 +7,9 @@ module ParseHelper
|
|
7
7
|
ALL_VERSIONS = %w(1.8)
|
8
8
|
else
|
9
9
|
require 'parser/all'
|
10
|
-
require 'parser/
|
10
|
+
require 'parser/ruby22'
|
11
11
|
|
12
|
-
ALL_VERSIONS = %w(1.8 1.9 2.0 2.1)
|
12
|
+
ALL_VERSIONS = %w(1.8 1.9 2.0 2.1 2.2)
|
13
13
|
end
|
14
14
|
|
15
15
|
def setup
|
@@ -24,6 +24,7 @@ module ParseHelper
|
|
24
24
|
when '1.9' then parser = Parser::Ruby19.new
|
25
25
|
when '2.0' then parser = Parser::Ruby20.new
|
26
26
|
when '2.1' then parser = Parser::Ruby21.new
|
27
|
+
when '2.2' then parser = Parser::Ruby22.new
|
27
28
|
else raise "Unrecognized Ruby version #{version}"
|
28
29
|
end
|
29
30
|
|
data/test/test_current.rb
CHANGED
@@ -10,8 +10,10 @@ class TestCurrent < Minitest::Test
|
|
10
10
|
assert_equal Parser::Ruby19, Parser::CurrentRuby
|
11
11
|
when '2.0.0'
|
12
12
|
assert_equal Parser::Ruby20, Parser::CurrentRuby
|
13
|
-
when '2.1.0', '2.1.1'
|
13
|
+
when '2.1.0', '2.1.1', '2.1.2'
|
14
14
|
assert_equal Parser::Ruby21, Parser::CurrentRuby
|
15
|
+
when '2.2.0'
|
16
|
+
assert_equal Parser::Ruby22, Parser::CurrentRuby
|
15
17
|
else
|
16
18
|
flunk "Update test_parser_current for #{RUBY_VERSION}"
|
17
19
|
end
|
data/test/test_parser.rb
CHANGED
@@ -1769,6 +1769,25 @@ class TestParser < Minitest::Test
|
|
1769
1769
|
| ~~~~~~ expression (args.blockarg)})
|
1770
1770
|
end
|
1771
1771
|
|
1772
|
+
def test_arg_scope
|
1773
|
+
# [ruby-core:61299] [Bug #9593]
|
1774
|
+
assert_parses(
|
1775
|
+
s(:def, :f,
|
1776
|
+
s(:args, s(:optarg, :var, s(:defined?, s(:lvar, :var)))),
|
1777
|
+
s(:lvar, :var)),
|
1778
|
+
%q{def f(var = defined?(var)) var end},
|
1779
|
+
%q{},
|
1780
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0))
|
1781
|
+
|
1782
|
+
assert_parses(
|
1783
|
+
s(:def, :f,
|
1784
|
+
s(:args, s(:kwoptarg, :var, s(:defined?, s(:lvar, :var)))),
|
1785
|
+
s(:lvar, :var)),
|
1786
|
+
%q{def f(var: defined?(var)) var end},
|
1787
|
+
%q{},
|
1788
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0))
|
1789
|
+
end
|
1790
|
+
|
1772
1791
|
def assert_parses_args(ast, code, versions=ALL_VERSIONS)
|
1773
1792
|
assert_parses(
|
1774
1793
|
s(:def, :f, ast, nil),
|
@@ -4765,6 +4784,34 @@ class TestParser < Minitest::Test
|
|
4765
4784
|
%q{desc "foo" do end})
|
4766
4785
|
end
|
4767
4786
|
|
4787
|
+
def test_bug_do_block_in_call_args
|
4788
|
+
# [ruby-core:59342] [Bug #9308]
|
4789
|
+
assert_parses(
|
4790
|
+
s(:send, nil, :bar,
|
4791
|
+
s(:def, :foo,
|
4792
|
+
s(:args),
|
4793
|
+
s(:block,
|
4794
|
+
s(:send, s(:self), :each),
|
4795
|
+
s(:args),
|
4796
|
+
nil))),
|
4797
|
+
%q{bar def foo; self.each do end end},
|
4798
|
+
%q{},
|
4799
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1))
|
4800
|
+
end
|
4801
|
+
|
4802
|
+
def test_bug_do_block_in_cmdarg
|
4803
|
+
# [ruby-core:61950] [Bug #9726]
|
4804
|
+
assert_parses(
|
4805
|
+
s(:send, nil, :tap,
|
4806
|
+
s(:begin,
|
4807
|
+
s(:block,
|
4808
|
+
s(:send, nil, :proc),
|
4809
|
+
s(:args), nil))),
|
4810
|
+
%q{tap (proc do end)},
|
4811
|
+
%q{},
|
4812
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1))
|
4813
|
+
end
|
4814
|
+
|
4768
4815
|
def test_bug_interp_single
|
4769
4816
|
assert_parses(
|
4770
4817
|
s(:dstr, s(:begin, s(:int, 1))),
|
@@ -74,7 +74,7 @@ class TestSourceRewriter < Minitest::Test
|
|
74
74
|
diagnostics << diag
|
75
75
|
end
|
76
76
|
|
77
|
-
assert_raises
|
77
|
+
assert_raises Parser::ClobberingError do
|
78
78
|
@rewriter.
|
79
79
|
replace(range(3, 1), '---').
|
80
80
|
remove(range(3, 1))
|
@@ -92,4 +92,88 @@ class TestSourceRewriter < Minitest::Test
|
|
92
92
|
diagnostics.last.message
|
93
93
|
assert_equal range(3, 1), diagnostics.last.location
|
94
94
|
end
|
95
|
+
|
96
|
+
def test_clobbering_error_backward_compatibility
|
97
|
+
silence_diagnostics
|
98
|
+
|
99
|
+
rescued = false
|
100
|
+
|
101
|
+
# We use begin..rescue..end here rather than #assert_raises
|
102
|
+
# since #assert_raises expects exact error class.
|
103
|
+
begin
|
104
|
+
@rewriter.
|
105
|
+
replace(range(3, 1), '---').
|
106
|
+
remove(range(3, 1))
|
107
|
+
rescue RuntimeError => error
|
108
|
+
rescued = true if error.message.include?('clobber')
|
109
|
+
end
|
110
|
+
|
111
|
+
assert rescued
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_transaction_returns_self
|
115
|
+
assert_equal @rewriter, @rewriter.transaction {}
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_transaction_commit
|
119
|
+
silence_diagnostics
|
120
|
+
|
121
|
+
# Original: 'foo bar baz'
|
122
|
+
|
123
|
+
# Rewrite as 'foo BAR baz'
|
124
|
+
@rewriter.replace(range(4, 3), 'BAR')
|
125
|
+
|
126
|
+
# Rewrite as '( bar )'
|
127
|
+
@rewriter.transaction do
|
128
|
+
@rewriter.replace(range(0, 3), '(')
|
129
|
+
@rewriter.replace(range(8, 3), ')')
|
130
|
+
end
|
131
|
+
|
132
|
+
@rewriter.replace(range(3, 1), '_')
|
133
|
+
@rewriter.replace(range(7, 1), '_')
|
134
|
+
|
135
|
+
assert_equal '(_BAR_)', @rewriter.process
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_transaction_rollback
|
139
|
+
silence_diagnostics
|
140
|
+
|
141
|
+
# Original: 'foo bar baz'
|
142
|
+
|
143
|
+
# Rewrite as 'foo bar BAZ'
|
144
|
+
@rewriter.replace(range(8, 3), 'BAZ')
|
145
|
+
|
146
|
+
assert_raises Parser::ClobberingError do
|
147
|
+
# Trying to rewrite as '( bar )', but it fails
|
148
|
+
@rewriter.transaction do
|
149
|
+
@rewriter.replace(range(0, 3), '(')
|
150
|
+
@rewriter.replace(range(8, 3), ')')
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
@rewriter.replace(range(0, 3), 'FOO')
|
155
|
+
|
156
|
+
assert_equal 'FOO bar BAZ', @rewriter.process
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_nested_transaction_raises_error
|
160
|
+
assert_raises RuntimeError, /nested/ do
|
161
|
+
@rewriter.transaction do
|
162
|
+
@rewriter.transaction do
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_process_in_transaction_raises_error
|
169
|
+
assert_raises RuntimeError, /transaction/ do
|
170
|
+
@rewriter.transaction do
|
171
|
+
@rewriter.process
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def silence_diagnostics
|
177
|
+
@rewriter.diagnostics.consumer = proc {}
|
178
|
+
end
|
95
179
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1
|
4
|
+
version: 2.2.0.pre.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Zotov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ast
|
@@ -68,16 +68,22 @@ dependencies:
|
|
68
68
|
name: rake
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
70
70
|
requirements:
|
71
|
-
- - "
|
71
|
+
- - ">="
|
72
72
|
- !ruby/object:Gem::Version
|
73
73
|
version: '0.9'
|
74
|
+
- - "<"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '11.0'
|
74
77
|
type: :development
|
75
78
|
prerelease: false
|
76
79
|
version_requirements: !ruby/object:Gem::Requirement
|
77
80
|
requirements:
|
78
|
-
- - "
|
81
|
+
- - ">="
|
79
82
|
- !ruby/object:Gem::Version
|
80
83
|
version: '0.9'
|
84
|
+
- - "<"
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '11.0'
|
81
87
|
- !ruby/object:Gem::Dependency
|
82
88
|
name: racc
|
83
89
|
requirement: !ruby/object:Gem::Requirement
|
@@ -242,7 +248,6 @@ extensions: []
|
|
242
248
|
extra_rdoc_files: []
|
243
249
|
files:
|
244
250
|
- ".gitignore"
|
245
|
-
- ".rubocop.yml"
|
246
251
|
- ".travis.yml"
|
247
252
|
- ".yardopts"
|
248
253
|
- CHANGELOG.md
|
@@ -265,6 +270,7 @@ files:
|
|
265
270
|
- lib/parser/ast/processor.rb
|
266
271
|
- lib/parser/base.rb
|
267
272
|
- lib/parser/builders/default.rb
|
273
|
+
- lib/parser/clobbering_error.rb
|
268
274
|
- lib/parser/compatibility/ruby1_8.rb
|
269
275
|
- lib/parser/compatibility/ruby1_9.rb
|
270
276
|
- lib/parser/current.rb
|
@@ -286,6 +292,7 @@ files:
|
|
286
292
|
- lib/parser/ruby20.y
|
287
293
|
- lib/parser/ruby21.rb
|
288
294
|
- lib/parser/ruby21.y
|
295
|
+
- lib/parser/ruby22.y
|
289
296
|
- lib/parser/runner.rb
|
290
297
|
- lib/parser/runner/ruby_parse.rb
|
291
298
|
- lib/parser/runner/ruby_rewrite.rb
|
@@ -346,9 +353,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
346
353
|
version: '0'
|
347
354
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
348
355
|
requirements:
|
349
|
-
- - "
|
356
|
+
- - ">"
|
350
357
|
- !ruby/object:Gem::Version
|
351
|
-
version:
|
358
|
+
version: 1.3.1
|
352
359
|
requirements: []
|
353
360
|
rubyforge_project:
|
354
361
|
rubygems_version: 2.2.2
|