parser 2.7.0.4 → 2.7.1.3
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 +18 -29
- data/CHANGELOG.md +53 -1
- data/README.md +6 -6
- data/Rakefile +2 -1
- data/doc/AST_FORMAT.md +54 -5
- data/lib/parser.rb +1 -0
- data/lib/parser/all.rb +1 -0
- data/lib/parser/ast/processor.rb +7 -0
- data/lib/parser/builders/default.rb +63 -14
- data/lib/parser/current.rb +13 -4
- data/lib/parser/diagnostic.rb +1 -1
- data/lib/parser/diagnostic/engine.rb +1 -2
- data/lib/parser/lexer.rl +7 -0
- data/lib/parser/messages.rb +15 -0
- data/lib/parser/meta.rb +2 -2
- data/lib/parser/ruby27.y +16 -5
- data/lib/parser/ruby28.y +3016 -0
- data/lib/parser/runner.rb +26 -2
- data/lib/parser/runner/ruby_rewrite.rb +2 -2
- data/lib/parser/source/buffer.rb +3 -1
- data/lib/parser/source/comment/associator.rb +14 -4
- data/lib/parser/source/map/endless_definition.rb +23 -0
- data/lib/parser/source/range.rb +16 -0
- data/lib/parser/source/tree_rewriter.rb +49 -12
- data/lib/parser/source/tree_rewriter/action.rb +96 -26
- data/lib/parser/tree_rewriter.rb +1 -2
- data/lib/parser/version.rb +1 -1
- data/parser.gemspec +2 -1
- data/test/helper.rb +25 -6
- data/test/parse_helper.rb +11 -17
- data/test/test_ast_processor.rb +32 -0
- data/test/test_base.rb +1 -1
- data/test/test_current.rb +2 -0
- data/test/test_diagnostic.rb +6 -7
- data/test/test_diagnostic_engine.rb +5 -8
- data/test/test_lexer.rb +17 -8
- data/test/test_meta.rb +12 -0
- data/test/test_parser.rb +260 -21
- data/test/test_runner_parse.rb +22 -1
- data/test/test_runner_rewrite.rb +1 -1
- data/test/test_source_buffer.rb +4 -1
- data/test/test_source_comment.rb +2 -2
- data/test/test_source_comment_associator.rb +47 -15
- data/test/test_source_map.rb +1 -2
- data/test/test_source_range.rb +29 -9
- data/test/test_source_rewriter.rb +4 -4
- data/test/test_source_rewriter_action.rb +2 -2
- data/test/test_source_tree_rewriter.rb +96 -6
- metadata +14 -7
data/lib/parser/tree_rewriter.rb
CHANGED
@@ -28,8 +28,7 @@ module Parser
|
|
28
28
|
# EOF
|
29
29
|
#
|
30
30
|
# ast = Parser::CurrentRuby.parse code
|
31
|
-
# buffer = Parser::Source::Buffer.new('(example)')
|
32
|
-
# buffer.source = code
|
31
|
+
# buffer = Parser::Source::Buffer.new('(example)', source: code)
|
33
32
|
# rewriter = RemoveDo.new
|
34
33
|
#
|
35
34
|
# # Rewrite the AST, returns a String with the new form.
|
data/lib/parser/version.rb
CHANGED
data/parser.gemspec
CHANGED
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
lib/parser/ruby25.rb
|
33
33
|
lib/parser/ruby26.rb
|
34
34
|
lib/parser/ruby27.rb
|
35
|
+
lib/parser/ruby28.rb
|
35
36
|
lib/parser/macruby.rb
|
36
37
|
lib/parser/rubymotion.rb
|
37
38
|
)
|
@@ -44,7 +45,7 @@ Gem::Specification.new do |spec|
|
|
44
45
|
spec.add_dependency 'ast', '~> 2.4.0'
|
45
46
|
|
46
47
|
spec.add_development_dependency 'bundler', '>= 1.15', '< 3.0.0'
|
47
|
-
spec.add_development_dependency 'rake', '~>
|
48
|
+
spec.add_development_dependency 'rake', '~> 13.0.1'
|
48
49
|
spec.add_development_dependency 'racc', '= 1.4.15'
|
49
50
|
spec.add_development_dependency 'cliver', '~> 0.3.2'
|
50
51
|
|
data/test/helper.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'tempfile'
|
4
|
-
require 'minitest/test'
|
5
|
-
|
6
4
|
require 'simplecov'
|
7
5
|
|
8
6
|
if ENV.include?('COVERAGE') && SimpleCov.usable?
|
@@ -20,6 +18,7 @@ if ENV.include?('COVERAGE') && SimpleCov.usable?
|
|
20
18
|
ruby25.y
|
21
19
|
ruby26.y
|
22
20
|
ruby27.y
|
21
|
+
ruby28.y
|
23
22
|
),
|
24
23
|
File.expand_path('../../lib/parser', __FILE__))
|
25
24
|
|
@@ -27,9 +26,9 @@ if ENV.include?('COVERAGE') && SimpleCov.usable?
|
|
27
26
|
at_exit { RaccCoverage.stop }
|
28
27
|
|
29
28
|
SimpleCov.start do
|
30
|
-
self.formatter = SimpleCov::Formatter::MultiFormatter
|
31
|
-
SimpleCov::Formatter::HTMLFormatter
|
32
|
-
|
29
|
+
self.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
30
|
+
SimpleCov::Formatter::HTMLFormatter
|
31
|
+
)
|
33
32
|
|
34
33
|
add_group 'Grammars' do |source_file|
|
35
34
|
source_file.filename =~ %r{\.y$}
|
@@ -52,9 +51,29 @@ require 'minitest/autorun'
|
|
52
51
|
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
53
52
|
require 'parser'
|
54
53
|
|
54
|
+
module NodeCollector
|
55
|
+
extend self
|
56
|
+
attr_accessor :callbacks, :nodes
|
57
|
+
self.callbacks = []
|
58
|
+
self.nodes = []
|
59
|
+
|
60
|
+
def check
|
61
|
+
@callbacks.each do |callback|
|
62
|
+
@nodes.each { |node| callback.call(node) }
|
63
|
+
end
|
64
|
+
puts "#{callbacks.size} additional tests on #{nodes.size} nodes ran successfully"
|
65
|
+
end
|
66
|
+
|
67
|
+
Minitest.after_run { check }
|
68
|
+
end
|
69
|
+
|
70
|
+
def for_each_node(&block)
|
71
|
+
NodeCollector.callbacks << block
|
72
|
+
end
|
73
|
+
|
55
74
|
class Parser::AST::Node
|
56
75
|
def initialize(type, *)
|
57
|
-
|
76
|
+
NodeCollector.nodes << self
|
58
77
|
super
|
59
78
|
end
|
60
79
|
end
|
data/test/parse_helper.rb
CHANGED
@@ -7,7 +7,7 @@ module ParseHelper
|
|
7
7
|
require 'parser/macruby'
|
8
8
|
require 'parser/rubymotion'
|
9
9
|
|
10
|
-
ALL_VERSIONS = %w(1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 mac ios)
|
10
|
+
ALL_VERSIONS = %w(1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 mac ios)
|
11
11
|
|
12
12
|
def setup
|
13
13
|
@diagnostics = []
|
@@ -27,6 +27,7 @@ module ParseHelper
|
|
27
27
|
when '2.5' then parser = Parser::Ruby25.new
|
28
28
|
when '2.6' then parser = Parser::Ruby26.new
|
29
29
|
when '2.7' then parser = Parser::Ruby27.new
|
30
|
+
when '2.8' then parser = Parser::Ruby28.new
|
30
31
|
when 'mac' then parser = Parser::MacRuby.new
|
31
32
|
when 'ios' then parser = Parser::RubyMotion.new
|
32
33
|
else raise "Unrecognized Ruby version #{version}"
|
@@ -84,8 +85,7 @@ module ParseHelper
|
|
84
85
|
end
|
85
86
|
|
86
87
|
def try_parsing(ast, code, parser, source_maps, version)
|
87
|
-
source_file = Parser::Source::Buffer.new('(assert_parses)')
|
88
|
-
source_file.source = code
|
88
|
+
source_file = Parser::Source::Buffer.new('(assert_parses)', source: code)
|
89
89
|
|
90
90
|
begin
|
91
91
|
parsed_ast = parser.parse(source_file)
|
@@ -105,8 +105,7 @@ module ParseHelper
|
|
105
105
|
assert_equal ast, parsed_ast,
|
106
106
|
"(#{version}) AST equality"
|
107
107
|
|
108
|
-
parse_source_map_descriptions(source_maps)
|
109
|
-
do |begin_pos, end_pos, map_field, ast_path, line|
|
108
|
+
parse_source_map_descriptions(source_maps) do |begin_pos, end_pos, map_field, ast_path, line|
|
110
109
|
|
111
110
|
astlet = traverse_ast(parsed_ast, ast_path)
|
112
111
|
|
@@ -142,8 +141,7 @@ module ParseHelper
|
|
142
141
|
# ~~~
|
143
142
|
def assert_diagnoses(diagnostic, code, source_maps='', versions=ALL_VERSIONS)
|
144
143
|
with_versions(versions) do |version, parser|
|
145
|
-
source_file = Parser::Source::Buffer.new('(assert_diagnoses)')
|
146
|
-
source_file.source = code
|
144
|
+
source_file = Parser::Source::Buffer.new('(assert_diagnoses)', source: code)
|
147
145
|
|
148
146
|
begin
|
149
147
|
parser = parser.parse(source_file)
|
@@ -159,15 +157,14 @@ module ParseHelper
|
|
159
157
|
|
160
158
|
level, reason, arguments = diagnostic
|
161
159
|
arguments ||= {}
|
162
|
-
message = Parser::
|
160
|
+
message = Parser::Messages.compile(reason, arguments)
|
163
161
|
|
164
162
|
assert_equal level, emitted_diagnostic.level
|
165
163
|
assert_equal reason, emitted_diagnostic.reason
|
166
164
|
assert_equal arguments, emitted_diagnostic.arguments
|
167
165
|
assert_equal message, emitted_diagnostic.message
|
168
166
|
|
169
|
-
parse_source_map_descriptions(source_maps)
|
170
|
-
do |begin_pos, end_pos, map_field, ast_path, line|
|
167
|
+
parse_source_map_descriptions(source_maps) do |begin_pos, end_pos, map_field, ast_path, line|
|
171
168
|
|
172
169
|
case map_field
|
173
170
|
when 'location'
|
@@ -201,8 +198,7 @@ module ParseHelper
|
|
201
198
|
# ~~~
|
202
199
|
def assert_diagnoses_many(diagnostics, code, versions=ALL_VERSIONS)
|
203
200
|
with_versions(versions) do |version, parser|
|
204
|
-
source_file = Parser::Source::Buffer.new('(assert_diagnoses_many)')
|
205
|
-
source_file.source = code
|
201
|
+
source_file = Parser::Source::Buffer.new('(assert_diagnoses_many)', source: code)
|
206
202
|
|
207
203
|
begin
|
208
204
|
parser = parser.parse(source_file)
|
@@ -215,7 +211,7 @@ module ParseHelper
|
|
215
211
|
diagnostics.zip(@diagnostics) do |expected_diagnostic, actual_diagnostic|
|
216
212
|
level, reason, arguments = expected_diagnostic
|
217
213
|
arguments ||= {}
|
218
|
-
message = Parser::
|
214
|
+
message = Parser::Messages.compile(reason, arguments)
|
219
215
|
|
220
216
|
assert_equal level, actual_diagnostic.level
|
221
217
|
assert_equal reason, actual_diagnostic.reason
|
@@ -227,8 +223,7 @@ module ParseHelper
|
|
227
223
|
|
228
224
|
def refute_diagnoses(code, versions=ALL_VERSIONS)
|
229
225
|
with_versions(versions) do |version, parser|
|
230
|
-
source_file = Parser::Source::Buffer.new('(refute_diagnoses)')
|
231
|
-
source_file.source = code
|
226
|
+
source_file = Parser::Source::Buffer.new('(refute_diagnoses)', source: code)
|
232
227
|
|
233
228
|
begin
|
234
229
|
parser = parser.parse(source_file)
|
@@ -244,8 +239,7 @@ module ParseHelper
|
|
244
239
|
|
245
240
|
def assert_context(context, code, versions=ALL_VERSIONS)
|
246
241
|
with_versions(versions) do |version, parser|
|
247
|
-
source_file = Parser::Source::Buffer.new('(assert_context)')
|
248
|
-
source_file.source = code
|
242
|
+
source_file = Parser::Source::Buffer.new('(assert_context)', source: code)
|
249
243
|
|
250
244
|
begin
|
251
245
|
parser.parse(source_file)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
class TestASTProcessor < Minitest::Test
|
6
|
+
LEAF_NODES = %i[
|
7
|
+
sym str int float complex rational
|
8
|
+
true false nil self
|
9
|
+
__FILE__ __LINE__ __ENCODING__
|
10
|
+
cbase regopt zsuper
|
11
|
+
match_with_trailing_comma match_nil_pattern
|
12
|
+
forward_args forwarded_args numargs kwnilarg
|
13
|
+
objc_varargs objc_restarg objc_kwarg
|
14
|
+
ident
|
15
|
+
].freeze
|
16
|
+
|
17
|
+
def setup
|
18
|
+
@traversible = Parser::AST::Processor
|
19
|
+
.instance_methods(false)
|
20
|
+
.map { |mid| mid.to_s.scan(/\Aon_(.*)/) }
|
21
|
+
.flatten
|
22
|
+
.map(&:to_sym)
|
23
|
+
|
24
|
+
@traversible += LEAF_NODES
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_nodes_are_traversible
|
28
|
+
for_each_node do |node|
|
29
|
+
assert_includes @traversible, node.type
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/test/test_base.rb
CHANGED
data/test/test_current.rb
CHANGED
@@ -22,6 +22,8 @@ class TestCurrent < Minitest::Test
|
|
22
22
|
assert_equal Parser::Ruby26, Parser::CurrentRuby
|
23
23
|
when /^2\.7\.\d+/
|
24
24
|
assert_equal Parser::Ruby27, Parser::CurrentRuby
|
25
|
+
when /^2\.8\.\d+/
|
26
|
+
assert_equal Parser::Ruby28, Parser::CurrentRuby
|
25
27
|
else
|
26
28
|
flunk "Update test_current for #{RUBY_VERSION}"
|
27
29
|
end
|
data/test/test_diagnostic.rb
CHANGED
@@ -4,8 +4,8 @@ require 'helper'
|
|
4
4
|
|
5
5
|
class TestDiagnostic < Minitest::Test
|
6
6
|
def setup
|
7
|
-
@buffer = Parser::Source::Buffer.new('(string)'
|
8
|
-
|
7
|
+
@buffer = Parser::Source::Buffer.new('(string)',
|
8
|
+
source: 'if (this is some bad code + bugs)')
|
9
9
|
|
10
10
|
@range1 = Parser::Source::Range.new(@buffer, 0, 2) # if
|
11
11
|
@range2 = Parser::Source::Range.new(@buffer, 4, 8) # this
|
@@ -16,7 +16,7 @@ class TestDiagnostic < Minitest::Test
|
|
16
16
|
Parser::Diagnostic.new(:foobar, :escape_eof, {}, @range1)
|
17
17
|
end
|
18
18
|
|
19
|
-
assert_match
|
19
|
+
assert_match(/level/, error.message)
|
20
20
|
end
|
21
21
|
|
22
22
|
def test_freezes
|
@@ -50,8 +50,8 @@ class TestDiagnostic < Minitest::Test
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def test_multiline_render
|
53
|
-
@buffer = Parser::Source::Buffer.new('(string)'
|
54
|
-
|
53
|
+
@buffer = Parser::Source::Buffer.new('(string)',
|
54
|
+
source: "abc abc abc\ndef def def\nghi ghi ghi\n")
|
55
55
|
|
56
56
|
location = Parser::Source::Range.new(@buffer, 4, 27)
|
57
57
|
|
@@ -80,8 +80,7 @@ class TestDiagnostic < Minitest::Test
|
|
80
80
|
}
|
81
81
|
}
|
82
82
|
CODE
|
83
|
-
@buffer = Parser::Source::Buffer.new('(string)')
|
84
|
-
@buffer.source = source
|
83
|
+
@buffer = Parser::Source::Buffer.new('(string)', source: source)
|
85
84
|
|
86
85
|
location = Parser::Source::Range.new(@buffer, 33, 34)
|
87
86
|
diag = Parser::Diagnostic.new(:error, :unexpected_token, { :token => 'tNL' },
|
@@ -4,9 +4,6 @@ require 'helper'
|
|
4
4
|
|
5
5
|
class TestDiagnosticEngine < Minitest::Test
|
6
6
|
def setup
|
7
|
-
@buffer = Parser::Source::Buffer.new('(source)')
|
8
|
-
@buffer.source = 'foobar'
|
9
|
-
|
10
7
|
@engine = Parser::Diagnostic::Engine.new
|
11
8
|
|
12
9
|
@queue = []
|
@@ -14,7 +11,7 @@ class TestDiagnosticEngine < Minitest::Test
|
|
14
11
|
end
|
15
12
|
|
16
13
|
def test_process_warnings
|
17
|
-
warn = Parser::Diagnostic.new(:warning, :invalid_escape,
|
14
|
+
warn = Parser::Diagnostic.new(:warning, :invalid_escape, {}, 1..2)
|
18
15
|
@engine.process(warn)
|
19
16
|
|
20
17
|
assert_equal [warn], @queue
|
@@ -23,7 +20,7 @@ class TestDiagnosticEngine < Minitest::Test
|
|
23
20
|
def test_ignore_warnings
|
24
21
|
@engine.ignore_warnings = true
|
25
22
|
|
26
|
-
warn = Parser::Diagnostic.new(:warning, :invalid_escape,
|
23
|
+
warn = Parser::Diagnostic.new(:warning, :invalid_escape, {}, 1..2)
|
27
24
|
@engine.process(warn)
|
28
25
|
|
29
26
|
assert_equal [], @queue
|
@@ -32,7 +29,7 @@ class TestDiagnosticEngine < Minitest::Test
|
|
32
29
|
def test_all_errors_are_fatal
|
33
30
|
@engine.all_errors_are_fatal = true
|
34
31
|
|
35
|
-
error = Parser::Diagnostic.new(:error, :invalid_escape,
|
32
|
+
error = Parser::Diagnostic.new(:error, :invalid_escape, {}, 1..2)
|
36
33
|
|
37
34
|
err = assert_raises Parser::SyntaxError do
|
38
35
|
@engine.process(error)
|
@@ -44,14 +41,14 @@ class TestDiagnosticEngine < Minitest::Test
|
|
44
41
|
end
|
45
42
|
|
46
43
|
def test_all_errors_are_collected
|
47
|
-
error = Parser::Diagnostic.new(:error, :invalid_escape,
|
44
|
+
error = Parser::Diagnostic.new(:error, :invalid_escape, {}, 1..2)
|
48
45
|
@engine.process(error)
|
49
46
|
|
50
47
|
assert_equal [error], @queue
|
51
48
|
end
|
52
49
|
|
53
50
|
def test_fatal_error
|
54
|
-
fatal = Parser::Diagnostic.new(:fatal, :invalid_escape,
|
51
|
+
fatal = Parser::Diagnostic.new(:fatal, :invalid_escape, {}, 1..2)
|
55
52
|
|
56
53
|
assert_raises Parser::SyntaxError do
|
57
54
|
@engine.process(fatal)
|
data/test/test_lexer.rb
CHANGED
@@ -37,9 +37,8 @@ class TestLexer < Minitest::Test
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def assert_escape(expected, input)
|
40
|
-
source_buffer = Parser::Source::Buffer.new('(assert_escape)'
|
41
|
-
|
42
|
-
source_buffer.source = "\"\\#{input}\"".encode(input.encoding)
|
40
|
+
source_buffer = Parser::Source::Buffer.new('(assert_escape)',
|
41
|
+
source: "\"\\#{input}\"".encode(input.encoding))
|
43
42
|
|
44
43
|
@lex.reset
|
45
44
|
@lex.source_buffer = source_buffer
|
@@ -71,8 +70,7 @@ class TestLexer < Minitest::Test
|
|
71
70
|
end
|
72
71
|
|
73
72
|
def assert_scanned(input, *args)
|
74
|
-
source_buffer = Parser::Source::Buffer.new('(assert_scanned)')
|
75
|
-
source_buffer.source = input
|
73
|
+
source_buffer = Parser::Source::Buffer.new('(assert_scanned)', source: input)
|
76
74
|
|
77
75
|
@lex.reset(false)
|
78
76
|
@lex.source_buffer = source_buffer
|
@@ -3569,14 +3567,25 @@ class TestLexer < Minitest::Test
|
|
3569
3567
|
:tIDENTIFIER, 're', [1, 3])
|
3570
3568
|
end
|
3571
3569
|
|
3570
|
+
def test_endless_method
|
3571
|
+
setup_lexer(28)
|
3572
|
+
|
3573
|
+
assert_scanned('def foo() = 42',
|
3574
|
+
:kDEF, "def", [0, 3],
|
3575
|
+
:tIDENTIFIER, "foo", [4, 7],
|
3576
|
+
:tLPAREN2, "(", [7, 8],
|
3577
|
+
:tRPAREN, ")", [8, 9],
|
3578
|
+
:tEQL, "=", [10, 11],
|
3579
|
+
:tINTEGER, 42, [12, 14])
|
3580
|
+
end
|
3581
|
+
|
3572
3582
|
def lex_numbered_parameter(input)
|
3573
3583
|
@lex.max_numparam_stack.push
|
3574
3584
|
|
3575
3585
|
@lex.context = Parser::Context.new
|
3576
3586
|
@lex.context.push(:block)
|
3577
3587
|
|
3578
|
-
source_buffer = Parser::Source::Buffer.new('(assert_lex_numbered_parameter)')
|
3579
|
-
source_buffer.source = input
|
3588
|
+
source_buffer = Parser::Source::Buffer.new('(assert_lex_numbered_parameter)', source: input)
|
3580
3589
|
|
3581
3590
|
@lex.source_buffer = source_buffer
|
3582
3591
|
|
@@ -3594,7 +3603,7 @@ class TestLexer < Minitest::Test
|
|
3594
3603
|
|
3595
3604
|
def refute_scanned_numbered_parameter(input, message = nil)
|
3596
3605
|
err = assert_raises Parser::SyntaxError do
|
3597
|
-
|
3606
|
+
_lex_token, (_lex_value, _lex_range) = lex_numbered_parameter(input)
|
3598
3607
|
end
|
3599
3608
|
|
3600
3609
|
if message
|
data/test/test_meta.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
class TestMeta < Minitest::Test
|
6
|
+
def test_NODE_TYPES
|
7
|
+
for_each_node do |node|
|
8
|
+
assert Parser::Meta::NODE_TYPES.include?(node.type),
|
9
|
+
"Type #{node.type} missing from Parser::Meta::NODE_TYPES"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/test/test_parser.rb
CHANGED
@@ -29,6 +29,7 @@ class TestParser < Minitest::Test
|
|
29
29
|
SINCE_2_5 = SINCE_2_4 - %w(2.4)
|
30
30
|
SINCE_2_6 = SINCE_2_5 - %w(2.5)
|
31
31
|
SINCE_2_7 = SINCE_2_6 - %w(2.6)
|
32
|
+
SINCE_2_8 = SINCE_2_7 - %w(2.7)
|
32
33
|
|
33
34
|
# Guidelines for test naming:
|
34
35
|
# * Test structure follows structure of AST_FORMAT.md.
|
@@ -5359,8 +5360,7 @@ class TestParser < Minitest::Test
|
|
5359
5360
|
|
5360
5361
|
def test_crlf_line_endings
|
5361
5362
|
with_versions(ALL_VERSIONS) do |_ver, parser|
|
5362
|
-
source_file = Parser::Source::Buffer.new('(comments)')
|
5363
|
-
source_file.source = "\r\nfoo"
|
5363
|
+
source_file = Parser::Source::Buffer.new('(comments)', source: "\r\nfoo")
|
5364
5364
|
|
5365
5365
|
range = lambda do |from, to|
|
5366
5366
|
Parser::Source::Range.new(source_file, from, to)
|
@@ -5433,8 +5433,7 @@ class TestParser < Minitest::Test
|
|
5433
5433
|
with_versions(ALL_VERSIONS) do |_ver, parser|
|
5434
5434
|
parser.builder.emit_file_line_as_literals = false
|
5435
5435
|
|
5436
|
-
source_file = Parser::Source::Buffer.new('(comments)')
|
5437
|
-
source_file.source = "[__FILE__, __LINE__]"
|
5436
|
+
source_file = Parser::Source::Buffer.new('(comments)', source: "[__FILE__, __LINE__]")
|
5438
5437
|
|
5439
5438
|
ast = parser.parse(source_file)
|
5440
5439
|
|
@@ -5518,8 +5517,7 @@ class TestParser < Minitest::Test
|
|
5518
5517
|
|
5519
5518
|
def assert_parses_with_comments(ast_pattern, source, comments_pattern)
|
5520
5519
|
with_versions(ALL_VERSIONS) do |_ver, parser|
|
5521
|
-
source_file = Parser::Source::Buffer.new('(comments)')
|
5522
|
-
source_file.source = source
|
5520
|
+
source_file = Parser::Source::Buffer.new('(comments)', source: source)
|
5523
5521
|
|
5524
5522
|
comments_pattern_here = comments_pattern.map do |(from, to)|
|
5525
5523
|
range = Parser::Source::Range.new(source_file, from, to)
|
@@ -5550,8 +5548,8 @@ class TestParser < Minitest::Test
|
|
5550
5548
|
|
5551
5549
|
def test_tokenize
|
5552
5550
|
with_versions(ALL_VERSIONS) do |_ver, parser|
|
5553
|
-
source_file = Parser::Source::Buffer.new('(tokenize)'
|
5554
|
-
|
5551
|
+
source_file = Parser::Source::Buffer.new('(tokenize)',
|
5552
|
+
source: "1 + # foo\n 2")
|
5555
5553
|
|
5556
5554
|
range = lambda do |from, to|
|
5557
5555
|
Parser::Source::Range.new(source_file, from, to)
|
@@ -5577,8 +5575,8 @@ class TestParser < Minitest::Test
|
|
5577
5575
|
|
5578
5576
|
def test_tokenize_recover
|
5579
5577
|
with_versions(ALL_VERSIONS) do |_ver, parser|
|
5580
|
-
source_file = Parser::Source::Buffer.new('(tokenize)'
|
5581
|
-
|
5578
|
+
source_file = Parser::Source::Buffer.new('(tokenize)',
|
5579
|
+
source: "1 + # foo\n ")
|
5582
5580
|
|
5583
5581
|
range = lambda do |from, to|
|
5584
5582
|
Parser::Source::Range.new(source_file, from, to)
|
@@ -8422,7 +8420,7 @@ class TestParser < Minitest::Test
|
|
8422
8420
|
nil,
|
8423
8421
|
s(:nil)),
|
8424
8422
|
%q{in x, then nil},
|
8425
|
-
%q{
|
8423
|
+
%q{ ~~ expression (in_pattern.array_pattern_with_tail)}
|
8426
8424
|
)
|
8427
8425
|
|
8428
8426
|
assert_parses_pattern_match(
|
@@ -8468,7 +8466,7 @@ class TestParser < Minitest::Test
|
|
8468
8466
|
nil,
|
8469
8467
|
s(:nil)),
|
8470
8468
|
%q{in x, y, then nil},
|
8471
|
-
%q{
|
8469
|
+
%q{ ~~~~~ expression (in_pattern.array_pattern_with_tail)}
|
8472
8470
|
)
|
8473
8471
|
|
8474
8472
|
assert_parses_pattern_match(
|
@@ -8675,6 +8673,18 @@ class TestParser < Minitest::Test
|
|
8675
8673
|
| ~ end (in_pattern.hash_pattern)}
|
8676
8674
|
)
|
8677
8675
|
|
8676
|
+
assert_parses_pattern_match(
|
8677
|
+
s(:in_pattern,
|
8678
|
+
s(:hash_pattern,
|
8679
|
+
s(:pair, s(:sym, :a), s(:int, 1))),
|
8680
|
+
nil,
|
8681
|
+
s(:true)),
|
8682
|
+
%q{in { a: 1, } then true},
|
8683
|
+
%q{ ~~~~~~~~~ expression (in_pattern.hash_pattern)
|
8684
|
+
| ~ begin (in_pattern.hash_pattern)
|
8685
|
+
| ~ end (in_pattern.hash_pattern)}
|
8686
|
+
)
|
8687
|
+
|
8678
8688
|
assert_parses_pattern_match(
|
8679
8689
|
s(:in_pattern,
|
8680
8690
|
s(:hash_pattern,
|
@@ -8746,6 +8756,67 @@ class TestParser < Minitest::Test
|
|
8746
8756
|
%q{in a: 1, _a:, ** then true},
|
8747
8757
|
%q{ ~~~~~~~~~~~~~ expression (in_pattern.hash_pattern)}
|
8748
8758
|
)
|
8759
|
+
|
8760
|
+
assert_parses_pattern_match(
|
8761
|
+
s(:in_pattern,
|
8762
|
+
s(:hash_pattern,
|
8763
|
+
s(:pair,
|
8764
|
+
s(:sym, :a),
|
8765
|
+
s(:int, 1))), nil,
|
8766
|
+
s(:false)),
|
8767
|
+
%q{
|
8768
|
+
in {a: 1
|
8769
|
+
}
|
8770
|
+
false
|
8771
|
+
},
|
8772
|
+
%q{}
|
8773
|
+
)
|
8774
|
+
|
8775
|
+
|
8776
|
+
assert_parses_pattern_match(
|
8777
|
+
s(:in_pattern,
|
8778
|
+
s(:hash_pattern,
|
8779
|
+
s(:pair,
|
8780
|
+
s(:sym, :a),
|
8781
|
+
s(:int, 2))), nil,
|
8782
|
+
s(:false)),
|
8783
|
+
%q{
|
8784
|
+
in {a:
|
8785
|
+
2}
|
8786
|
+
false
|
8787
|
+
},
|
8788
|
+
%q{}
|
8789
|
+
)
|
8790
|
+
|
8791
|
+
assert_parses_pattern_match(
|
8792
|
+
s(:in_pattern,
|
8793
|
+
s(:hash_pattern,
|
8794
|
+
s(:pair,
|
8795
|
+
s(:sym, :a),
|
8796
|
+
s(:hash_pattern,
|
8797
|
+
s(:match_var, :b))),
|
8798
|
+
s(:match_var, :c)), nil,
|
8799
|
+
s(:send, nil, :p,
|
8800
|
+
s(:lvar, :c))),
|
8801
|
+
%q{
|
8802
|
+
in a: {b:}, c:
|
8803
|
+
p c
|
8804
|
+
},
|
8805
|
+
%q{}
|
8806
|
+
)
|
8807
|
+
|
8808
|
+
assert_parses_pattern_match(
|
8809
|
+
s(:in_pattern,
|
8810
|
+
s(:hash_pattern,
|
8811
|
+
s(:match_var, :a)), nil,
|
8812
|
+
s(:true)),
|
8813
|
+
%q{
|
8814
|
+
in {a:
|
8815
|
+
}
|
8816
|
+
true
|
8817
|
+
},
|
8818
|
+
%q{}
|
8819
|
+
)
|
8749
8820
|
end
|
8750
8821
|
|
8751
8822
|
def test_pattern_matching_hash_with_string_keys
|
@@ -8860,6 +8931,22 @@ class TestParser < Minitest::Test
|
|
8860
8931
|
%q{ ~~~~~~~ location},
|
8861
8932
|
SINCE_2_7
|
8862
8933
|
)
|
8934
|
+
|
8935
|
+
assert_diagnoses(
|
8936
|
+
[:error, :pm_interp_in_var_name],
|
8937
|
+
%q{case a; in "#{a}": 1; end},
|
8938
|
+
%q{ ~~~~~~~ location},
|
8939
|
+
SINCE_2_7
|
8940
|
+
)
|
8941
|
+
end
|
8942
|
+
|
8943
|
+
def test_pattern_matching_invalid_lvar_name
|
8944
|
+
assert_diagnoses(
|
8945
|
+
[:error, :lvar_name, { name: :a? }],
|
8946
|
+
%q{case a; in a?:; end},
|
8947
|
+
%q{ ~~ location},
|
8948
|
+
SINCE_2_7
|
8949
|
+
)
|
8863
8950
|
end
|
8864
8951
|
|
8865
8952
|
def test_pattern_matching_keyword_variable
|
@@ -8993,7 +9080,7 @@ class TestParser < Minitest::Test
|
|
8993
9080
|
nil,
|
8994
9081
|
s(:true)),
|
8995
9082
|
%q{in A(1, 2) then true},
|
8996
|
-
%q{
|
9083
|
+
%q{ ~~~~~~~ expression (in_pattern.const_pattern)
|
8997
9084
|
| ~ begin (in_pattern.const_pattern)
|
8998
9085
|
| ~ end (in_pattern.const_pattern)
|
8999
9086
|
| ~ expression (in_pattern.const_pattern.const)
|
@@ -9009,7 +9096,7 @@ class TestParser < Minitest::Test
|
|
9009
9096
|
nil,
|
9010
9097
|
s(:true)),
|
9011
9098
|
%q{in A(x:) then true},
|
9012
|
-
%q{
|
9099
|
+
%q{ ~~~~~ expression (in_pattern.const_pattern)
|
9013
9100
|
| ~ begin (in_pattern.const_pattern)
|
9014
9101
|
| ~ end (in_pattern.const_pattern)
|
9015
9102
|
| ~ expression (in_pattern.const_pattern.const)
|
@@ -9024,7 +9111,7 @@ class TestParser < Minitest::Test
|
|
9024
9111
|
nil,
|
9025
9112
|
s(:true)),
|
9026
9113
|
%q{in A() then true},
|
9027
|
-
%q{
|
9114
|
+
%q{ ~~~ expression (in_pattern.const_pattern)
|
9028
9115
|
| ~ begin (in_pattern.const_pattern)
|
9029
9116
|
| ~ end (in_pattern.const_pattern)
|
9030
9117
|
| ~ expression (in_pattern.const_pattern.const)
|
@@ -9041,7 +9128,7 @@ class TestParser < Minitest::Test
|
|
9041
9128
|
nil,
|
9042
9129
|
s(:true)),
|
9043
9130
|
%q{in A[1, 2] then true},
|
9044
|
-
%q{
|
9131
|
+
%q{ ~~~~~~~ expression (in_pattern.const_pattern)
|
9045
9132
|
| ~ begin (in_pattern.const_pattern)
|
9046
9133
|
| ~ end (in_pattern.const_pattern)
|
9047
9134
|
| ~ expression (in_pattern.const_pattern.const)
|
@@ -9057,7 +9144,7 @@ class TestParser < Minitest::Test
|
|
9057
9144
|
nil,
|
9058
9145
|
s(:true)),
|
9059
9146
|
%q{in A[x:] then true},
|
9060
|
-
%q{
|
9147
|
+
%q{ ~~~~~ expression (in_pattern.const_pattern)
|
9061
9148
|
| ~ begin (in_pattern.const_pattern)
|
9062
9149
|
| ~ end (in_pattern.const_pattern)
|
9063
9150
|
| ~ expression (in_pattern.const_pattern.const)
|
@@ -9072,7 +9159,7 @@ class TestParser < Minitest::Test
|
|
9072
9159
|
nil,
|
9073
9160
|
s(:true)),
|
9074
9161
|
%q{in A[] then true},
|
9075
|
-
%q{
|
9162
|
+
%q{ ~~~ expression (in_pattern.const_pattern)
|
9076
9163
|
| ~ begin (in_pattern.const_pattern)
|
9077
9164
|
| ~ end (in_pattern.const_pattern)
|
9078
9165
|
| ~~ expression (in_pattern.const_pattern.array_pattern)}
|
@@ -9137,8 +9224,7 @@ class TestParser < Minitest::Test
|
|
9137
9224
|
code = "case 1; #{match_code}; then [#{lvar_names.join(', ')}]; end"
|
9138
9225
|
|
9139
9226
|
with_versions(versions) do |version, parser|
|
9140
|
-
source_file = Parser::Source::Buffer.new('(assert_context)')
|
9141
|
-
source_file.source = code
|
9227
|
+
source_file = Parser::Source::Buffer.new('(assert_context)', source: code)
|
9142
9228
|
|
9143
9229
|
lvar_names.each do |lvar_name|
|
9144
9230
|
refute parser.static_env.declared?(lvar_name),
|
@@ -9148,7 +9234,7 @@ class TestParser < Minitest::Test
|
|
9148
9234
|
before = parser.static_env.instance_variable_get(:@variables).to_a
|
9149
9235
|
|
9150
9236
|
begin
|
9151
|
-
|
9237
|
+
_parsed_ast = parser.parse(source_file)
|
9152
9238
|
rescue Parser::SyntaxError => exc
|
9153
9239
|
backtrace = exc.backtrace
|
9154
9240
|
Exception.instance_method(:initialize).bind(exc).
|
@@ -9354,4 +9440,157 @@ class TestParser < Minitest::Test
|
|
9354
9440
|
%{},
|
9355
9441
|
SINCE_1_9)
|
9356
9442
|
end
|
9443
|
+
|
9444
|
+
def test_endless_method
|
9445
|
+
assert_parses(
|
9446
|
+
s(:def_e, :foo,
|
9447
|
+
s(:args),
|
9448
|
+
s(:int, 42)),
|
9449
|
+
%q{def foo() = 42},
|
9450
|
+
%q{~~~ keyword
|
9451
|
+
| ~~~ name
|
9452
|
+
| ^ assignment
|
9453
|
+
|~~~~~~~~~~~~~~ expression},
|
9454
|
+
SINCE_2_8)
|
9455
|
+
|
9456
|
+
assert_parses(
|
9457
|
+
s(:def_e, :inc,
|
9458
|
+
s(:args, s(:arg, :x)),
|
9459
|
+
s(:send,
|
9460
|
+
s(:lvar, :x), :+,
|
9461
|
+
s(:int, 1))),
|
9462
|
+
%q{def inc(x) = x + 1},
|
9463
|
+
%q{~~~ keyword
|
9464
|
+
| ~~~ name
|
9465
|
+
| ^ assignment
|
9466
|
+
|~~~~~~~~~~~~~~~~~~ expression},
|
9467
|
+
SINCE_2_8)
|
9468
|
+
|
9469
|
+
assert_parses(
|
9470
|
+
s(:defs_e, s(:send, nil, :obj), :foo,
|
9471
|
+
s(:args),
|
9472
|
+
s(:int, 42)),
|
9473
|
+
%q{def obj.foo() = 42},
|
9474
|
+
%q{~~~ keyword
|
9475
|
+
| ^ operator
|
9476
|
+
| ~~~ name
|
9477
|
+
| ^ assignment
|
9478
|
+
|~~~~~~~~~~~~~~~~~~ expression},
|
9479
|
+
SINCE_2_8)
|
9480
|
+
|
9481
|
+
assert_parses(
|
9482
|
+
s(:defs_e, s(:send, nil, :obj), :inc,
|
9483
|
+
s(:args, s(:arg, :x)),
|
9484
|
+
s(:send,
|
9485
|
+
s(:lvar, :x), :+,
|
9486
|
+
s(:int, 1))),
|
9487
|
+
%q{def obj.inc(x) = x + 1},
|
9488
|
+
%q{~~~ keyword
|
9489
|
+
| ~~~ name
|
9490
|
+
| ^ operator
|
9491
|
+
| ^ assignment
|
9492
|
+
|~~~~~~~~~~~~~~~~~~~~~~ expression},
|
9493
|
+
SINCE_2_8)
|
9494
|
+
|
9495
|
+
assert_parses(
|
9496
|
+
s(:def_e, :foo,
|
9497
|
+
s(:forward_args),
|
9498
|
+
s(:send, nil, :bar,
|
9499
|
+
s(:forwarded_args))),
|
9500
|
+
%q{def foo(...) = bar(...)},
|
9501
|
+
%q{~~~ keyword
|
9502
|
+
| ~~~ name
|
9503
|
+
| ^ assignment
|
9504
|
+
|~~~~~~~~~~~~~~~~~~~~~~~ expression},
|
9505
|
+
SINCE_2_8)
|
9506
|
+
end
|
9507
|
+
|
9508
|
+
def test_endless_method_without_brackets
|
9509
|
+
assert_diagnoses(
|
9510
|
+
[:error, :unexpected_token, { :token => 'tEQL' }],
|
9511
|
+
%Q{def foo = 42},
|
9512
|
+
%q{ ^ location},
|
9513
|
+
SINCE_2_8)
|
9514
|
+
|
9515
|
+
assert_diagnoses(
|
9516
|
+
[:error, :unexpected_token, { :token => 'tEQL' }],
|
9517
|
+
%Q{def obj.foo = 42},
|
9518
|
+
%q{ ^ location},
|
9519
|
+
SINCE_2_8
|
9520
|
+
)
|
9521
|
+
end
|
9522
|
+
|
9523
|
+
def test_endless_method_with_rescue_mod
|
9524
|
+
assert_parses(
|
9525
|
+
s(:def_e, :m,
|
9526
|
+
s(:args),
|
9527
|
+
s(:rescue,
|
9528
|
+
s(:int, 1),
|
9529
|
+
s(:resbody, nil, nil,
|
9530
|
+
s(:int, 2)), nil)),
|
9531
|
+
%q{def m() = 1 rescue 2},
|
9532
|
+
%q{},
|
9533
|
+
SINCE_2_8)
|
9534
|
+
|
9535
|
+
assert_parses(
|
9536
|
+
s(:defs_e,
|
9537
|
+
s(:self), :m,
|
9538
|
+
s(:args),
|
9539
|
+
s(:rescue,
|
9540
|
+
s(:int, 1),
|
9541
|
+
s(:resbody, nil, nil,
|
9542
|
+
s(:int, 2)), nil)),
|
9543
|
+
%q{def self.m() = 1 rescue 2},
|
9544
|
+
%q{},
|
9545
|
+
SINCE_2_8)
|
9546
|
+
end
|
9547
|
+
|
9548
|
+
def test_rasgn
|
9549
|
+
assert_parses(
|
9550
|
+
s(:rasgn,
|
9551
|
+
s(:int, 1), s(:lvasgn, :a)),
|
9552
|
+
%q{1 => a},
|
9553
|
+
%q{~~~~~~ expression
|
9554
|
+
| ^^ operator},
|
9555
|
+
SINCE_2_8)
|
9556
|
+
|
9557
|
+
assert_parses(
|
9558
|
+
s(:rasgn,
|
9559
|
+
s(:send, s(:int, 1), :+, s(:int, 2)),
|
9560
|
+
s(:gvasgn, :$a)),
|
9561
|
+
%q{1 + 2 => $a},
|
9562
|
+
%q{~~~~~~~~~~~ expression
|
9563
|
+
| ^^ operator},
|
9564
|
+
SINCE_2_8)
|
9565
|
+
end
|
9566
|
+
|
9567
|
+
def test_mrasgn
|
9568
|
+
assert_parses(
|
9569
|
+
s(:mrasgn,
|
9570
|
+
s(:send, s(:int, 13), :divmod, s(:int, 5)),
|
9571
|
+
s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b))),
|
9572
|
+
%q{13.divmod(5) => a,b},
|
9573
|
+
%q{~~~~~~~~~~~~~~~~~~~ expression
|
9574
|
+
| ^^ operator},
|
9575
|
+
SINCE_2_8)
|
9576
|
+
|
9577
|
+
assert_parses(
|
9578
|
+
s(:mrasgn,
|
9579
|
+
s(:mrasgn,
|
9580
|
+
s(:send, s(:int, 13), :divmod, s(:int, 5)),
|
9581
|
+
s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b))),
|
9582
|
+
s(:mlhs, s(:lvasgn, :c), s(:lvasgn, :d))),
|
9583
|
+
%q{13.divmod(5) => a,b => c, d},
|
9584
|
+
%q{~~~~~~~~~~~~~~~~~~~ expression (mrasgn)
|
9585
|
+
|~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression},
|
9586
|
+
SINCE_2_8)
|
9587
|
+
end
|
9588
|
+
|
9589
|
+
def test_rasgn_line_continuation
|
9590
|
+
assert_diagnoses(
|
9591
|
+
[:error, :unexpected_token, { :token => 'tASSOC' }],
|
9592
|
+
%Q{13.divmod(5)\n=> a,b; [a, b]},
|
9593
|
+
%{ ^^ location},
|
9594
|
+
SINCE_2_8)
|
9595
|
+
end
|
9357
9596
|
end
|