ruby_parser 3.0.0 → 3.19.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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.autotest +36 -19
  4. data/History.rdoc +1297 -0
  5. data/Manifest.txt +35 -7
  6. data/{README.txt → README.rdoc} +44 -14
  7. data/Rakefile +308 -110
  8. data/bin/ruby_parse +3 -1
  9. data/bin/ruby_parse_extract_error +36 -16
  10. data/compare/normalize.rb +218 -0
  11. data/debugging.md +190 -0
  12. data/gauntlet.md +107 -0
  13. data/lib/.document +1 -0
  14. data/lib/rp_extensions.rb +53 -0
  15. data/lib/rp_stringscanner.rb +33 -0
  16. data/lib/ruby20_parser.rb +10973 -0
  17. data/lib/ruby20_parser.y +2683 -0
  18. data/lib/ruby21_parser.rb +10980 -0
  19. data/lib/ruby21_parser.y +2700 -0
  20. data/lib/ruby22_parser.rb +11123 -0
  21. data/lib/ruby22_parser.y +2711 -0
  22. data/lib/ruby23_parser.rb +11132 -0
  23. data/lib/ruby23_parser.y +2713 -0
  24. data/lib/ruby24_parser.rb +11231 -0
  25. data/lib/ruby24_parser.y +2721 -0
  26. data/lib/ruby25_parser.rb +11231 -0
  27. data/lib/ruby25_parser.y +2721 -0
  28. data/lib/ruby26_parser.rb +11253 -0
  29. data/lib/ruby26_parser.y +2736 -0
  30. data/lib/ruby27_parser.rb +12980 -0
  31. data/lib/ruby27_parser.y +3324 -0
  32. data/lib/ruby30_parser.rb +13242 -0
  33. data/lib/ruby30_parser.y +3447 -0
  34. data/lib/ruby31_parser.rb +13622 -0
  35. data/lib/ruby31_parser.y +3481 -0
  36. data/lib/ruby3_parser.yy +3536 -0
  37. data/lib/ruby_lexer.rb +933 -1232
  38. data/lib/ruby_lexer.rex +185 -0
  39. data/lib/ruby_lexer.rex.rb +399 -0
  40. data/lib/ruby_lexer_strings.rb +638 -0
  41. data/lib/ruby_parser.rb +97 -3
  42. data/lib/ruby_parser.yy +3465 -0
  43. data/lib/ruby_parser_extras.rb +1216 -687
  44. data/test/test_ruby_lexer.rb +2249 -1092
  45. data/test/test_ruby_parser.rb +5156 -975
  46. data/test/test_ruby_parser_extras.rb +47 -77
  47. data/tools/munge.rb +250 -0
  48. data/tools/ripper.rb +44 -0
  49. data.tar.gz.sig +1 -1
  50. metadata +200 -155
  51. metadata.gz.sig +0 -0
  52. data/.gemtest +0 -0
  53. data/History.txt +0 -482
  54. data/lib/gauntlet_rubyparser.rb +0 -120
  55. data/lib/ruby18_parser.rb +0 -5747
  56. data/lib/ruby18_parser.y +0 -1873
  57. data/lib/ruby19_parser.rb +0 -6110
  58. data/lib/ruby19_parser.y +0 -2078
data/Manifest.txt CHANGED
@@ -1,18 +1,46 @@
1
1
  .autotest
2
- History.txt
2
+ History.rdoc
3
3
  Manifest.txt
4
- README.txt
4
+ README.rdoc
5
5
  Rakefile
6
6
  bin/ruby_parse
7
7
  bin/ruby_parse_extract_error
8
- lib/gauntlet_rubyparser.rb
9
- lib/ruby18_parser.rb
10
- lib/ruby18_parser.y
11
- lib/ruby19_parser.rb
12
- lib/ruby19_parser.y
8
+ compare/normalize.rb
9
+ debugging.md
10
+ gauntlet.md
11
+ lib/.document
12
+ lib/rp_extensions.rb
13
+ lib/rp_stringscanner.rb
14
+ lib/ruby20_parser.rb
15
+ lib/ruby20_parser.y
16
+ lib/ruby21_parser.rb
17
+ lib/ruby21_parser.y
18
+ lib/ruby22_parser.rb
19
+ lib/ruby22_parser.y
20
+ lib/ruby23_parser.rb
21
+ lib/ruby23_parser.y
22
+ lib/ruby24_parser.rb
23
+ lib/ruby24_parser.y
24
+ lib/ruby25_parser.rb
25
+ lib/ruby25_parser.y
26
+ lib/ruby26_parser.rb
27
+ lib/ruby26_parser.y
28
+ lib/ruby27_parser.rb
29
+ lib/ruby27_parser.y
30
+ lib/ruby30_parser.rb
31
+ lib/ruby30_parser.y
32
+ lib/ruby31_parser.rb
33
+ lib/ruby31_parser.y
34
+ lib/ruby3_parser.yy
13
35
  lib/ruby_lexer.rb
36
+ lib/ruby_lexer.rex
37
+ lib/ruby_lexer.rex.rb
38
+ lib/ruby_lexer_strings.rb
14
39
  lib/ruby_parser.rb
40
+ lib/ruby_parser.yy
15
41
  lib/ruby_parser_extras.rb
16
42
  test/test_ruby_lexer.rb
17
43
  test/test_ruby_parser.rb
18
44
  test/test_ruby_parser_extras.rb
45
+ tools/munge.rb
46
+ tools/ripper.rb
@@ -7,25 +7,35 @@ rdoc :: http://docs.seattlerb.org/ruby_parser
7
7
  == DESCRIPTION:
8
8
 
9
9
  ruby_parser (RP) is a ruby parser written in pure ruby (utilizing
10
- racc--which does by default use a C extension). RP's output is
11
- the same as ParseTree's output: s-expressions using ruby's arrays and
12
- base types.
10
+ racc--which does by default use a C extension). It outputs
11
+ s-expressions which can be manipulated and converted back to ruby via
12
+ the ruby2ruby gem.
13
13
 
14
14
  As an example:
15
15
 
16
- def conditional1 arg1
17
- return 1 if arg1 == 0
18
- return 0
19
- end
16
+ def conditional1 arg1
17
+ return 1 if arg1 == 0
18
+ return 0
19
+ end
20
20
 
21
21
  becomes:
22
22
 
23
- s(:defn, :conditional1, s(:args, :arg1),
24
- s(:if,
25
- s(:call, s(:lvar, :arg1), :==, s(:lit, 0)),
26
- s(:return, s(:lit, 1)),
27
- nil),
28
- s(:return, s(:lit, 0)))
23
+ s(:defn, :conditional1, s(:args, :arg1),
24
+ s(:if,
25
+ s(:call, s(:lvar, :arg1), :==, s(:lit, 0)),
26
+ s(:return, s(:lit, 1)),
27
+ nil),
28
+ s(:return, s(:lit, 0)))
29
+
30
+ Tested against 801,039 files from the latest of all rubygems (as of 2013-05):
31
+
32
+ * 1.8 parser is at 99.9739% accuracy, 3.651 sigma
33
+ * 1.9 parser is at 99.9940% accuracy, 4.013 sigma
34
+ * 2.0 parser is at 99.9939% accuracy, 4.008 sigma
35
+ * 2.6 parser is at 99.9972% accuracy, 4.191 sigma
36
+ * 3.0 parser has a 100% parse rate.
37
+ * Tested against 2,672,412 unique ruby files across 167k gems.
38
+ * As do all the others now, basically.
29
39
 
30
40
  == FEATURES/PROBLEMS:
31
41
 
@@ -43,9 +53,29 @@ becomes:
43
53
 
44
54
  == SYNOPSIS:
45
55
 
46
- Ruby19Parser.new.parse "1+1"
56
+ RubyParser.new.parse "1+1"
57
+ # => s(:call, s(:lit, 1), :+, s(:lit, 1))
58
+
59
+ You can also use Ruby19Parser, Ruby18Parser, or RubyParser.for_current_ruby:
60
+
61
+ RubyParser.for_current_ruby.parse "1+1"
47
62
  # => s(:call, s(:lit, 1), :+, s(:lit, 1))
48
63
 
64
+ == DEVELOPER NOTES:
65
+
66
+ To add a new version:
67
+
68
+ * New parser should be generated from lib/ruby[3]_parser.yy.
69
+ * Extend lib/ruby[3]_parser.yy with new class name.
70
+ * Add new version number to V2/V3 in Rakefile for rule creation.
71
+ * Add new (full) version to `ruby_parse` section of Rakefile for rake compare
72
+ * Require generated parser in lib/ruby_parser.rb.
73
+ * Add empty TestRubyParserShared##Plus module and TestRubyParserV## to test/test_ruby_parser.rb.
74
+ * Extend Manifest.txt with generated file names.
75
+ * Add new version number to sexp_processor's pt_testcase.rb in all_versions
76
+
77
+ Until all of these are done, you won't have a clean test run.
78
+
49
79
  == REQUIREMENTS:
50
80
 
51
81
  * ruby. woot.
data/Rakefile CHANGED
@@ -1,107 +1,131 @@
1
1
  # -*- ruby -*-
2
2
 
3
- require 'rubygems'
4
- require 'hoe'
3
+ require "rubygems"
4
+ require "hoe"
5
5
 
6
6
  Hoe.plugin :seattlerb
7
7
  Hoe.plugin :racc
8
8
  Hoe.plugin :isolate
9
+ Hoe.plugin :rdoc
9
10
 
11
+ Hoe.add_include_dirs "lib"
10
12
  Hoe.add_include_dirs "../../sexp_processor/dev/lib"
13
+ Hoe.add_include_dirs "../../minitest/dev/lib"
14
+ Hoe.add_include_dirs "../../oedipus_lex/dev/lib"
11
15
 
12
- Hoe.spec 'ruby_parser' do
13
- developer 'Ryan Davis', 'ryand-ruby@zenspider.com'
16
+ V2 = %w[20 21 22 23 24 25 26 27]
17
+ V3 = %w[30 31]
14
18
 
15
- self.rubyforge_name = 'parsetree'
19
+ VERS = V2 + V3
16
20
 
17
- dependency 'sexp_processor', '~> 4.1'
21
+ ENV["FAST"] = VERS.last if ENV["FAST"] && !VERS.include?(ENV["FAST"])
22
+ VERS.replace [ENV["FAST"]] if ENV["FAST"]
18
23
 
19
- if plugin? :perforce then
20
- self.perforce_ignore << "lib/ruby18_parser.rb"
21
- self.perforce_ignore << "lib/ruby19_parser.rb"
22
- end
24
+ Hoe.spec "ruby_parser" do
25
+ developer "Ryan Davis", "ryand-ruby@zenspider.com"
23
26
 
24
- self.racc_flags << " -t" if plugin?(:racc) && ENV["DEBUG"]
25
- end
27
+ license "MIT"
26
28
 
27
- file "lib/ruby18_parser.rb" => "lib/ruby18_parser.y"
28
- file "lib/ruby19_parser.rb" => "lib/ruby19_parser.y"
29
+ dependency "sexp_processor", "~> 4.16"
30
+ dependency "rake", [">= 10", "< 15"], :developer
31
+ dependency "oedipus_lex", "~> 2.6", :developer
29
32
 
30
- task :clean do
31
- rm_rf(Dir["**/*~"] +
32
- Dir["**/*.diff"] +
33
- Dir["coverage.info"] +
34
- Dir["coverage"] +
35
- Dir["lib/*.output"])
36
- end
33
+ # NOTE: Ryan!!! Stop trying to fix this dependency! Isolate just
34
+ # can't handle having a faux-gem half-installed! Stop! Just `gem
35
+ # install racc` and move on. Revisit this ONLY once racc-compiler
36
+ # gets split out.
37
37
 
38
- def next_num(glob)
39
- num = Dir[glob].max[/\d+/].to_i + 1
40
- end
38
+ dependency "racc", "~> 1.5", :developer
39
+
40
+ require_ruby_version [">= 2.1", "< 4"]
41
+
42
+ if plugin? :perforce then # generated files
43
+ VERS.each do |n|
44
+ self.perforce_ignore << "lib/ruby#{n}_parser.rb"
45
+ end
41
46
 
42
- desc "Compares PT to RP and deletes all files that match"
43
- task :compare do
44
- files = Dir["unit/**/*.rb"]
45
- puts "Parsing #{files.size} files"
46
- files.each do |file|
47
- puts file
48
- system "./cmp.rb -q #{file} && rm #{file}"
47
+ VERS.each do |n|
48
+ self.perforce_ignore << "lib/ruby#{n}_parser.y"
49
+ end
50
+
51
+ self.perforce_ignore << "lib/ruby_lexer.rex.rb"
49
52
  end
50
- system 'find -d unit -type d -empty -exec rmdir {} \;'
51
- end
52
53
 
53
- desc "Compares PT to RP and stops on first failure"
54
- task :find_bug do
55
- files = Dir["unit/**/*.rb"]
56
- puts "Parsing #{files.size} files"
57
- files.each do |file|
58
- puts file
59
- sh "./cmp.rb -q #{file}"
54
+ if plugin?(:racc)
55
+ self.racc_flags << " -t" if ENV["DEBUG"]
56
+ self.racc_flags << " --superclass RubyParser::Parser"
57
+ # self.racc_flags << " --runtime ruby_parser" # TODO: broken in racc
60
58
  end
61
59
  end
62
60
 
63
- task :sort do
64
- sh 'grepsort "^ +def" lib/ruby_lexer.rb'
65
- sh 'grepsort "^ +def (test|util)" test/test_ruby_lexer.rb'
66
- end
61
+ def maybe_add_to_top path, string
62
+ file = File.read path
67
63
 
68
- task :loc do
69
- loc1 = `wc -l ../1.0.0/lib/ruby_lexer.rb`[/\d+/]
70
- flog1 = `flog -s ../1.0.0/lib/ruby_lexer.rb`[/\d+\.\d+/]
71
- loc2 = `cat lib/ruby_lexer.rb lib/ruby_parser_extras.rb | wc -l`[/\d+/]
72
- flog2 = `flog -s lib/ruby_lexer.rb lib/ruby_parser_extras.rb`[/\d+\.\d+/]
64
+ return if file.start_with? string
73
65
 
74
- loc1, loc2, flog1, flog2 = loc1.to_i, loc2.to_i, flog1.to_f, flog2.to_f
66
+ warn "Altering top of #{path}"
67
+ tmp_path = "#{path}.tmp"
68
+ File.open(tmp_path, "w") do |f|
69
+ f.puts string
70
+ f.puts
75
71
 
76
- puts "1.0.0: loc = #{loc1} flog = #{flog1}"
77
- puts "dev : loc = #{loc2} flog = #{flog2}"
78
- puts "delta: loc = #{loc2-loc1} flog = #{flog2-flog1}"
72
+ f.write file
73
+ # TODO: make this deal with encoding comments properly?
74
+ end
75
+ File.rename tmp_path, path
79
76
  end
80
77
 
81
- desc "Validate against all normal files in unit dir"
82
- task :validate do
83
- sh "./cmp.rb unit/*.rb"
78
+ def unifdef?
79
+ @unifdef ||= system("which unifdef") or abort <<~EOM
80
+ unifdef not found!
81
+
82
+ Please install 'unifdef' package on your system or `rake generate` on a mac.
83
+ EOM
84
84
  end
85
85
 
86
- def run_and_log cmd, prefix
87
- files = ENV['FILES'] || 'unit/*.rb'
88
- p, x = prefix, "txt"
89
- n = Dir["#{p}.*.#{x}"].map { |s| s[/\d+/].to_i }.max + 1 rescue 1
90
- f = "#{p}.#{n}.#{x}"
86
+ V2.each do |n|
87
+ file "lib/ruby#{n}_parser.y" => "lib/ruby_parser.yy" do |t|
88
+ unifdef?
89
+ cmd = 'unifdef -tk -DV=%s -UDEAD %s > %s || true' % [n, t.source, t.name]
90
+ sh cmd
91
+ end
91
92
 
92
- sh "#{cmd} #{Hoe::RUBY_FLAGS} bin/ruby_parse -q -g #{files} &> #{f}"
93
+ file "lib/ruby#{n}_parser.rb" => "lib/ruby#{n}_parser.y"
94
+ end
95
+
96
+ V3.each do |n|
97
+ file "lib/ruby#{n}_parser.y" => "lib/ruby3_parser.yy" do |t|
98
+ unifdef?
99
+ cmd = 'unifdef -tk -DV=%s -UDEAD %s > %s || true' % [n, t.source, t.name]
100
+ sh cmd
101
+ end
93
102
 
94
- puts File.read(f)
103
+ file "lib/ruby#{n}_parser.rb" => "lib/ruby#{n}_parser.y"
95
104
  end
96
105
 
97
- desc "Benchmark against all normal files in unit dir"
98
- task :benchmark do
99
- run_and_log "ruby", "benchmark"
106
+ file "lib/ruby_lexer.rex.rb" => "lib/ruby_lexer.rex"
107
+
108
+ task :parser do |t|
109
+ t.prerequisite_tasks.grep(Rake::FileTask).select(&:already_invoked).each do |f|
110
+ maybe_add_to_top f.name, "# frozen_string_literal: true"
111
+ end
112
+ end
113
+
114
+ task :generate => [:lexer, :parser]
115
+
116
+ task :clean do
117
+ rm_rf(Dir["**/*~"] +
118
+ Dir["diff.diff"] + # not all diffs. bit me too many times
119
+ Dir["coverage.info"] +
120
+ Dir["coverage"] +
121
+ Dir["lib/ruby2*_parser.y"] +
122
+ Dir["lib/ruby3*_parser.y"] +
123
+ Dir["lib/*.output"])
100
124
  end
101
125
 
102
- desc "Profile against all normal files in unit dir"
103
- task :profile do
104
- run_and_log "zenprofile", "profile"
126
+ task :sort do
127
+ sh "grepsort '^ +def' lib/ruby_lexer.rb"
128
+ sh "grepsort '^ +def (test|util)' test/test_ruby_lexer.rb"
105
129
  end
106
130
 
107
131
  desc "what was that command again?"
@@ -109,80 +133,254 @@ task :huh? do
109
133
  puts "ruby #{Hoe::RUBY_FLAGS} bin/ruby_parse -q -g ..."
110
134
  end
111
135
 
112
- task :irb => [:isolate] do
113
- sh "GEM_HOME=#{Gem.path.first} irb -rubygems -Ilib -rruby_parser;"
114
- end
115
-
116
136
  def (task(:phony)).timestamp
117
137
  Time.at 0
118
138
  end
119
139
 
120
140
  task :isolate => :phony
121
141
 
122
- file "lib/ruby18_parser.rb" => :isolate
123
- file "lib/ruby19_parser.rb" => :isolate
142
+ def in_compare
143
+ Dir.chdir "compare" do
144
+ yield
145
+ end
146
+ end
124
147
 
125
- task :compare18 do
126
- sh "./yack.rb lib/ruby18_parser.output > racc18.txt"
127
- sh "./yack.rb parse18.output > yacc18.txt"
128
- sh "diff -du racc18.txt yacc18.txt || true"
129
- puts
130
- sh "diff -du racc18.txt yacc18.txt | wc -l"
148
+ def dl v
149
+ dir = v[/^\d+\.\d+/]
150
+ url = "https://cache.ruby-lang.org/pub/ruby/#{dir}/ruby-#{v}.tar.xz"
151
+ path = File.basename url
152
+ unless File.exist? path then
153
+ system "curl -O #{url}"
154
+ end
131
155
  end
132
156
 
133
- task :compare19 do
134
- sh "./yack.rb lib/ruby19_parser.output > racc19.txt"
135
- sh "./yack.rb parse19.output > yacc19.txt"
136
- sh "diff -du racc19.txt yacc19.txt || true"
137
- puts
138
- sh "diff -du racc19.txt yacc19.txt | wc -l"
157
+ def ruby_parse version
158
+ v = version[/^\d+\.\d+/].delete "."
159
+ rp_txt = "rp#{v}.txt"
160
+ mri_txt = "mri#{v}.txt"
161
+ parse_y = "parse#{v}.y"
162
+ tarball = "ruby-#{version}.tar.xz"
163
+ ruby_dir = "ruby-#{version}"
164
+ diff = "diff#{v}.diff"
165
+ rp_out = "lib/ruby#{v}_parser.output"
166
+ _rp_y = "lib/ruby#{v}_parser.y"
167
+ rp_y_rb = "lib/ruby#{v}_parser.rb"
168
+
169
+ c_diff = "compare/#{diff}"
170
+ c_rp_txt = "compare/#{rp_txt}"
171
+ c_mri_txt = "compare/#{mri_txt}"
172
+ c_parse_y = "compare/#{parse_y}"
173
+ c_tarball = "compare/#{tarball}"
174
+ normalize = "compare/normalize.rb"
175
+
176
+ file c_tarball do
177
+ in_compare do
178
+ dl version
179
+ end
180
+ end
181
+
182
+ desc "fetch all tarballs"
183
+ task :fetch => c_tarball
184
+
185
+ file c_parse_y => c_tarball do
186
+ in_compare do
187
+ extract_glob = case
188
+ when version > "2.7" then
189
+ "{id.h,parse.y,tool/{id2token.rb,lib/vpath.rb}}"
190
+ else
191
+ "{id.h,parse.y,tool/{id2token.rb,vpath.rb}}"
192
+ end
193
+ system "tar Jxf #{tarball} #{ruby_dir}/#{extract_glob}"
194
+
195
+ Dir.chdir ruby_dir do
196
+ if File.exist? "tool/id2token.rb" then
197
+ sh "ruby tool/id2token.rb --path-separator=.:./ id.h parse.y | expand > ../#{parse_y}"
198
+ else
199
+ sh "expand parse.y > ../#{parse_y}"
200
+ end
201
+
202
+ ruby "-pi", "-e", 'gsub(/^%pure-parser/, "%define api.pure")', "../#{parse_y}"
203
+ end
204
+ sh "rm -rf #{ruby_dir}"
205
+ end
206
+ end
207
+
208
+ bison = Dir["/opt/homebrew/opt/bison/bin/bison",
209
+ "/usr/local/opt/bison/bin/bison",
210
+ `which bison`.chomp,
211
+ ].first
212
+
213
+ file c_mri_txt => [c_parse_y, normalize] do
214
+ in_compare do
215
+ sh "#{bison} -r all #{parse_y}"
216
+ sh "./normalize.rb parse#{v}.output > #{mri_txt}"
217
+ rm ["parse#{v}.output", "parse#{v}.tab.c"]
218
+ end
219
+ end
220
+
221
+ file rp_out => rp_y_rb
222
+
223
+ file c_rp_txt => [rp_out, normalize] do
224
+ in_compare do
225
+ sh "./normalize.rb ../#{rp_out} > #{rp_txt}"
226
+ end
227
+ end
228
+
229
+ compare = "compare#{v}"
230
+
231
+ desc "Compare all grammars to MRI"
232
+ task :compare => compare
233
+
234
+ file c_diff => [c_mri_txt, c_rp_txt] do
235
+ in_compare do
236
+ sh "diff -du #{mri_txt} #{rp_txt} > #{diff}; true"
237
+ end
238
+ end
239
+
240
+ desc "Compare #{v} grammar to MRI #{version}"
241
+ task compare => c_diff do
242
+ in_compare do
243
+ system "wc -l #{diff}"
244
+ end
245
+ end
246
+
247
+ task :clean do
248
+ rm_f Dir[c_mri_txt, c_rp_txt]
249
+ end
250
+
251
+ task :realclean do
252
+ rm_f Dir[c_parse_y, tarball]
253
+ end
254
+ end
255
+
256
+ task :versions do
257
+ require "open-uri"
258
+ require "net/http" # avoid require issues in threads
259
+ require "net/https"
260
+
261
+ versions = VERS.map { |s| s.split(//).join "." }
262
+
263
+ base_url = "https://cache.ruby-lang.org/pub/ruby"
264
+
265
+ class Array
266
+ def human_sort
267
+ sort_by { |item| item.to_s.split(/(\d+)/).map { |e| [e.to_i, e] } }
268
+ end
269
+ end
270
+
271
+ versions = versions.map { |ver|
272
+ Thread.new {
273
+ URI
274
+ .parse("#{base_url}/#{ver}/")
275
+ .read
276
+ .scan(/ruby-\d+\.\d+\.\d+[-\w.]*?.tar.gz/)
277
+ .reject { |s| s =~ /-(?:rc|preview)\d/ }
278
+ .human_sort
279
+ .last
280
+ .delete_prefix("ruby-")
281
+ .delete_suffix ".tar.gz"
282
+ }
283
+ }.map(&:value).sort
284
+
285
+ puts versions.map { |v| "ruby_parse %p" % [v] }
139
286
  end
140
287
 
288
+ ruby_parse "2.0.0-p648"
289
+ ruby_parse "2.1.10"
290
+ ruby_parse "2.2.10"
291
+ ruby_parse "2.3.8"
292
+ ruby_parse "2.4.10"
293
+ ruby_parse "2.5.9"
294
+ ruby_parse "2.6.9"
295
+ ruby_parse "2.7.5"
296
+ ruby_parse "3.0.3"
297
+ ruby_parse "3.1.1"
298
+
141
299
  task :debug => :isolate do
142
- ENV["V"] ||= "19"
300
+ ENV["V"] ||= VERS.last
143
301
  Rake.application[:parser].invoke # this way we can have DEBUG set
302
+ Rake.application[:lexer].invoke # this way we can have DEBUG set
303
+
304
+ $:.unshift "lib"
305
+ require "ruby_parser"
306
+ require "pp"
144
307
 
145
- $: << "lib"
146
- require 'ruby_parser'
308
+ klass = Object.const_get("Ruby#{ENV["V"]}Parser") rescue nil
309
+ raise "Unsupported version #{ENV["V"]}" unless klass
310
+ parser = klass.new
147
311
 
148
- parser = if ENV["V"] == "18" then
149
- Ruby18Parser.new
150
- else
151
- Ruby19Parser.new
152
- end
312
+ time = (ENV["RP_TIMEOUT"] || 10).to_i
153
313
 
154
- file = ENV["F"] || ENV["FILE"]
314
+ n = ENV["BUG"]
315
+ file = (n && "bug#{n}.rb") || ENV["F"] || ENV["FILE"] || "debug.rb"
316
+ ruby = ENV["R"] || ENV["RUBY"]
317
+
318
+ if ruby then
319
+ file = "env"
320
+ else
321
+ ruby = File.read file
322
+ end
155
323
 
156
- ruby = if file then
157
- File.read(file)
158
- else
159
- file = "env"
160
- ENV["R"] || ENV["RUBY"]
161
- end
162
324
 
163
325
  begin
164
- p parser.process(ruby, file)
165
- rescue Racc::ParseError => e
326
+ pp parser.process(ruby, file, time)
327
+ rescue ArgumentError, Racc::ParseError => e
166
328
  p e
167
- ss = parser.lexer.src
329
+ puts e.backtrace.join "\n "
330
+ ss = parser.lexer.ss
168
331
  src = ss.string
169
332
  lines = src[0..ss.pos].split(/\n/)
170
333
  abort "on #{file}:#{lines.size}"
171
334
  end
172
335
  end
173
336
 
174
- task :debug_ruby do
175
- file = ENV["F"] || ENV["FILE"]
176
- sh "ruby19 -cwy #{file} 2>&1 | ./yuck.rb"
337
+ task :debug3 do
338
+ file = ENV["F"] || "debug.rb"
339
+ version = ENV["V"] || ""
340
+ verbose = ENV["VERBOSE"] ? "-v" : ""
341
+ munge = "./tools/munge.rb #{verbose}"
342
+
343
+ abort "Need a file to parse, via: F=path.rb" unless file
344
+
345
+ ENV.delete "V"
346
+
347
+ ruby = "ruby#{version}"
348
+
349
+ sh "#{ruby} -v"
350
+ sh "#{ruby} -y #{file} 2>&1 | #{munge} > tmp/ruby"
351
+ sh "#{ruby} ./tools/ripper.rb -d #{file} | #{munge} > tmp/rip"
352
+ sh "rake debug F=#{file} DEBUG=1 2>&1 | #{munge} > tmp/rp"
353
+ sh "diff -U 999 -d tmp/{ruby,rp}"
354
+ end
355
+
356
+ task :cmp do
357
+ sh %(emacsclient --eval '(ediff-files "tmp/ruby" "tmp/rp")')
358
+ end
359
+
360
+ task :cmp3 do
361
+ sh %(emacsclient --eval '(ediff-files3 "tmp/ruby" "tmp/rip" "tmp/rp")')
177
362
  end
178
363
 
179
364
  task :extract => :isolate do
180
- ENV["V"] ||= "19"
365
+ ENV["V"] ||= VERS.last
181
366
  Rake.application[:parser].invoke # this way we can have DEBUG set
182
367
 
183
- file = ENV["F"] || ENV["FILE"]
368
+ file = ENV["F"] || ENV["FILE"] || abort("Need to provide F=<path>")
184
369
 
185
370
  ruby "-Ilib", "bin/ruby_parse_extract_error", file
186
371
  end
187
372
 
373
+ task :parse => :isolate do
374
+ ENV["V"] ||= VERS.last
375
+ Rake.application[:parser].invoke # this way we can have DEBUG set
376
+
377
+ file = ENV["F"] || ENV["FILE"] || abort("Need to provide F=<path>")
378
+
379
+ ruby "-Ilib", "bin/ruby_parse", file
380
+ end
381
+
382
+ task :bugs do
383
+ sh "for f in bug*.rb bad*.rb ; do #{Gem.ruby} -S rake debug F=$f && rm $f ; done"
384
+ end
385
+
188
386
  # vim: syntax=Ruby
data/bin/ruby_parse CHANGED
@@ -26,6 +26,8 @@ class File
26
26
  end
27
27
 
28
28
  begin
29
+ time = (ENV["RP_TIMEOUT"] || 10).to_i
30
+
29
31
  ARGV.each do |file|
30
32
  rp = RubyParser.new
31
33
  loc = `wc -l #{file}`.strip.to_i
@@ -45,7 +47,7 @@ begin
45
47
  begin
46
48
  begin
47
49
  rp.reset
48
- r = rp.parse(File.binread(file), file)
50
+ r = rp.process(File.binread(file), file, time)
49
51
  pp r unless $q
50
52
  good += 1
51
53
  rescue SyntaxError => e