parser 2.7.1.5 → 2.7.2.0

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/parser/current.rb +1 -1
  3. data/lib/parser/meta.rb +2 -2
  4. data/lib/parser/ruby28.rb +8047 -0
  5. data/lib/parser/version.rb +1 -1
  6. data/parser.gemspec +1 -20
  7. metadata +7 -96
  8. data/.travis.yml +0 -41
  9. data/.yardopts +0 -21
  10. data/CHANGELOG.md +0 -1137
  11. data/CONTRIBUTING.md +0 -17
  12. data/Gemfile +0 -10
  13. data/LICENSE.txt +0 -25
  14. data/README.md +0 -309
  15. data/Rakefile +0 -167
  16. data/ci/run_rubocop_specs +0 -14
  17. data/doc/AST_FORMAT.md +0 -2284
  18. data/doc/CUSTOMIZATION.md +0 -37
  19. data/doc/INTERNALS.md +0 -21
  20. data/doc/css/.gitkeep +0 -0
  21. data/doc/css/common.css +0 -68
  22. data/lib/parser/lexer.rl +0 -2550
  23. data/lib/parser/macruby.y +0 -2208
  24. data/lib/parser/ruby18.y +0 -1936
  25. data/lib/parser/ruby19.y +0 -2185
  26. data/lib/parser/ruby20.y +0 -2363
  27. data/lib/parser/ruby21.y +0 -2364
  28. data/lib/parser/ruby22.y +0 -2371
  29. data/lib/parser/ruby23.y +0 -2377
  30. data/lib/parser/ruby24.y +0 -2415
  31. data/lib/parser/ruby25.y +0 -2412
  32. data/lib/parser/ruby26.y +0 -2420
  33. data/lib/parser/ruby27.y +0 -2949
  34. data/lib/parser/ruby30.y +0 -3048
  35. data/lib/parser/rubymotion.y +0 -2192
  36. data/test/bug_163/fixtures/input.rb +0 -5
  37. data/test/bug_163/fixtures/output.rb +0 -5
  38. data/test/bug_163/rewriter.rb +0 -20
  39. data/test/helper.rb +0 -103
  40. data/test/parse_helper.rb +0 -328
  41. data/test/racc_coverage_helper.rb +0 -133
  42. data/test/test_ast_processor.rb +0 -32
  43. data/test/test_base.rb +0 -31
  44. data/test/test_current.rb +0 -31
  45. data/test/test_diagnostic.rb +0 -95
  46. data/test/test_diagnostic_engine.rb +0 -59
  47. data/test/test_encoding.rb +0 -99
  48. data/test/test_lexer.rb +0 -3617
  49. data/test/test_lexer_stack_state.rb +0 -78
  50. data/test/test_meta.rb +0 -12
  51. data/test/test_parse_helper.rb +0 -83
  52. data/test/test_parser.rb +0 -9986
  53. data/test/test_runner_parse.rb +0 -56
  54. data/test/test_runner_rewrite.rb +0 -47
  55. data/test/test_source_buffer.rb +0 -165
  56. data/test/test_source_comment.rb +0 -36
  57. data/test/test_source_comment_associator.rb +0 -399
  58. data/test/test_source_map.rb +0 -14
  59. data/test/test_source_range.rb +0 -192
  60. data/test/test_source_rewriter.rb +0 -541
  61. data/test/test_source_rewriter_action.rb +0 -46
  62. data/test/test_source_tree_rewriter.rb +0 -361
  63. data/test/test_static_environment.rb +0 -45
  64. data/test/using_tree_rewriter/fixtures/input.rb +0 -3
  65. data/test/using_tree_rewriter/fixtures/output.rb +0 -3
  66. data/test/using_tree_rewriter/using_tree_rewriter.rb +0 -9
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- if(true)
4
- puts "Hello, world!"
5
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- if true
4
- puts "Hello, world!"
5
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Rewriter < Parser::Rewriter
4
- def on_if(node)
5
- # Crude, totally-not-usable-in-the-real-world code to remove optional
6
- # parens from control keywords.
7
- #
8
- # In a perfect test scenario we'd simply make this a no-op, to demonstrate
9
- # that the bug happens when any rewriter is loaded regardless of whether it
10
- # actually changes anything but that makes assertions much harder to get
11
- # right. It's much easier to just show that the file did, or did not
12
- # get changed.
13
- if node.children[0].type == :begin
14
- replace node.children[0].loc.begin, ' '
15
- remove node.children[0].loc.end
16
- end
17
-
18
- super
19
- end
20
- end
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'tempfile'
4
- require 'simplecov'
5
-
6
- if ENV.include?('COVERAGE') && SimpleCov.usable?
7
- require_relative 'racc_coverage_helper'
8
-
9
- RaccCoverage.start(
10
- %w(
11
- ruby18.y
12
- ruby19.y
13
- ruby20.y
14
- ruby21.y
15
- ruby22.y
16
- ruby23.y
17
- ruby24.y
18
- ruby25.y
19
- ruby26.y
20
- ruby27.y
21
- ruby30.y
22
- ),
23
- File.expand_path('../../lib/parser', __FILE__))
24
-
25
- # Report results faster.
26
- at_exit { RaccCoverage.stop }
27
-
28
- SimpleCov.start do
29
- self.formatter = SimpleCov::Formatter::MultiFormatter.new(
30
- SimpleCov::Formatter::HTMLFormatter
31
- )
32
-
33
- add_group 'Grammars' do |source_file|
34
- source_file.filename =~ %r{\.y$}
35
- end
36
-
37
- # Exclude the testsuite itself.
38
- add_filter '/test/'
39
-
40
- # Exclude generated files.
41
- add_filter do |source_file|
42
- source_file.filename =~ %r{/lib/parser/(lexer|ruby\d+|macruby|rubymotion)\.rb$}
43
- end
44
- end
45
- end
46
-
47
- # minitest/autorun must go after SimpleCov to preserve
48
- # correct order of at_exit hooks.
49
- require 'minitest/autorun'
50
-
51
- $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
52
- require 'parser'
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
-
74
- class Parser::AST::Node
75
- def initialize(type, *)
76
- NodeCollector.nodes << self
77
- super
78
- end
79
- end
80
-
81
- # Special test extension that records a context of the parser
82
- # for any node that is created
83
- module NodeContextExt
84
- module NodeExt
85
- attr_reader :context
86
-
87
- def assign_properties(properties)
88
- super
89
-
90
- if (context = properties[:context])
91
- @context = context
92
- end
93
- end
94
- end
95
- Parser::AST::Node.prepend(NodeExt)
96
-
97
- module BuilderExt
98
- def n(type, children, source_map)
99
- super.updated(nil, nil, context: @parser.context.stack.dup)
100
- end
101
- end
102
- Parser::Builders::Default.prepend(BuilderExt)
103
- end
@@ -1,328 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ParseHelper
4
- include AST::Sexp
5
-
6
- require 'parser/all'
7
- require 'parser/macruby'
8
- require 'parser/rubymotion'
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 3.0 mac ios)
11
-
12
- def setup
13
- @diagnostics = []
14
-
15
- super if defined?(super)
16
- end
17
-
18
- def parser_for_ruby_version(version)
19
- case version
20
- when '1.8' then parser = Parser::Ruby18.new
21
- when '1.9' then parser = Parser::Ruby19.new
22
- when '2.0' then parser = Parser::Ruby20.new
23
- when '2.1' then parser = Parser::Ruby21.new
24
- when '2.2' then parser = Parser::Ruby22.new
25
- when '2.3' then parser = Parser::Ruby23.new
26
- when '2.4' then parser = Parser::Ruby24.new
27
- when '2.5' then parser = Parser::Ruby25.new
28
- when '2.6' then parser = Parser::Ruby26.new
29
- when '2.7' then parser = Parser::Ruby27.new
30
- when '3.0' then parser = Parser::Ruby30.new
31
- when 'mac' then parser = Parser::MacRuby.new
32
- when 'ios' then parser = Parser::RubyMotion.new
33
- else raise "Unrecognized Ruby version #{version}"
34
- end
35
-
36
- parser.diagnostics.consumer = lambda do |diagnostic|
37
- @diagnostics << diagnostic
38
- end
39
-
40
- parser
41
- end
42
-
43
- def with_versions(versions)
44
- (versions & ALL_VERSIONS).each do |version|
45
- @diagnostics.clear
46
-
47
- parser = parser_for_ruby_version(version)
48
- yield version, parser
49
- end
50
- end
51
-
52
- def assert_source_range(expect_range, range, version, what)
53
- if expect_range == nil
54
- # Avoid "Use assert_nil if expecting nil from .... This will fail in Minitest 6.""
55
- assert_nil range,
56
- "(#{version}) range of #{what}"
57
- else
58
- assert range.is_a?(Parser::Source::Range),
59
- "(#{version}) #{range.inspect}.is_a?(Source::Range) for #{what}"
60
- assert_equal expect_range, range.to_range,
61
- "(#{version}) range of #{what}"
62
- end
63
- end
64
-
65
- # Use like this:
66
- # ~~~
67
- # assert_parses(
68
- # s(:send, s(:lit, 10), :+, s(:lit, 20))
69
- # %q{10 + 20},
70
- # %q{~~~~~~~ expression
71
- # | ^ operator
72
- # | ~~ expression (lit)
73
- # },
74
- # %w(1.8 1.9) # optional
75
- # )
76
- # ~~~
77
- def assert_parses(ast, code, source_maps='', versions=ALL_VERSIONS)
78
- with_versions(versions) do |version, parser|
79
- try_parsing(ast, code, parser, source_maps, version)
80
- end
81
-
82
- # Also try parsing with lexer set to use UTF-32LE internally
83
- with_versions(versions) do |version, parser|
84
- parser.instance_eval { @lexer.force_utf32 = true }
85
- try_parsing(ast, code, parser, source_maps, version)
86
- end
87
- end
88
-
89
- def try_parsing(ast, code, parser, source_maps, version)
90
- source_file = Parser::Source::Buffer.new('(assert_parses)', source: code)
91
-
92
- begin
93
- parsed_ast = parser.parse(source_file)
94
- rescue => exc
95
- backtrace = exc.backtrace
96
- Exception.instance_method(:initialize).bind(exc).
97
- call("(#{version}) #{exc.message}")
98
- exc.set_backtrace(backtrace)
99
- raise
100
- end
101
-
102
- if ast.nil?
103
- assert_nil parsed_ast, "(#{version}) AST equality"
104
- return
105
- end
106
-
107
- assert_equal ast, parsed_ast,
108
- "(#{version}) AST equality"
109
-
110
- parse_source_map_descriptions(source_maps) do |range, map_field, ast_path, line|
111
-
112
- astlet = traverse_ast(parsed_ast, ast_path)
113
-
114
- if astlet.nil?
115
- # This is a testsuite bug.
116
- raise "No entity with AST path #{ast_path} in #{parsed_ast.inspect}"
117
- end
118
-
119
- assert astlet.frozen?
120
-
121
- assert astlet.location.respond_to?(map_field),
122
- "(#{version}) #{astlet.location.inspect}.respond_to?(#{map_field.inspect}) for:\n#{parsed_ast.inspect}"
123
-
124
- found_range = astlet.location.send(map_field)
125
-
126
- assert_source_range(range, found_range, version, line.inspect)
127
- end
128
-
129
- assert parser.instance_eval { @lexer }.cmdarg.empty?,
130
- "(#{version}) expected cmdarg to be empty after parsing"
131
-
132
- assert_equal 0, parser.instance_eval { @lexer.instance_eval { @paren_nest } },
133
- "(#{version}) expected paren_nest to be 0 after parsing"
134
- end
135
-
136
- # Use like this:
137
- # ~~~
138
- # assert_diagnoses(
139
- # [:warning, :ambiguous_prefix, { prefix: '*' }],
140
- # %q{foo *bar},
141
- # %q{ ^ location
142
- # | ~~~ highlights (0)})
143
- # ~~~
144
- def assert_diagnoses(diagnostic, code, source_maps='', versions=ALL_VERSIONS)
145
- with_versions(versions) do |version, parser|
146
- source_file = Parser::Source::Buffer.new('(assert_diagnoses)', source: code)
147
-
148
- begin
149
- parser = parser.parse(source_file)
150
- rescue Parser::SyntaxError
151
- # do nothing; the diagnostic was reported
152
- end
153
-
154
- assert_equal 1, @diagnostics.count,
155
- "(#{version}) emits a single diagnostic, not\n" \
156
- "#{@diagnostics.map(&:render).join("\n")}"
157
-
158
- emitted_diagnostic = @diagnostics.first
159
-
160
- level, reason, arguments = diagnostic
161
- arguments ||= {}
162
- message = Parser::Messages.compile(reason, arguments)
163
-
164
- assert_equal level, emitted_diagnostic.level
165
- assert_equal reason, emitted_diagnostic.reason
166
- assert_equal arguments, emitted_diagnostic.arguments
167
- assert_equal message, emitted_diagnostic.message
168
-
169
- parse_source_map_descriptions(source_maps) do |range, map_field, ast_path, line|
170
-
171
- case map_field
172
- when 'location'
173
- assert_source_range range,
174
- emitted_diagnostic.location,
175
- version, 'location'
176
-
177
- when 'highlights'
178
- index = ast_path.first.to_i
179
-
180
- assert_source_range range,
181
- emitted_diagnostic.highlights[index],
182
- version, "#{index}th highlight"
183
-
184
- else
185
- raise "Unknown diagnostic range #{map_field}"
186
- end
187
- end
188
- end
189
- end
190
-
191
- # Use like this:
192
- # ~~~
193
- # assert_diagnoses_many(
194
- # [
195
- # [:warning, :ambiguous_literal],
196
- # [:error, :unexpected_token, { :token => :tLCURLY }]
197
- # ],
198
- # %q{m /foo/ {}},
199
- # SINCE_2_4)
200
- # ~~~
201
- def assert_diagnoses_many(diagnostics, code, versions=ALL_VERSIONS)
202
- with_versions(versions) do |version, parser|
203
- source_file = Parser::Source::Buffer.new('(assert_diagnoses_many)', source: code)
204
-
205
- begin
206
- parser = parser.parse(source_file)
207
- rescue Parser::SyntaxError
208
- # do nothing; the diagnostic was reported
209
- end
210
-
211
- assert_equal diagnostics.count, @diagnostics.count
212
-
213
- diagnostics.zip(@diagnostics) do |expected_diagnostic, actual_diagnostic|
214
- level, reason, arguments = expected_diagnostic
215
- arguments ||= {}
216
- message = Parser::Messages.compile(reason, arguments)
217
-
218
- assert_equal level, actual_diagnostic.level
219
- assert_equal reason, actual_diagnostic.reason
220
- assert_equal arguments, actual_diagnostic.arguments
221
- assert_equal message, actual_diagnostic.message
222
- end
223
- end
224
- end
225
-
226
- def refute_diagnoses(code, versions=ALL_VERSIONS)
227
- with_versions(versions) do |version, parser|
228
- source_file = Parser::Source::Buffer.new('(refute_diagnoses)', source: code)
229
-
230
- begin
231
- parser = parser.parse(source_file)
232
- rescue Parser::SyntaxError
233
- # do nothing; the diagnostic was reported
234
- end
235
-
236
- assert_empty @diagnostics,
237
- "(#{version}) emits no diagnostics, not\n" \
238
- "#{@diagnostics.map(&:render).join("\n")}"
239
- end
240
- end
241
-
242
- def assert_context(context, code, versions=ALL_VERSIONS)
243
- with_versions(versions) do |version, parser|
244
- source_file = Parser::Source::Buffer.new('(assert_context)', source: code)
245
-
246
- parsed_ast = parser.parse(source_file)
247
-
248
- nodes = find_matching_nodes(parsed_ast) { |node| node.type == :send && node.children[1] == :get_context }
249
- assert_equal 1, nodes.count, "there must exactly 1 `get_context()` call"
250
-
251
- node = nodes.first
252
- assert_equal context, node.context, "(#{version}) expect parsing context to match"
253
- end
254
- end
255
-
256
- SOURCE_MAP_DESCRIPTION_RE =
257
- /(?x)
258
- ^(?# $1 skip) ^(\s*)
259
- (?# $2 highlight) ([~\^]+|\!)
260
- \s+
261
- (?# $3 source_map_field) ([a-z_]+)
262
- (?# $5 ast_path) (\s+\(([a-z_.\/0-9]+)\))?
263
- $/
264
-
265
- def parse_source_map_descriptions(descriptions)
266
- unless block_given?
267
- return to_enum(:parse_source_map_descriptions, descriptions)
268
- end
269
-
270
- descriptions.each_line do |line|
271
- # Remove leading " |", if it exists.
272
- line = line.sub(/^\s*\|/, '').rstrip
273
-
274
- next if line.empty?
275
-
276
- if (match = SOURCE_MAP_DESCRIPTION_RE.match(line))
277
- if match[2] != '!'
278
- begin_pos = match[1].length
279
- end_pos = begin_pos + match[2].length
280
- range = begin_pos...end_pos
281
- end
282
- source_map_field = match[3]
283
-
284
- if match[5]
285
- ast_path = match[5].split('.')
286
- else
287
- ast_path = []
288
- end
289
-
290
- yield range, source_map_field, ast_path, line
291
- else
292
- raise "Cannot parse source map description line: #{line.inspect}."
293
- end
294
- end
295
- end
296
-
297
- def traverse_ast(ast, path)
298
- path.inject(ast) do |astlet, path_component|
299
- # Split "dstr/2" to :dstr and 1
300
- type_str, index_str = path_component.split('/')
301
-
302
- type = type_str.to_sym
303
-
304
- if index_str.nil?
305
- index = 0
306
- else
307
- index = index_str.to_i - 1
308
- end
309
-
310
- matching_children = \
311
- astlet.children.select do |child|
312
- AST::Node === child && child.type == type
313
- end
314
-
315
- matching_children[index]
316
- end
317
- end
318
-
319
- def find_matching_nodes(ast, &block)
320
- return [] unless ast.is_a?(AST::Node)
321
-
322
- result = []
323
- result << ast if block.call(ast)
324
- ast.children.each { |child| result += find_matching_nodes(child, &block) }
325
-
326
- result
327
- end
328
- end