redparse 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,6 +16,19 @@
16
16
  along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  =end
18
18
 
19
+ #this is actually fixing a bug in reg 0.4.7, grrrrr
20
+ unless Array===(Class*5).subregs
21
+ module ::Reg
22
+ class Repeat
23
+ undef subregs if instance_methods.include? "subregs"
24
+ def subregs
25
+ [@reg]
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+
19
32
  unless defined? ::Reg::Transform and ::Reg::Transform.ancestors.include? ::Reg::HasCmatch
20
33
  #hack, until support for this syntax makes it into the release of reg
21
34
  module ::Reg
@@ -49,6 +62,10 @@
49
62
  @reg
50
63
  end
51
64
 
65
+ def subregs
66
+ [@reg]
67
+ end
68
+
52
69
  def itemrange
53
70
  0..0
54
71
  end
@@ -72,6 +89,10 @@
72
89
  @reg
73
90
  end
74
91
 
92
+ def subregs
93
+ [@reg]
94
+ end
95
+
75
96
  def itemrange
76
97
  0..0
77
98
  end
@@ -1,3 +1,3 @@
1
1
  class RedParse
2
- VERSION='0.8.1'
2
+ VERSION='0.8.2'
3
3
  end
@@ -0,0 +1,2 @@
1
+ def foo(a = 1) end; def foo(a=b=c={}) end; def bar(a=b=c=1,d=2) end
2
+
@@ -39,7 +39,7 @@ $RUBY=ENV['RUBY']||'ruby'
39
39
 
40
40
  #$RUBYLEXERVSRUBY="#$RUBY test/code/rubylexervsruby.rb"
41
41
 
42
- RUBY_VERSION[/^1\.8\.7/] or raise 'need ruby>= 1.8.7'
42
+ RUBY_VERSION[/^1\.8\.6/] or raise 'need ruby>= 1.8.6'
43
43
 
44
44
 
45
45
 
@@ -140,6 +140,7 @@ RUBYLIST=(pf.badlist+
140
140
  split("\n")
141
141
  ].sort_by{rand})-pf.goodlist + pf.goodlist
142
142
  RUBYLIST.reject!{|x| %r{japanese/zipcodes\.rb$}===x } #65M of ruby src!!!
143
+ RUBYLIST.reject!{|x| /\A\s*\Z/===x }
143
144
  RUBYLIST.uniq!
144
145
 
145
146
  def self.main
@@ -20,21 +20,277 @@
20
20
  require 'test/unit'
21
21
  require 'rubygems'
22
22
  require 'parse_tree'
23
+ require 'tempfile'
23
24
 
24
25
  require "redparse"
25
26
 
26
- begin
27
27
  require "rubylexer/test/testcases"
28
- rescue Exception
29
- puts "!!!!!!rubylexer/test/testcases not found!!!!"
30
- module TestCases;TESTCASES=[];end
28
+
29
+ $VERBOSE=1
30
+
31
+ class Test::Unit::TestCase
32
+ def known_error
33
+ from=caller.first
34
+ from=from[/ in `.*'\Z/] || from[/\A[^:]*:[^:]*/]
35
+ yield
36
+ rescue Test::Unit::AssertionFailedError=>e
37
+ warn "an expected error occurred in #{from}: #{e.message}"
38
+ if defined? @@known_errors
39
+ @@known_errors+=1
40
+ else
41
+ @@known_errors=1
42
+ at_exit {warn "!!!UNFIXED KNOWN ERRORS!!!: #@@known_errors"}
43
+ end
44
+ rescue Exception=>e
45
+ raise
46
+ else
47
+ warn "expected error in #{from}, but was fixed(?!)"
48
+ if defined? @@known_errors_fixed
49
+ @@known_errors_fixed+=1
50
+ else
51
+ @@known_errors_fixed=1
52
+ at_exit {warn "unexpectedly fixed known errors: #@@known_errors_fixed"}
53
+ end
54
+ end
55
+
56
+ def known_failure
57
+ from=caller.first
58
+ from=from[/ in `.*'\Z/] || from[/\A[^:]*:[^:]*/]
59
+ yield
60
+ rescue Exception=>e
61
+ warn "an expected failure occurred in #{from}: #{e}"
62
+ if defined? @@known_failures
63
+ @@known_failures+=1
64
+ else
65
+ @@known_failures=1
66
+ at_exit {warn "!!!UNFIXED KNOWN FAILURES!!!: #@@known_failures"}
67
+ end
68
+ else
69
+ warn "expected failure in #{from}, but was fixed(?!)"
70
+ if defined? @@known_failures_fixed
71
+ @@known_failures_fixed+=1
72
+ else
73
+ @@known_failures_fixed=1
74
+ at_exit {warn "unexpectedly fixed known failures: #@@known_failures_fixed"}
75
+ end
76
+ end
77
+
78
+ def slow
79
+ if ENV['SLOW']
80
+ yield
81
+ else
82
+ if defined? @@slow_spots
83
+ @@slow_spots+=1
84
+ else
85
+ @@slow_spots=1
86
+ at_exit {warn "slow test code skipped in #@@slow_spots places. (set SLOW to enable)"}
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ require 'test/unit/ui/console/testrunner'
93
+ class Test::Unit::UI::Console::TestRunner
94
+ alias add_fault__no_immed_output add_fault
95
+ def add_fault fault
96
+ @fault_count||=0
97
+ output("\n%3d) %s" % [@fault_count+=1, fault.long_display])
98
+ add_fault__no_immed_output fault
99
+ end
100
+ end
101
+
102
+ class ParseTree
103
+ def put o
104
+ o=Marshal.dump o
105
+ @@out.write [o.size].pack("N")+o
106
+ end
107
+ def get
108
+ Marshal.load @@in.read(@@in.read(4).unpack("N")[0])
109
+ end
110
+ def fork_server?
111
+ return if defined? @@out
112
+ si,co=IO::pipe
113
+ ci,so=IO::pipe
114
+ fork{
115
+ begin
116
+ co.close; ci.close
117
+ @@out=so; @@in=si
118
+ warnstash=Tempfile.new "warnstash"
119
+ STDERR.reopen warnstash
120
+ while 1
121
+ str=get
122
+ exit! if str==:exit!
123
+
124
+ pos=STDERR.pos
125
+
126
+ tree=
127
+ begin
128
+ parse_tree_for_string(str) #tree
129
+ rescue Exception=>e;
130
+ tree=e
131
+ end
132
+ put tree
133
+
134
+ open(STDERR.path){|f|
135
+ f.pos=pos
136
+ put f.read.split #warnings
137
+ }
138
+ end
139
+ rescue Exception=>e; p e; raise
140
+ ensure exit!
141
+ end
142
+ }
143
+ si.close; so.close
144
+ @@out=co; @@in=ci
145
+ at_exit { put :exit! }
146
+ end
147
+
148
+ #returns +[parse_tree|Exception, +[String.*]]
149
+ def parse_tree_and_warnings str
150
+ fork_server?
151
+ put str
152
+ tree=get
153
+ warnings=get
154
+ raise tree if Exception===tree
155
+ return tree,warnings
156
+ end
157
+
158
+ #this way is bad enough, but there's a fd leak this way,
159
+ #so I have to use the even more complicated version above
160
+ def parse_tree_and_warnings_leaks_stderr(str)
161
+ oldSTDERR=STDERR.dup
162
+ warnstash=Tempfile.new "warnstash"
163
+ warnings=[]
164
+
165
+ STDERR.reopen warnstash
166
+ tree=parse_tree_for_string(str)
167
+
168
+ return tree,warnings
169
+ ensure
170
+ STDERR.reopen oldSTDERR
171
+
172
+ warnstash.rewind
173
+ warnings.replace warnstash.read.split
174
+ warnstash.close
175
+ end
31
176
  end
32
177
 
33
178
  class RedParseTest<Test::Unit::TestCase
179
+ ERROR_EXAMPLES=[
180
+ '%W"is #{x}#{"Slim #{2?"W":"S"} "}."',
181
+ '%W"is #{x}#{"Slim #{2?"W":"S"}"}#{xx}."',
182
+ '%W"is #{x}#{"Slim #{2?W: S} "}."',
183
+ '%W"is #{x}#{%Q\'Slim #{2?W: S} \'}."',
184
+ '%W"is #{x}#{%W"Slim #{2?"W":"S"}"}#{xx}."',
185
+ '%W"is #{x}#{%W\'Slim #{2?W: S} \'}."',
186
+ '%W"is #{x}#{%q\'Slim #{2?W: S} \'}."',
187
+ '%W"is #{x}#{%r\'Slim #{2?W: S} \'}."',
188
+ '%W"is #{x}#{%w\'Slim #{2?W: S} \'}."',
189
+ '%W"is #{x}#{%x\'Slim #{2?W: S} \'}."',
190
+ '%W"is #{x}#{/Slim #{2?W: S} /}."',
191
+ '%W"is #{x}#{`Slim #{2?W: S} `}."',
192
+ '%W"is_#{"Slim_#{2?"W":"S"}"}#{xx}."',
193
+ '%W"is_#{x}#{"Slim_#{2?"W":"S"}"}#{xx}."',
194
+ '%W"is_#{x}#{"Slim_#{2?"W":"S"}_"}."',
195
+ ]
196
+ FAILURE_EXAMPLES=[
197
+ ]
198
+ RUBYBUG_EXAMPLES=[
199
+ 'def foo(a=b=c={}) end',
200
+ "$11111111111111111111111111111111111111111111111111111111111111111111",
201
+ "c do p (110).m end",
202
+ "case F;when G; else;case; when j; end;end",
203
+ "p = p m %(1)",
204
+ "p = p m %(1) ,&t",
205
+ "p = p m %(1) ,*t",
206
+ "p = p m %(1) ,t",
207
+ "p = p m %(1) do end",
208
+ "p=556;p (e) /a",
209
+ "z{|| p (1).m}",
210
+ 'def sum(options = {:weights => weights = Hash.new(1)}); options.empty? or options.keys.size > 1; end',
211
+ ]
212
+
34
213
  ONELINERS=[
214
+ 'z = valueo_s rescue "?"'...'',
215
+ '"#{publi}#{}>"'...'',
216
+ 'return (@images = @old_imgs)'...'',
217
+ ' /\A#{__FILE__}tcase/n =~ i '...'',
218
+ 'doc_status, err_args = Documeh_status{fcgi_state = 3; docespond do doc_response =fcgi_state = 1; end }'...'',
219
+ 'print "coled: " + $! +" wiin #{@ray}\n";'...'',
220
+ 'class A;def b;class <<self;@@p = false end;end;end'...'',
221
+ 'def d; return (block_given? ? begin; yield f; ensure; f.close; end : f); end'...'',
222
+ 'def sum(options = {:weights => weights = Hash.new(1)}); options.empty? or options.keys.size > 1; end'...'',
223
+ 'def d;e install_dir;end'...'',
224
+ '(m).kk,(m+n).kk=3'...'',
225
+ '((m).kk,(m+n).kk)=3'...'',
226
+ '((m).kk,(m+n).kk),t=3'...'',
227
+ 's,((m).kk,(m+n).kk)=3'...'',
228
+ 's,((m).kk,(m+n).kk),t=3'...'',
229
+ 'proc{|(m).kk,(m+n).kk| }'...'',
230
+ "p p:'b'"...'', #changes semantics in 1.9
231
+ "p:'b'"...'', #but this doesn't
232
+ 't ?6e0 : 5'...'',
233
+ "super[]"...'',
234
+ 'p end=5'...'', #illegal
235
+ 'p or=5'...'', #illegal
236
+ 'p else=5'...'', #illegal
237
+ 'p if=5'...'', #illegal
238
+ "x{\x0afor i in (begin\n[44,55,66,77,88] end) do p i**Math.sqrt(i) end\n}\n"...'',
239
+ 'e { |c|; print "%02X" % c }'...'',
240
+ %[p <<-heredoc "x y z" and 5\n a b c\n heredoc]...'',
241
+ "File.open() {|f| ; }"...'',
242
+ %[ p <<-heredoc "x y z" and 5\n a b c\n heredoc]...'',
243
+ 'a rescue b until 1'...'',
244
+ 'a rescue b while 1'...'',
245
+ '%W[r\\c 3]'...'',
246
+
247
+ "%w[a\\C- b]"...'',
248
+ "%w[a\\M- b]"...'',
249
+ "%w[a\\c b]"...'',
250
+ "%W[a\\c b]"...'',
251
+ "%w[a\\\\c b]"...'',
252
+ "%W[a\\\\c b]"...'',
253
+ "%w[a\\c b]"...'',
254
+ "%W[a\\c b]"...'',
255
+ "%w[a\\\\c b]"...'',
256
+ "%W[a\\\\c b]"...'',
257
+ "module A; b; rescue C=>d; e; else g; ensure f; end"...'',
258
+ "class<<A; b; rescue C=>d; e; else g; ensure f; end"...'',
259
+ "class A; b; rescue C=>d; e; else g; ensure f; end"...'',
260
+ 'def i;"..#{@@c = 1}";end'...'',
261
+ "def wait; begin; ync; mup; end ;end"...'',
262
+ "def e; begin; y; g else t; m; end ;end"...'',
263
+ '"#{}"""'...'',
264
+ %[%W(white\\ \\ \\ \\ \\ space).should == ["white ", " ", " ", " space"]]...'',
265
+ "%w[- \\\\ ]"...'',
266
+ "%w[- \\\\ e]"...'',
267
+ "begin begin; ync; p1; end;rr end"...'',
268
+ "begin;mode;rescue;o_chmod rescue nil;end"...'',
269
+ "%w![ ] { } ( ) | - * . \\\\ ? + ^ $ #!"...'',
270
+
271
+ 'def foo(a = 1) end; def foo(a=b=c={}) end; def bar(a=b=c=1,d=2) end'...'',
272
+ '() until 1'...'',
273
+ '(a) until 1'...'',
274
+ '(a) while l 1'...'',
275
+ "module A; B='' end"...'',
276
+ "{'one' => {}}"...'',
277
+ "a[3, 2] = 'a', 'b'"...'',
278
+ 'def st; begin ire end end'...'',
279
+ 'x{k=1; return-k}'...'',
280
+ 'x{k=1; return -k}'...'',
281
+ 'x{k=1; return- k}'...'',
282
+ 'x{k=1; return - k}'...'',
283
+ 'x{k=1; return + k}'...'',
284
+ 'x{k=1; return * k}'...'',
285
+ 'x{k=1; break - k}'...'',
286
+ 'x{k=1; next - k}'...'',
287
+ "p\r44"...'',
288
+ 'yield []'...'',
289
+ 'yield [1]'...'',
290
+ 'f{a rescue b}'...'',
35
291
  '%w[- \\\\\\\\ e]'...'',
36
292
  '%w[- \\\\\\\\ ]'...'',
37
- 'a=[]; a [42] = 24'...'', #not legal unless a is a local var
293
+ 'x{a=[]; a [42] = 24}'...'', #not legal unless a is a local var
38
294
  '%w![ ] { } ( ) | - * . \\\\\\\\ ? + ^ $ #!'...'',
39
295
  '%W(white\ \ \ \ \ space).should == ["white ", " ", " ", " space"]'...'',
40
296
  'module A; b; rescue C=>d; e; else g; ensure f; end'...'',
@@ -761,6 +1017,32 @@ class RedParseTest<Test::Unit::TestCase
761
1017
  '%W"is #{"Slim #{2?"W":"S"}"}."'...'',
762
1018
  '"is #{"Slim #{2?"W":"S"}"}#{xx}."'...'',
763
1019
  '%W"is #{"Slim #{2?"W":"S"}"}#{xx}."'...'',
1020
+ '"is #{x}#{"Slim #{2?"W":"S"}"}#{xx}."'...'',
1021
+ '%W"is #{x}#{"Slim #{2?"W":"S"}"}#{xx}."'...'',
1022
+ '"is #{x}#{%W"Slim #{2?"W":"S"}"}#{xx}."'...'',
1023
+ '%W"is #{x}#{%W"Slim #{2?"W":"S"}"}#{xx}."'...'',
1024
+
1025
+ '%W"is_#{x}#{"Slim_#{2?"W":"S"}"}#{xx}."'...'',
1026
+ '%W"is_#{"Slim_#{2?"W":"S"}"}#{xx}."'...'',
1027
+ '%W"is_#{"Slim_#{2?"W":"S"}"}."'...'',
1028
+ '%W"is_#{x}#{"Slim_#{2?"W":"S"}_"}."'...'',
1029
+ '%W"is_#{"Slim_#{2?"W":"S"}_"}."'...'',
1030
+ '%W"is_#{"Slim_#{2?"W":"S"}_" "rr"}."'...'',
1031
+
1032
+ "%W\"is \#{x}\#{%W'Slim \#{2?W: S} '}.\""...'',
1033
+ "%W\"is \#{x}\#{%w'Slim \#{2?W: S} '}.\""...'',
1034
+ "%W\"is \#{x}\#{%Q'Slim \#{2?W: S} '}.\""...'',
1035
+ "%W\"is \#{x}\#{\"Slim \#{2?W: S} \"}.\""...'',
1036
+ "%W\"is \#{x}\#{%q'Slim \#{2?W: S} '}.\""...'',
1037
+ "%W\"is \#{x}\#{%x'Slim \#{2?W: S} '}.\""...'',
1038
+ "%W\"is \#{x}\#{%r'Slim \#{2?W: S} '}.\""...'',
1039
+ "%W\"is \#{x}\#{`Slim \#{2?W: S} `}.\""...'',
1040
+ "%W\"is \#{x}\#{/Slim \#{2?W: S} /}.\""...'',
1041
+ "%\"is \#{x}\#{%r'Slim \#{2?W: S} '}.\""...'',
1042
+ "\"is \#{x}\#{%r'Slim \#{2?W: S} '}.\""...'',
1043
+ "\"is \#{x}\#{%'Slim \#{2?W: S} '}.\""...'',
1044
+ "\"is \#{x}\#{'Slim \#{2?W: S} '}.\""...'',
1045
+
764
1046
  'case $1; when 0,*[2,66]: p 1; when 3; 4 else p 2 end'...'',
765
1047
  'case $1; when 0,*a: p 1; when 3; 4 else p 2 end'...'',
766
1048
  ' p(String <<- Class)'...'',
@@ -2388,7 +2670,93 @@ class RedParseTest<Test::Unit::TestCase
2388
2670
  ]
2389
2671
 
2390
2672
 
2391
- STANZAS=%q[
2673
+ PASSTHRU_BSLASHES_ENTIRE=<<'END'
2674
+ <<-'foo'.count('\\')==0
2675
+ '
2676
+ foo
2677
+
2678
+ <<-'foo'.count('\\')==1
2679
+ \'
2680
+ foo
2681
+
2682
+ <<-'foo'.count('\\')==2
2683
+ \\'
2684
+ foo
2685
+
2686
+ <<-'foo'.count('\\')==3
2687
+ \\\'
2688
+ foo
2689
+
2690
+ <<-'foo'.count('\\')==4
2691
+ \\\\'
2692
+ foo
2693
+
2694
+ <<-'foo'.count('\\')==5
2695
+ \\\\\'
2696
+ foo
2697
+
2698
+ <<-"foo".count('\\')==0
2699
+ "
2700
+ foo
2701
+
2702
+ <<-"foo".count('\\')==0
2703
+ \"
2704
+ foo
2705
+
2706
+ <<-"foo".count('\\')==1
2707
+ \\"
2708
+ foo
2709
+
2710
+ <<-"foo".count('\\')==1
2711
+ \\\"
2712
+ foo
2713
+
2714
+ <<-"foo".count('\\')==2
2715
+ \\\\"
2716
+ foo
2717
+
2718
+ <<-"foo".count('\\')==2
2719
+ \\\\\"
2720
+ foo
2721
+
2722
+ <<-`foo`
2723
+ \`
2724
+ foo
2725
+
2726
+ <<-`foo`
2727
+ \\`
2728
+ foo
2729
+
2730
+ <<-"foo"
2731
+ \"
2732
+ foo
2733
+
2734
+ <<-"foo"
2735
+ "
2736
+ foo
2737
+
2738
+ <<-"foo"
2739
+ \\"
2740
+ foo
2741
+
2742
+ END
2743
+
2744
+ STANZAS=PASSTHRU_BSLASHES_ENTIRE+%q[
2745
+ return @senders[1] =
2746
+ 2
2747
+
2748
+ case
2749
+ when 0
2750
+ guecoding
2751
+ else case
2752
+ when eucjp_match_length
2753
+ guing
2754
+ end
2755
+ end
2756
+
2757
+ %w[ ac
2758
+ df]
2759
+
2392
2760
  begin
2393
2761
  a
2394
2762
  rescue B=>c
@@ -3003,11 +3371,11 @@ end
3003
3371
  end
3004
3372
 
3005
3373
  location_display = if(location.size == 1)
3006
- location[0].sub(/\A(.+:\d+).*/, ' [\\1]')
3374
+ location[0].sub(/\\A(.+:\\d+).*/, ' [\\1]')
3007
3375
  else
3008
- "\n#{location.join("\n")}"
3376
+ "\\n#{location.join("\\n")}"
3009
3377
  end
3010
- "Failure:\n#@test_name#{location_display}:\n#@message"
3378
+ "Failure:\\n#@test_name#{location_display}:\\n#@message"
3011
3379
 
3012
3380
  def parse_date(aString)
3013
3381
  return Time.rfc822(aString) rescue Time.parse(aString)
@@ -3138,10 +3506,15 @@ EOS
3138
3506
  end
3139
3507
 
3140
3508
  EXAMPLES=ONELINERS.map{|rng| rng.first}+STANZAS.split(/\n( *\n)+/)+TestCases::TESTCASES+
3141
- from_rubinius #+ESC_SEQS
3509
+ from_rubinius + #ESC_SEQS +
3510
+ []-ERROR_EXAMPLES-FAILURE_EXAMPLES-RUBYBUG_EXAMPLES
3511
+
3142
3512
 
3143
3513
  WRAPPERS=[ #enable at most 2 or tests take forever!!!
3144
3514
  '(...)', #normal mode, should usually be enabled
3515
+ # 'a rescue (...)',
3516
+ # "((...))",
3517
+ # 'def ((...)).foo; end',
3145
3518
  # 'a0 = (...) rescue b0',
3146
3519
  # 'a0 = ((...)) rescue b0',
3147
3520
  # '(...) #with a comment',
@@ -3160,11 +3533,10 @@ EOS
3160
3533
  # 'a=b,c=d',
3161
3534
  ]
3162
3535
  puts "warning: most data fuzzing is disabled for now"
3163
- puts "warning: unparser tests disabled for now"
3164
3536
 
3165
- RUBYIDENT=/((?:$|@@?)?[a-z_][a-z_0-9]*[?!]?)/i
3537
+ RUBYIDENT=/((?:$|@@?)?#{RubyLexer::LETTER}#{RubyLexer::LETTER_DIGIT}*[?!]?)/o
3166
3538
 
3167
- def self.snippet2testmethod(snippet)
3539
+ def self.snippet2testmethod(snippet,wrap=nil)
3168
3540
  escaped=snippet.gsub(/[\\']/){"\\"+$&}
3169
3541
  safe=escaped.gsub(/([^ -~])/){
3170
3542
  x=$1[0].to_s(16)
@@ -3173,11 +3545,13 @@ EOS
3173
3545
  }
3174
3546
  safe.gsub! /\\\\/,"__"
3175
3547
  safe[/[^ -~]|\\\\/] and fail
3548
+ cp="check_parsing '#{escaped}',pt"
3549
+ cp="#{wrap}{#{cp}}" if wrap
3176
3550
  "
3177
3551
  define_method 'test_parsing_of_#{safe}' do
3178
3552
  #puts 'test_parsing_of_#{safe}'
3179
3553
  pt=ParseTree.new
3180
- check_parsing '#{escaped}',pt
3554
+ #{cp}
3181
3555
  end
3182
3556
  "
3183
3557
  end
@@ -3190,25 +3564,83 @@ EOS
3190
3564
  /\A\s*x\s*\{(.*)\}\Z/===xmpl and xmpl=$1
3191
3565
  # xmpl= (xmpl[/\A\s*x\s*\{(.*)\}\s*(#.*)?\Z/,1] rescue xmpl)
3192
3566
 
3193
- wrapped=WRAPPERS.map{|wrap|
3194
- #apply wrapper
3195
- snippet2testmethod(wrap.gsub('(...)', xmpl))
3196
- }
3197
- injected=INJECTABLES.map{|inj|
3198
- xlist=xmpl.split(RUBYIDENT)
3199
- if xlist.size>1
3200
- i=rand(xlist.size&~1)|1
3201
- i&1==1 or fail
3202
- /\A#{RUBYIDENT}\Z/o===xlist[i] or fail
3203
- xlist[i]=inj
3204
- snippet2testmethod(xlist.to_s)
3205
- end
3206
- }
3207
- wrapped+injected
3567
+ wrapped=WRAPPERS.map{|wrap|
3568
+ #apply wrapper
3569
+ maybe_slow="slow" if xmpl.size>1000
3570
+ wrap=wrap.dup
3571
+ wrap['(...)']=xmpl
3572
+ snippet2testmethod(wrap,maybe_slow)
3573
+ }
3574
+ injected=INJECTABLES.map{|inj|
3575
+ xlist=xmpl.split(RUBYIDENT)
3576
+ if xlist.size>1
3577
+ i=rand(xlist.size&~1)|1
3578
+ i&1==1 or fail
3579
+ /\A#{RUBYIDENT}\Z/o===xlist[i] or fail
3580
+ xlist[i]=inj
3581
+ maybe_slow="slow" if xmpl.size>1000
3582
+ snippet2testmethod(xlist.to_s,maybe_slow)
3583
+ end
3584
+ }
3585
+ wrapped+injected
3208
3586
  }.to_s
3209
3587
  #puts code.split("\n")[5880..5890].join("\n")
3210
3588
  eval code
3211
3589
 
3590
+ error_code=RUBYBUG_EXAMPLES.map{|xmpl|
3591
+ #remove comment if present
3592
+ /\A(.*)\s*\Z/===xmpl and xmpl=$1
3593
+ #remove x{...} wrapper if present
3594
+ /\A\s*x\s*\{(.*)\}\Z/===xmpl and xmpl=$1
3595
+
3596
+ snippet2testmethod(xmpl, :known_ruby_bug)
3597
+ }.to_s
3598
+ eval error_code
3599
+
3600
+ error_code=ERROR_EXAMPLES.map{|xmpl|
3601
+ #remove comment if present
3602
+ /\A(.*)\s*\Z/===xmpl and xmpl=$1
3603
+ #remove x{...} wrapper if present
3604
+ /\A\s*x\s*\{(.*)\}\Z/===xmpl and xmpl=$1
3605
+
3606
+ snippet2testmethod(xmpl, :known_error)
3607
+ }.to_s
3608
+ eval error_code
3609
+
3610
+ failure_code=FAILURE_EXAMPLES.map{|xmpl|
3611
+ #remove comment if present
3612
+ /\A(.*)\s*\Z/===xmpl and xmpl=$1
3613
+ #remove x{...} wrapper if present
3614
+ /\A\s*x\s*\{(.*)\}\Z/===xmpl and xmpl=$1
3615
+
3616
+ snippet2testmethod(xmpl, :known_failure)
3617
+ }.to_s
3618
+ eval failure_code
3619
+
3620
+ def known_ruby_bug
3621
+ from=caller.first
3622
+ from=from[/ in `.*'\Z/] || from[/\A[^:]*:[^:]*/]
3623
+ yield
3624
+ rescue Test::Unit::AssertionFailedError=>e
3625
+ warn "a known bug in MRI reared its head in #{from}: #{e.message}"
3626
+ if defined? @@known_ruby_bugs
3627
+ @@known_ruby_bugs+=1
3628
+ else
3629
+ @@known_ruby_bugs=1
3630
+ at_exit {warn "unfixed bugs in MRI/ParseTree: #@@known_ruby_bugs"}
3631
+ end
3632
+ rescue Exception=>e
3633
+ raise
3634
+ else
3635
+ warn "expected bug in MRI in #{from}, but was fixed(?!)"
3636
+ if defined? @@known_ruby_bugs_fixed
3637
+ @@known_ruby_bugs_fixed+=1
3638
+ else
3639
+ @@known_ruby_bugs_fixed=1
3640
+ at_exit {warn "unexpectedly fixed known MRI/ParseTree bugs: #@@known_ruby_bugs_fixed"}
3641
+ end
3642
+ end
3643
+
3212
3644
  def test_case_that_segfaults_ruby185
3213
3645
  assert_equal \
3214
3646
  [[:op_asgn1, [:call, [:vcall, :a], :b], [:zarray], :%, [:vcall, :d]]],
@@ -3227,13 +3659,91 @@ EOS
3227
3659
  RedParse.new('Proc{|&b|}','-').parse.to_parsetree(:quirks)
3228
3660
  end
3229
3661
 
3662
+ def test_cases_misparsed_by_ruby186_slash_parsetree
3663
+ {"$11111111111111111111111111111111111111111111111111111111111111111111"=>[
3664
+ [:nth_ref, 11111111111111111111111111111111111111111111111111111111111111111111]],
3665
+ "c do p (110).m end"=>[
3666
+ [:iter, [:fcall, :c], nil, [:fcall, :p, [:array, [:call, [:lit, 110], :m]]]]],
3667
+ "case F;when G; else;case; when j; end;end"=>[
3668
+ [:case, [:const, :F], [:when, [:array, [:const, :G]], nil],
3669
+ [:case, nil, [:when, [:array, [:vcall, :j]], nil], nil]]],
3670
+ "p = p m %(1)"=>[
3671
+ [:lasgn, :p, [:fcall, :p, [:array, [:fcall, :m, [:array, [:str, "1"]]]]]]],
3672
+ "p = p m %(1) ,&t"=>[
3673
+ [:lasgn, :p, [:fcall, :p, [:array,
3674
+ [:block_pass, [:vcall, :t], [:fcall, :m, [:array, [:str, "1"]]]]]]]],
3675
+ "p = p m %(1) ,*t"=>[
3676
+ [:lasgn, :p, [:fcall, :p,
3677
+ [:array, [:fcall, :m, [:argscat, [:array, [:str, "1"]], [:vcall, :t]]]]]]],
3678
+ "p = p m %(1) ,t"=>[
3679
+ [:lasgn, :p, [:fcall, :p, [:array, [:fcall, :m,
3680
+ [:array, [:str, "1"], [:vcall, :t]]]]]]],
3681
+ "p = p m %(1) do end"=>[
3682
+ [:lasgn, :p, [:iter, [:fcall, :p, [:array,
3683
+ [:fcall, :m, [:array, [:str, "1"]]]]], nil]]],
3684
+ "p=556;p (e) /a"=>[
3685
+ [:block, [:lasgn, :p, [:lit, 556]],
3686
+ [:fcall, :p, [:array, [:call, [:vcall, :e], :/, [:array, [:vcall, :a]]]]]]],
3687
+ "z{|| p (1).m}"=>[
3688
+ [:iter, [:fcall, :z], 0, [:fcall, :p, [:array, [:call, [:lit, 1], :m]]]]],
3689
+ "
3690
+ <<-'foo'
3691
+ \\'
3692
+ foo
3693
+ "=>[[:str, " \\'\n"]],
3694
+ "
3695
+ <<-'foo'
3696
+ \\\\'
3697
+ foo
3698
+ "=>[[:str, " \\\\'\n"]],
3699
+ "
3700
+ <<-'foo'
3701
+ \\\\\\'
3702
+ foo
3703
+ "=>[[:str, " \\\\\\'\n"]],
3704
+ "
3705
+ <<-'foo'
3706
+ \\\\\\\\'
3707
+ foo
3708
+ "=>[[:str, " \\\\\\\\'\n"]],
3709
+ "
3710
+ <<-'foo'
3711
+ \\\\\\\\\\'
3712
+ foo
3713
+ "=>[[:str, " \\\\\\\\\\'\n"]],
3714
+ "
3715
+ <<-'foo'
3716
+ \\\\\\\\\\\\'
3717
+ foo
3718
+ "=>[[:str, " \\\\\\\\\\\\'\n"]],
3719
+
3720
+
3721
+ }.each_pair{|code,tree|
3722
+ assert_equal tree,RedParse.new(code,'-').parse.to_parsetree(:quirks)
3723
+ }
3724
+ end
3725
+
3726
+ POWERS_OF_2={}
3727
+ i=1
3728
+ while i<1_000_000_000
3729
+ POWERS_OF_2[i]=1
3730
+ i*=2
3731
+ end
3732
+
3230
3733
  def assert_hopefully_raises_Exception xmpl
3231
3734
  begin
3232
3735
  yield
3233
3736
  rescue Exception
3234
3737
  assert true
3235
3738
  else
3236
- puts "warning: syntax error expected, but none was seen, expression: <<< #{xmpl} >>>"
3739
+ if defined? @@missed_syntax_errors
3740
+ @@missed_syntax_errors+=1
3741
+ else
3742
+ @@missed_syntax_errors=1
3743
+ at_exit{warn "missed syntax errors: #@@missed_syntax_errors"}
3744
+ end
3745
+ #puts "warning: syntax error expected, but none was seen, expression: <<< #{xmpl} >>>" if
3746
+ # POWERS_OF_2[@@missed_syntax_errors]
3237
3747
  end
3238
3748
  end
3239
3749
 
@@ -3248,11 +3758,12 @@ EOS
3248
3758
  @problem_exprs=$stdout
3249
3759
  end
3250
3760
 
3251
- @@differed_by_nil=0
3252
-
3253
3761
  def check_parsing xmpl,pt=ParseTree.new
3762
+ pt_opts=[:quirks]
3763
+ pt_opts<<:ruby187 if ::VERSION["1.8.7"]
3254
3764
  /unparse/===xmpl and warn 'unparse in parser test data!'
3255
3765
  problem_exprs=problem_exprs()
3766
+ nodes=warnings=warnings2=nil
3256
3767
  =begin
3257
3768
  xmpl=<<-prefix+xmpl+<<-suffix
3258
3769
  BEGIN{throw :never_exec_parse_data_try1,1}
@@ -3272,31 +3783,39 @@ EOS
3272
3783
  # catch(:never_exec_parse_data_try1){
3273
3784
  # catch(:never_exec_parse_data_try2){
3274
3785
  # catch(:never_exec_parse_data_try3){
3275
- tree=pt.parse_tree_for_string(xmpl)
3786
+ tree,warnings=pt.parse_tree_and_warnings(xmpl)
3276
3787
  # }
3277
3788
  # }
3278
3789
  # }
3279
3790
  # break if loops+=1 > 3
3280
- rescue Interrupt: raise
3281
- rescue Exception=>e:
3791
+ rescue Interrupt; raise
3792
+ rescue Exception=>e
3793
+ #pp e
3794
+ #pp e.backtrace
3282
3795
  #raise "last gasp ParseTree exec catcher failed!"
3283
3796
  tree=e
3284
- tree2=nodes=nil
3797
+ tree2=nodes=h=nil
3285
3798
  assert_hopefully_raises_Exception(xmpl){
3286
3799
  nodes=RedParse.new(xmpl,"-").parse
3287
- tree2=nodes.to_parsetree(:quirks)
3800
+ h=nodes.hash
3801
+ tree2,warnings2=nodes.to_parsetree_and_warnings(*pt_opts)
3288
3802
  }
3803
+ assert_equal h,nodes.hash if h
3289
3804
  else
3290
3805
  begin
3291
3806
  nodes=RedParse.new(xmpl,"-").parse
3292
- tree2=nodes.to_parsetree(:quirks)
3293
- if tree==tree2
3294
- assert true
3295
- else
3296
- assert_equal recursive_compact!(tree), recursive_compact!(tree2)
3297
- warn "parsetree differed by nil(s), expression #{xmpl}"
3298
- @@differed_by_nil+=1
3299
- END{ puts "#@@differed_by_nil expressions differed by nil(s)" }
3807
+ h=nodes.hash
3808
+ tree2,warnings2=nodes.to_parsetree_and_warnings(*pt_opts)
3809
+ assert_equal h,nodes.hash
3810
+ assert_equal tree, tree2
3811
+ assert_equal warnings, warnings2 if ENV['WARN_PICKINESS']
3812
+ if warnings != warnings2
3813
+ if defined? @@mismatched_warnings
3814
+ @@mismatched_warnings+=1
3815
+ else
3816
+ @@mismatched_warnings=1
3817
+ at_exit{warn "mismatched warnings: #@@mismatched_warnings (set WARN_PICKINESS for details)"}
3818
+ end
3300
3819
  end
3301
3820
  rescue Exception=>e
3302
3821
  if problem_exprs
@@ -3313,26 +3832,40 @@ EOS
3313
3832
 
3314
3833
  end #until output.equal? tree
3315
3834
 
3316
- return #skip unparse tests for now
3835
+ # puts "warning: unparser tests disabled for now"
3836
+ # return #skip unparse tests for now
3317
3837
 
3318
- reparsed= RedParse.new(nodes.unparse({}),"-").parse
3319
- assert_equal nodes.delete_extraneous_ivars!,
3320
- reparsed.delete_extraneous_ivars!
3838
+ return unless nodes
3839
+ begin
3840
+ unparsed=nodes.unparse
3841
+ if unparsed==xmpl
3842
+ assert true
3843
+ return
3844
+ end
3845
+ reparsed= RedParse.new(unparsed,"-").parse
3846
+ if nodes.delete_extraneous_ivars! != reparsed.delete_extraneous_ivars!
3847
+ assert_equal nodes.delete_linenums!, reparsed.delete_linenums!
3848
+ warn "unparser doesn't preserve linenums perfectly in #{xmpl}"
3849
+ if defined? @@unparse_mismatched_linenums
3850
+ @@unparse_mismatched_linenums+=1
3851
+ else
3852
+ @@unparse_mismatched_linenums=1
3853
+ at_exit{warn "unparse mismatched linenums: #@@unparse_mismatched_linenums"}
3854
+ end
3855
+ else
3856
+ assert true
3857
+ end
3858
+ rescue Exception
3859
+ raise unless Exception===tree
3860
+ end
3321
3861
 
3322
- tree3=reparsed.to_parsetree(:quirks)
3323
- assert_equal tree, tree3
3862
+ unless Exception===tree
3863
+ tree3=reparsed.to_parsetree(*pt_opts)
3864
+ assert_equal tree, tree3
3865
+ else #missing a syntax errr, but that's been noted already
3866
+ end
3324
3867
 
3325
3868
  # rescue Exception=>e:
3326
3869
  # raise "error: #{e}:#{e.class} while testing '#{xmpl}'"
3327
3870
  end
3328
-
3329
- def recursive_compact!(tree)
3330
- return tree unless Array===tree
3331
- recursive_compact_!(tree)
3332
- end
3333
- def recursive_compact_!(tree)
3334
- tree.compact!
3335
- tree.each{|subtree| recursive_compact_!(subtree) if Array===subtree}
3336
- return tree
3337
- end
3338
3871
  end