parser 2.6.0.0 → 3.1.0.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/lib/parser/all.rb +3 -0
  3. data/lib/parser/ast/processor.rb +48 -1
  4. data/lib/parser/base.rb +30 -6
  5. data/lib/parser/builders/default.rb +670 -38
  6. data/lib/parser/context.rb +24 -26
  7. data/lib/parser/current.rb +36 -9
  8. data/lib/parser/current_arg_stack.rb +46 -0
  9. data/lib/parser/diagnostic/engine.rb +1 -2
  10. data/lib/parser/diagnostic.rb +1 -1
  11. data/lib/parser/lexer/dedenter.rb +58 -49
  12. data/lib/parser/lexer/explanation.rb +1 -1
  13. data/lib/parser/lexer.rb +13837 -11893
  14. data/lib/parser/macruby.rb +2544 -2489
  15. data/lib/parser/max_numparam_stack.rb +56 -0
  16. data/lib/parser/messages.rb +78 -44
  17. data/lib/parser/meta.rb +13 -3
  18. data/lib/parser/ruby18.rb +2313 -2259
  19. data/lib/parser/ruby19.rb +2537 -2488
  20. data/lib/parser/ruby20.rb +2724 -2673
  21. data/lib/parser/ruby21.rb +2766 -2727
  22. data/lib/parser/ruby22.rb +2683 -2628
  23. data/lib/parser/ruby23.rb +2796 -2755
  24. data/lib/parser/ruby24.rb +2812 -2771
  25. data/lib/parser/ruby25.rb +2703 -2670
  26. data/lib/parser/ruby26.rb +2794 -2747
  27. data/lib/parser/ruby27.rb +7914 -0
  28. data/lib/parser/ruby28.rb +8047 -0
  29. data/lib/parser/ruby30.rb +8096 -0
  30. data/lib/parser/ruby31.rb +8354 -0
  31. data/lib/parser/rubymotion.rb +2527 -2485
  32. data/lib/parser/runner/ruby_parse.rb +2 -2
  33. data/lib/parser/runner/ruby_rewrite.rb +2 -2
  34. data/lib/parser/runner.rb +36 -2
  35. data/lib/parser/source/buffer.rb +53 -28
  36. data/lib/parser/source/comment/associator.rb +31 -8
  37. data/lib/parser/source/comment.rb +14 -1
  38. data/lib/parser/source/map/method_definition.rb +25 -0
  39. data/lib/parser/source/range.rb +19 -3
  40. data/lib/parser/source/tree_rewriter/action.rb +137 -28
  41. data/lib/parser/source/tree_rewriter.rb +144 -14
  42. data/lib/parser/static_environment.rb +23 -0
  43. data/lib/parser/tree_rewriter.rb +3 -3
  44. data/lib/parser/variables_stack.rb +36 -0
  45. data/lib/parser/version.rb +1 -1
  46. data/lib/parser.rb +4 -0
  47. data/parser.gemspec +12 -19
  48. metadata +34 -99
  49. data/.gitignore +0 -32
  50. data/.travis.yml +0 -45
  51. data/.yardopts +0 -21
  52. data/CHANGELOG.md +0 -943
  53. data/CONTRIBUTING.md +0 -17
  54. data/Gemfile +0 -10
  55. data/README.md +0 -301
  56. data/Rakefile +0 -165
  57. data/ci/run_rubocop_specs +0 -14
  58. data/doc/AST_FORMAT.md +0 -1735
  59. data/doc/CUSTOMIZATION.md +0 -37
  60. data/doc/INTERNALS.md +0 -21
  61. data/doc/css/.gitkeep +0 -0
  62. data/doc/css/common.css +0 -68
  63. data/lib/parser/lexer.rl +0 -2383
  64. data/lib/parser/macruby.y +0 -2198
  65. data/lib/parser/ruby18.y +0 -1934
  66. data/lib/parser/ruby19.y +0 -2175
  67. data/lib/parser/ruby20.y +0 -2353
  68. data/lib/parser/ruby21.y +0 -2357
  69. data/lib/parser/ruby22.y +0 -2364
  70. data/lib/parser/ruby23.y +0 -2370
  71. data/lib/parser/ruby24.y +0 -2408
  72. data/lib/parser/ruby25.y +0 -2405
  73. data/lib/parser/ruby26.y +0 -2413
  74. data/lib/parser/rubymotion.y +0 -2182
  75. data/test/bug_163/fixtures/input.rb +0 -5
  76. data/test/bug_163/fixtures/output.rb +0 -5
  77. data/test/bug_163/rewriter.rb +0 -20
  78. data/test/helper.rb +0 -52
  79. data/test/parse_helper.rb +0 -315
  80. data/test/racc_coverage_helper.rb +0 -133
  81. data/test/test_base.rb +0 -31
  82. data/test/test_current.rb +0 -27
  83. data/test/test_diagnostic.rb +0 -96
  84. data/test/test_diagnostic_engine.rb +0 -62
  85. data/test/test_encoding.rb +0 -99
  86. data/test/test_lexer.rb +0 -3543
  87. data/test/test_lexer_stack_state.rb +0 -78
  88. data/test/test_parse_helper.rb +0 -80
  89. data/test/test_parser.rb +0 -7087
  90. data/test/test_runner_rewrite.rb +0 -47
  91. data/test/test_source_buffer.rb +0 -162
  92. data/test/test_source_comment.rb +0 -36
  93. data/test/test_source_comment_associator.rb +0 -367
  94. data/test/test_source_map.rb +0 -15
  95. data/test/test_source_range.rb +0 -172
  96. data/test/test_source_rewriter.rb +0 -541
  97. data/test/test_source_rewriter_action.rb +0 -46
  98. data/test/test_source_tree_rewriter.rb +0 -173
  99. data/test/test_static_environment.rb +0 -45
  100. data/test/using_tree_rewriter/fixtures/input.rb +0 -3
  101. data/test/using_tree_rewriter/fixtures/output.rb +0 -3
  102. 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
data/test/helper.rb DELETED
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'tempfile'
4
- require 'minitest/test'
5
-
6
- require 'simplecov'
7
-
8
- if ENV.include?('COVERAGE') && SimpleCov.usable?
9
- require_relative 'racc_coverage_helper'
10
-
11
- RaccCoverage.start(
12
- %w(
13
- ruby18.y
14
- ruby19.y
15
- ruby20.y
16
- ruby21.y
17
- ruby22.y
18
- ruby23.y
19
- ruby24.y
20
- ruby25.y
21
- ruby26.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[
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'
data/test/parse_helper.rb DELETED
@@ -1,315 +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 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 'mac' then parser = Parser::MacRuby.new
30
- when 'ios' then parser = Parser::RubyMotion.new
31
- else raise "Unrecognized Ruby version #{version}"
32
- end
33
-
34
- parser.diagnostics.consumer = lambda do |diagnostic|
35
- @diagnostics << diagnostic
36
- end
37
-
38
- parser
39
- end
40
-
41
- def with_versions(versions)
42
- (versions & ALL_VERSIONS).each do |version|
43
- @diagnostics.clear
44
-
45
- parser = parser_for_ruby_version(version)
46
- yield version, parser
47
- end
48
- end
49
-
50
- def assert_source_range(begin_pos, end_pos, range, version, what)
51
- assert range.is_a?(Parser::Source::Range),
52
- "(#{version}) #{range.inspect}.is_a?(Source::Range) for #{what}"
53
-
54
- assert_equal begin_pos, range.begin_pos,
55
- "(#{version}) begin of #{what}"
56
-
57
- assert_equal end_pos, range.end_pos,
58
- "(#{version}) end of #{what}"
59
- end
60
-
61
- # Use like this:
62
- # ~~~
63
- # assert_parses(
64
- # s(:send, s(:lit, 10), :+, s(:lit, 20))
65
- # %q{10 + 20},
66
- # %q{~~~~~~~ expression
67
- # | ^ operator
68
- # | ~~ expression (lit)
69
- # },
70
- # %w(1.8 1.9) # optional
71
- # )
72
- # ~~~
73
- def assert_parses(ast, code, source_maps='', versions=ALL_VERSIONS)
74
- with_versions(versions) do |version, parser|
75
- try_parsing(ast, code, parser, source_maps, version)
76
- end
77
-
78
- # Also try parsing with lexer set to use UTF-32LE internally
79
- with_versions(versions) do |version, parser|
80
- parser.instance_eval { @lexer.force_utf32 = true }
81
- try_parsing(ast, code, parser, source_maps, version)
82
- end
83
- end
84
-
85
- def try_parsing(ast, code, parser, source_maps, version)
86
- source_file = Parser::Source::Buffer.new('(assert_parses)')
87
- source_file.source = code
88
-
89
- begin
90
- parsed_ast = parser.parse(source_file)
91
- rescue => exc
92
- backtrace = exc.backtrace
93
- Exception.instance_method(:initialize).bind(exc).
94
- call("(#{version}) #{exc.message}")
95
- exc.set_backtrace(backtrace)
96
- raise
97
- end
98
-
99
- if ast.nil?
100
- assert_nil parsed_ast, "(#{version}) AST equality"
101
- return
102
- end
103
-
104
- assert_equal ast, parsed_ast,
105
- "(#{version}) AST equality"
106
-
107
- parse_source_map_descriptions(source_maps) \
108
- do |begin_pos, end_pos, map_field, ast_path, line|
109
-
110
- astlet = traverse_ast(parsed_ast, ast_path)
111
-
112
- if astlet.nil?
113
- # This is a testsuite bug.
114
- raise "No entity with AST path #{ast_path} in #{parsed_ast.inspect}"
115
- end
116
-
117
- assert astlet.frozen?
118
-
119
- assert astlet.location.respond_to?(map_field),
120
- "(#{version}) #{astlet.location.inspect}.respond_to?(#{map_field.inspect}) for:\n#{parsed_ast.inspect}"
121
-
122
- range = astlet.location.send(map_field)
123
-
124
- assert_source_range(begin_pos, end_pos, range, version, line.inspect)
125
- end
126
-
127
- assert parser.instance_eval { @lexer }.cmdarg.empty?,
128
- "(#{version}) expected cmdarg to be empty after parsing"
129
- end
130
-
131
- # Use like this:
132
- # ~~~
133
- # assert_diagnoses(
134
- # [:warning, :ambiguous_prefix, { prefix: '*' }],
135
- # %q{foo *bar},
136
- # %q{ ^ location
137
- # | ~~~ highlights (0)})
138
- # ~~~
139
- def assert_diagnoses(diagnostic, code, source_maps='', versions=ALL_VERSIONS)
140
- with_versions(versions) do |version, parser|
141
- source_file = Parser::Source::Buffer.new('(assert_diagnoses)')
142
- source_file.source = code
143
-
144
- begin
145
- parser = parser.parse(source_file)
146
- rescue Parser::SyntaxError
147
- # do nothing; the diagnostic was reported
148
- end
149
-
150
- assert_equal 1, @diagnostics.count,
151
- "(#{version}) emits a single diagnostic, not\n" \
152
- "#{@diagnostics.map(&:render).join("\n")}"
153
-
154
- emitted_diagnostic = @diagnostics.first
155
-
156
- level, reason, arguments = diagnostic
157
- arguments ||= {}
158
- message = Parser::MESSAGES[reason] % arguments
159
-
160
- assert_equal level, emitted_diagnostic.level
161
- assert_equal reason, emitted_diagnostic.reason
162
- assert_equal arguments, emitted_diagnostic.arguments
163
- assert_equal message, emitted_diagnostic.message
164
-
165
- parse_source_map_descriptions(source_maps) \
166
- do |begin_pos, end_pos, map_field, ast_path, line|
167
-
168
- case map_field
169
- when 'location'
170
- assert_source_range begin_pos, end_pos,
171
- emitted_diagnostic.location,
172
- version, 'location'
173
-
174
- when 'highlights'
175
- index = ast_path.first.to_i
176
-
177
- assert_source_range begin_pos, end_pos,
178
- emitted_diagnostic.highlights[index],
179
- version, "#{index}th highlight"
180
-
181
- else
182
- raise "Unknown diagnostic range #{map_field}"
183
- end
184
- end
185
- end
186
- end
187
-
188
- # Use like this:
189
- # ~~~
190
- # assert_diagnoses_many(
191
- # [
192
- # [:warning, :ambiguous_literal],
193
- # [:error, :unexpected_token, { :token => :tLCURLY }]
194
- # ],
195
- # %q{m /foo/ {}},
196
- # SINCE_2_4)
197
- # ~~~
198
- def assert_diagnoses_many(diagnostics, code, versions=ALL_VERSIONS)
199
- with_versions(versions) do |version, parser|
200
- source_file = Parser::Source::Buffer.new('(assert_diagnoses_many)')
201
- source_file.source = code
202
-
203
- begin
204
- parser = parser.parse(source_file)
205
- rescue Parser::SyntaxError
206
- # do nothing; the diagnostic was reported
207
- end
208
-
209
- assert_equal diagnostics.count, @diagnostics.count
210
-
211
- diagnostics.zip(@diagnostics) do |expected_diagnostic, actual_diagnostic|
212
- level, reason, arguments = expected_diagnostic
213
- arguments ||= {}
214
- message = Parser::MESSAGES[reason] % arguments
215
-
216
- assert_equal level, actual_diagnostic.level
217
- assert_equal reason, actual_diagnostic.reason
218
- assert_equal arguments, actual_diagnostic.arguments
219
- assert_equal message, actual_diagnostic.message
220
- end
221
- end
222
- end
223
-
224
- def refute_diagnoses(code, versions=ALL_VERSIONS)
225
- with_versions(versions) do |version, parser|
226
- source_file = Parser::Source::Buffer.new('(refute_diagnoses)')
227
- source_file.source = code
228
-
229
- begin
230
- parser = parser.parse(source_file)
231
- rescue Parser::SyntaxError
232
- # do nothing; the diagnostic was reported
233
- end
234
-
235
- assert_empty @diagnostics,
236
- "(#{version}) emits no diagnostics, not\n" \
237
- "#{@diagnostics.map(&:render).join("\n")}"
238
- end
239
- end
240
-
241
- def assert_context(context, code, versions=ALL_VERSIONS)
242
- with_versions(versions) do |version, parser|
243
- source_file = Parser::Source::Buffer.new('(assert_context)')
244
- source_file.source = code
245
-
246
- begin
247
- parser.parse(source_file)
248
- rescue Parser::SyntaxError
249
- # do nothing; the diagnostic was reported
250
- end
251
-
252
- assert_equal parser.context.stack, context, "(#{version}) parsing context"
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
- begin_pos = match[1].length
278
- end_pos = begin_pos + match[2].length
279
- source_map_field = match[3]
280
-
281
- if match[5]
282
- ast_path = match[5].split('.')
283
- else
284
- ast_path = []
285
- end
286
-
287
- yield begin_pos, end_pos, source_map_field, ast_path, line
288
- else
289
- raise "Cannot parse source map description line: #{line.inspect}."
290
- end
291
- end
292
- end
293
-
294
- def traverse_ast(ast, path)
295
- path.inject(ast) do |astlet, path_component|
296
- # Split "dstr/2" to :dstr and 1
297
- type_str, index_str = path_component.split('/')
298
-
299
- type = type_str.to_sym
300
-
301
- if index_str.nil?
302
- index = 0
303
- else
304
- index = index_str.to_i - 1
305
- end
306
-
307
- matching_children = \
308
- astlet.children.select do |child|
309
- AST::Node === child && child.type == type
310
- end
311
-
312
- matching_children[index]
313
- end
314
- end
315
- end
@@ -1,133 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'racc/grammarfileparser'
4
-
5
- # Unfortunately, Ruby's Coverage module ignores module_eval statements,
6
- # which Racc uses to map `parser.y` locations in the generated
7
- # `parser.rb`.
8
- module RaccCoverage
9
- @coverage = {}
10
- @base_path = nil
11
- @trace = nil
12
-
13
- def self.start(parsers, base_path)
14
- @base_path = base_path
15
-
16
- parsers.each do |parser|
17
- @coverage[parser] = extract_interesting_lines(parser, base_path)
18
- end
19
-
20
- @trace = TracePoint.new(:line) do |trace|
21
- lineno = trace.lineno - 1
22
-
23
- if (line_coverage = @coverage[trace.path])
24
- if line_coverage[lineno]
25
- line_coverage[lineno] += 1
26
- end
27
- end
28
- end
29
- @trace.enable
30
- end
31
-
32
- def self.stop
33
- @trace.disable
34
- end
35
-
36
- # Ruby's TracePoint#lineno will point only on "interesting" lines,
37
- # i.e.: only code (no comments or empty lines), no `end` keywords,
38
- # and for multi-line statements, only the first line of the statement.
39
- #
40
- # This method implements a very dumb Ruby parser, which skips empty lines
41
- # or lines with just comments, `end` keywords, and correctly handles
42
- # multi-line statements of the following form:
43
- #
44
- # * All lines of the statement except the last must end with `,`, `.` or `(`.
45
- #
46
- # Coverage can be disabled for code regions with annotations :nocov: and :cov:.
47
- #
48
- # Also, for best results, all actions should be delimited by at least
49
- # one non-action line.
50
- #
51
- def self.extract_interesting_lines(parser, base_path)
52
- grammar_source = File.join(@base_path, parser)
53
- grammar_file = Racc::GrammarFileParser.parse_file(grammar_source)
54
-
55
- ruby_sources = [
56
- # Header and footer aren't passed through module_eval
57
- # in Racc-generated file, so the location info is lost.
58
- *grammar_file.params.inner,
59
- ].compact
60
-
61
- grammar_file.grammar.each_rule do |rule|
62
- source = rule.action.source
63
- next if source.nil?
64
-
65
- ruby_sources << source
66
- end
67
-
68
- lines = []
69
-
70
- ruby_sources.each do |source|
71
- first_line = source.lineno
72
-
73
- state = :first_line
74
-
75
- source.text.each_line.with_index do |line, index|
76
- line = line.strip
77
-
78
- continues = line.end_with?(',') ||
79
- line.end_with?('(') ||
80
- line.end_with?('.')
81
-
82
- case state
83
- when :first_line
84
- if line =~ /:nocov/
85
- state = :nocov
86
- next
87
- elsif line.empty? ||
88
- line == 'end' ||
89
- line.start_with?('#')
90
- next
91
- elsif continues
92
- state = :mid_line
93
- end
94
-
95
- lines[first_line + index - 1] = 0
96
-
97
- when :mid_line
98
- unless continues
99
- state = :first_line
100
- end
101
-
102
- when :nocov
103
- if line =~ /:cov:/
104
- state = :first_line
105
- end
106
- end
107
- end
108
- end
109
-
110
- lines
111
- end
112
-
113
- def self.result
114
- result =
115
- @coverage.map do |parser, coverage|
116
- [File.join(@base_path, parser), coverage]
117
- end
118
-
119
- Hash[result]
120
- end
121
- end
122
-
123
- class << SimpleCov
124
- def result_with_racc_coverage
125
- @result ||= SimpleCov::Result.new(
126
- Coverage.result.merge(RaccCoverage.result))
127
-
128
- result_without_racc_coverage
129
- end
130
-
131
- alias result_without_racc_coverage result
132
- alias result result_with_racc_coverage
133
- end
data/test/test_base.rb DELETED
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'helper'
4
- require 'parser/current'
5
-
6
- class TestBase < Minitest::Test
7
- include AST::Sexp
8
-
9
- def test_parse
10
- ast = Parser::CurrentRuby.parse('1')
11
- assert_equal s(:int, 1), ast
12
- end
13
-
14
- def test_parse_with_comments
15
- ast, comments = Parser::CurrentRuby.parse_with_comments('1 # foo')
16
- assert_equal s(:int, 1), ast
17
- assert_equal 1, comments.size
18
- assert_equal '# foo', comments.first.text
19
- end
20
-
21
- def test_loc_to_node
22
- ast = Parser::CurrentRuby.parse('1')
23
- assert_equal ast.loc.node, ast
24
- end
25
-
26
- def test_loc_dup
27
- ast = Parser::CurrentRuby.parse('1')
28
- assert_nil ast.loc.dup.node
29
- Parser::AST::Node.new(:root, [], :location => ast.loc)
30
- end
31
- end
data/test/test_current.rb DELETED
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'helper'
4
- require 'parser/current'
5
-
6
- class TestCurrent < Minitest::Test
7
- def test_current
8
- case RUBY_VERSION
9
- when '2.0.0'
10
- assert_equal Parser::Ruby20, Parser::CurrentRuby
11
- when /^2\.1\.\d+/
12
- assert_equal Parser::Ruby21, Parser::CurrentRuby
13
- when /^2\.2\.\d+/
14
- assert_equal Parser::Ruby22, Parser::CurrentRuby
15
- when /^2\.3\.\d+/
16
- assert_equal Parser::Ruby23, Parser::CurrentRuby
17
- when /^2\.4\.\d+/
18
- assert_equal Parser::Ruby24, Parser::CurrentRuby
19
- when /^2\.5\.\d+/
20
- assert_equal Parser::Ruby25, Parser::CurrentRuby
21
- when /^2\.6\.\d+/
22
- assert_equal Parser::Ruby26, Parser::CurrentRuby
23
- else
24
- flunk "Update test_current for #{RUBY_VERSION}"
25
- end
26
- end
27
- end
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'helper'
4
-
5
- class TestDiagnostic < Minitest::Test
6
- def setup
7
- @buffer = Parser::Source::Buffer.new('(string)')
8
- @buffer.source = 'if (this is some bad code + bugs)'
9
-
10
- @range1 = Parser::Source::Range.new(@buffer, 0, 2) # if
11
- @range2 = Parser::Source::Range.new(@buffer, 4, 8) # this
12
- end
13
-
14
- def test_verifies_levels
15
- error = assert_raises ArgumentError do
16
- Parser::Diagnostic.new(:foobar, :escape_eof, {}, @range1)
17
- end
18
-
19
- assert_match /level/, error.message
20
- end
21
-
22
- def test_freezes
23
- string = 'foo'.dup
24
- highlights = [@range2]
25
-
26
- diag = Parser::Diagnostic.new(:error, :escape_eof, @range1, highlights)
27
- assert diag.frozen?
28
- assert diag.arguments.frozen?
29
- assert diag.highlights.frozen?
30
-
31
- refute string.frozen?
32
- refute highlights.frozen?
33
- end
34
-
35
- def test_render
36
- location = Parser::Source::Range.new(@buffer, 26, 27)
37
-
38
- highlights = [
39
- Parser::Source::Range.new(@buffer, 21, 25),
40
- Parser::Source::Range.new(@buffer, 28, 32)
41
- ]
42
-
43
- diag = Parser::Diagnostic.new(:error, :unexpected, { :character => '+' },
44
- location, highlights)
45
- assert_equal([
46
- "(string):1:27: error: unexpected `+'",
47
- '(string):1: if (this is some bad code + bugs)',
48
- '(string):1: ~~~~ ^ ~~~~ '
49
- ], diag.render)
50
- end
51
-
52
- def test_multiline_render
53
- @buffer = Parser::Source::Buffer.new('(string)')
54
- @buffer.source = "abc abc abc\ndef def def\nghi ghi ghi\n"
55
-
56
- location = Parser::Source::Range.new(@buffer, 4, 27)
57
-
58
- highlights = [
59
- Parser::Source::Range.new(@buffer, 0, 3),
60
- Parser::Source::Range.new(@buffer, 28, 31)
61
- ]
62
-
63
- diag = Parser::Diagnostic.new(:error, :unexpected_token, { :token => 'ghi' },
64
- location, highlights)
65
-
66
- assert_equal([
67
- "(string):1:5-3:3: error: unexpected token ghi",
68
- '(string):1: abc abc abc',
69
- '(string):1: ~~~ ^~~~~~~...',
70
- '(string):3: ghi ghi ghi',
71
- '(string):3: ~~~ ~~~ '
72
- ], diag.render)
73
- end
74
-
75
- def test_bug_error_on_newline
76
- # regression test; see GitHub issue 273
77
- source = <<-CODE
78
- {
79
- foo: ->() # I forgot my brace
80
- }
81
- }
82
- CODE
83
- @buffer = Parser::Source::Buffer.new('(string)')
84
- @buffer.source = source
85
-
86
- location = Parser::Source::Range.new(@buffer, 33, 34)
87
- diag = Parser::Diagnostic.new(:error, :unexpected_token, { :token => 'tNL' },
88
- location)
89
-
90
- assert_equal([
91
- '(string):2:32: error: unexpected token tNL',
92
- '(string):2: foo: ->() # I forgot my brace',
93
- '(string):2: ^'
94
- ], diag.render)
95
- end
96
- end