parser 2.1.9 → 2.2.0.pre.1
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.
- 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
|