redparse 0.8.3 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,162 @@
1
+ class Float
2
+ SIZE=[1.1].pack("d").size
3
+ BITSIZE=SIZE*8
4
+ BASE10_DIGITS=(2**BITSIZE-1).to_s.size
5
+ def accurate_to_s
6
+ return "#{'-' if self<0}Infinity" if infinite?
7
+ return "NaN" if nan?
8
+ return "0.0e0" if zero?
9
+
10
+ as_str=sprintf("%.#{BASE10_DIGITS+2}e",self)
11
+
12
+ #decompose self into sign, mantissa, and exponent (in string form)
13
+ all,sign,first,digits,exp=*as_str.match(/^([+-]?)(\d)\.(\d+)e(.*)$/)
14
+ digits=first<<digits
15
+ exp=exp.to_i+1
16
+ lead=sign<<"0."
17
+ return digits=digits if as_str.to_f.zero? #hopeless
18
+
19
+ #recompose back to a float
20
+ result=[lead,digits,"e",exp].join
21
+ result_f=result.to_f
22
+ delta=result_f - self
23
+ return digits=digits if delta.zero? #if representation is exact, return here
24
+
25
+ #figure out which direction to go to get toward the right answer
26
+ if delta<0
27
+ incr=1
28
+ else #delta>0
29
+ incr=-1
30
+ end
31
+
32
+ #keep adding increasing increments to mantissa
33
+ #until we get to a value on the other side of the correct answer
34
+ while true
35
+ while true
36
+ try_digits=digits.to_i.+(incr).to_s
37
+ if try_digits.size>digits.size
38
+ exp+=1
39
+ digits="0"+digits
40
+ end
41
+ fail if try_digits[0]==?- #can't happen... I think?
42
+ trying=[lead,try_digits,"e",exp].join
43
+ trying_f=trying.to_f
44
+ break unless trying_f.zero?
45
+ digits[-1,1]='' #workaround 1.8 bug
46
+ end
47
+ return digits=try_digits if trying_f==self
48
+ break if self.between?(*[trying_f,result_f].sort) #(trying_f-self)*delta<0
49
+ incr*=2
50
+ end
51
+
52
+ #we now have lower and upper bounds on the correct answer
53
+ lower,upper=*[digits.to_i, digits.to_i.+(incr)].sort
54
+
55
+ #maybe one of the bounds is already the correct answer?
56
+ result=[lead,lower,"e",exp].join
57
+ return digits=lower if result.to_f==self
58
+ result=[lead,upper,"e",exp].join
59
+ return digits=upper if result.to_f==self
60
+
61
+ #binary search between lower and upper bounds til we find a correct answer
62
+ digits=nil
63
+ while true
64
+ return as_str if upper-lower <= 1 #hopeless
65
+ mid=(lower+upper)/2
66
+ mid_s=[lead,mid,"e",exp].join
67
+ mid_f=mid_s.to_f
68
+ return digits=mid if mid_f==self
69
+ if mid_f<self
70
+ lower=mid
71
+ else #mid_f>self
72
+ upper=mid
73
+ end
74
+ end
75
+ ensure
76
+
77
+ #try to drop unneeded trailing digits
78
+ if digits
79
+ digits=digits.to_s
80
+ begin
81
+ last=digits.slice!( -1 )
82
+ result=[lead,digits,"e",exp].join.to_f
83
+ end while result==self or result.zero? && digits.size.nonzero?
84
+ roundup=(digits.to_i+1).to_s
85
+ if roundup.size>digits.size
86
+ exp+=1
87
+ digits="0"+digits
88
+ end
89
+ roundup.slice!( /0+\Z/ )
90
+ roundup=[lead,roundup,"e",exp].join
91
+ return roundup if roundup.to_f==self
92
+ return [lead,digits<<last,"e",exp].join
93
+ end
94
+ end
95
+ end
96
+
97
+ =begin not quite accurate, tho
98
+ class String
99
+ def accurate_to_f
100
+ all,sign,int,frac,exp=*self.match(/\A([+-])?([0-9_]+)(?:\.([0-9_]+))?(?:[eE]([+-]?[0-9_]+))?/)
101
+ exp=exp.to_i||0
102
+ exp-=frac.size
103
+ mantissa=sign<<int<<frac
104
+ mantissa=mantissa.to_f
105
+ scale=10.0**exp
106
+ return mantissa*scale
107
+ end
108
+ end
109
+ =end
110
+
111
+ eval DATA.read if __FILE__==$0
112
+ __END__
113
+
114
+ require 'test/unit'
115
+
116
+ class FloatRoundTripTest<Test::Unit::TestCase
117
+ def float_round_trip f
118
+ str=f.accurate_to_s
119
+ if str=="Infinity"
120
+ return 1.0/0
121
+ elsif str=="-Infinity"
122
+ return -1.0/0
123
+ elsif str=="NaN"
124
+ return 0.0/0.0
125
+ else
126
+ str.to_f
127
+ end
128
+ end
129
+ alias frt float_round_trip
130
+
131
+ def rand_float
132
+ base=rand
133
+ range=Float::MIN_10_EXP..Float::MAX_10_EXP
134
+ extent=range.last-range.first
135
+ offset=rand(extent+1)
136
+ exp=range.first+offset
137
+ base*=10**exp
138
+ end
139
+
140
+ def test_frt
141
+ data=[0.399891415240566, 0.198188037200931, 0.90302699802093,
142
+ 7.48121345153454520016e-01, 4.11408313999083175005e-02,
143
+ 2.68070684698467065488e-02, 3.85029229764812574999e-01,
144
+ "\327\237vY\343n\342?".unpack("d")[0],
145
+ 1.0/0, -1.0/0, 0.0/0.0,
146
+ "\333\211>4\253Atu".unpack("d")[0],
147
+ "\2461\220\253\214\267e\021".unpack("d")[0],
148
+ "\r\032N\f'\336\243\003".unpack("d")[0],
149
+ "B[\226\001\2175f\021".unpack("d")[0],
150
+ "%\217\336\362\326\272\026\001".unpack("d")[0],
151
+ "\312\342\344\206\237\024\"\003".unpack("d")[0],
152
+ ]
153
+ 1_000_000.times{|i|
154
+ f=data.shift||rand_float
155
+ p sprintf("%.#{Float::BASE10_DIGITS}e",f)
156
+ p [f].pack"d"
157
+ p f.accurate_to_s
158
+ f2=frt f
159
+ warn "failed with i=#{i} f=#{f}, #{[f].pack("d").inspect}; f2=#{f2}, #{[f2].pack("d").inspect}" unless [f].pack("d")==[f2].pack("d")
160
+ }
161
+ end
162
+ end
@@ -205,6 +205,10 @@ def repl(rule,m)
205
205
  when Class
206
206
  %[static VALUE repl_#{rule.name}=rb_const_lookup(rb_const_lookup(kNIL,"RedParse"),"#{repl.name});\n]
207
207
  when StackMonkey
208
+ huh
209
+ else
210
+ huh
211
+ end
208
212
  end
209
213
 
210
214
  def reduce(rule,m)
@@ -235,7 +239,7 @@ def reduce(rule,m)
235
239
  SEMANTIC_STACK_SET(yyredval); /* Copy ($$) onto semantic stack.*/
236
240
  goto nonterminal_#{str2cname repl.name}; /* Compute transition on produced node type.*/
237
241
  ]
238
- end
242
+ #end
239
243
 
240
244
  rescue Exception=>e
241
245
  backtrace.unshift("exception in reduce of rule #{rule.name} #{e.class}:#{e}").join("\n")
@@ -352,7 +356,7 @@ end
352
356
  }
353
357
  STRMAP_REX=/#{STRMAPPINGS.keys.map{|x| Regexp.quote x}.join "|"}/
354
358
  def self.str2cname str
355
- str.gsub(STRMAP_REX){|str| STRMAPPINGS[str] } \
359
+ str.gsub(STRMAP_REX){|str2| STRMAPPINGS[str2] } \
356
360
  .gsub(/(?!#{LETTER_DIGIT}).|[X]/o){|ch|
357
361
  "X"+ esc=CHARMAPPINGS[ch[0]] ? esc : ch[0].to_s(16)
358
362
  }
data/lib/redparse/node.rb CHANGED
@@ -27,13 +27,12 @@ require 'tempfile'
27
27
  require 'pp'
28
28
  require "rubylexer"
29
29
  require "reg"
30
-
30
+ require "redparse/float_accurate_to_s"
31
31
 
32
32
 
33
33
 
34
34
 
35
35
  class RedParse
36
- # module Nodes
37
36
  #import token classes from rubylexer
38
37
  RubyLexer::constants.each{|k|
39
38
  t=RubyLexer::const_get(k)
@@ -41,12 +40,14 @@ class RedParse
41
40
  }
42
41
 
43
42
  module FlattenedIvars
43
+ EXCLUDED_IVARS=%w[@data @offset @startline @endline]
44
+ EXCLUDED_IVARS.push(*EXCLUDED_IVARS.map{|iv| iv.to_sym })
44
45
  def flattened_ivars
45
- result=[]
46
- instance_variables.sort.each{|iv|
47
- if iv!="@data"
48
- result.push iv, instance_variable_get(iv)
49
- end
46
+ ivars=instance_variables
47
+ ivars-=EXCLUDED_IVARS
48
+ ivars.sort!
49
+ result=ivars+ivars.map{|iv|
50
+ instance_variable_get(iv)
50
51
  }
51
52
  return result
52
53
  end
@@ -148,7 +149,7 @@ class RedParse
148
149
  def identity_name
149
150
  k=self.class
150
151
  list=[k.name]
151
- list.concat k.boolean_identity_params.map{|(bip,)| bip if send(bip) }.compact
152
+ list.concat k.boolean_identity_params.map{|(bip,*)| bip if send(bip) }.compact
152
153
  list.concat k.identity_params.map{|(ip,variations)|
153
154
  val=send(ip)
154
155
  variations.include? val or fail "identity_param #{k}##{ip} unexpected value #{val.inspect}"
@@ -230,7 +231,7 @@ class RedParse
230
231
 
231
232
  def infix
232
233
  @infix if defined? @infix
233
- end unless instance_methods.include? "infix"
234
+ end unless allocate.respond_to? :infix
234
235
  end
235
236
 
236
237
  class OperatorToken
@@ -242,25 +243,18 @@ class RedParse
242
243
  ]+RubyLexer::OPORBEGINWORDLIST+%w<; lhs, rhs, rescue3>
243
244
  #identity_param :unary, true,false,nil
244
245
  #identity_param :tag, :lhs,:rhs,:param,:call,:array,:block,:nested,nil
245
-
246
- #this should be in rubylexer
247
- def as
248
- if tag and ident[/^[,*&]$/]
249
- tag.to_s+ident
250
- end
251
- end
252
246
  end
253
247
 
254
248
  class NumberToken
255
249
  alias to_lisp to_s
256
- def negative; /\A-/ === ident end unless instance_methods.include? "negative"
250
+ def negative; /\A-/ === ident end unless allocate.respond_to? :negative
257
251
 
258
252
  identity_param :negative, true,false
259
253
  end
260
254
 
261
255
  class MethNameToken
262
256
  alias to_lisp to_s
263
- def has_equals; /#{LETTER_DIGIT}=$/o===ident end unless instance_methods.include? "has_equals"
257
+ def has_equals; /#{LETTER_DIGIT}=$/o===ident end unless allocate.respond_to? :has_equals
264
258
 
265
259
  identity_param :has_equals, true,false
266
260
  end
@@ -367,6 +361,8 @@ class RedParse
367
361
  case val
368
362
  when Symbol
369
363
  val=CallNode[nil,val.to_s]
364
+ when Integer,Float
365
+ val=LiteralNode[val]
370
366
  end
371
367
  super( *args<<val )
372
368
  end
@@ -387,14 +383,8 @@ class RedParse
387
383
  @endline||=0
388
384
  end
389
385
 
390
- def flattened_ivars
391
- result=super
392
- result.each_with_index{|x,i|
393
- if i&1==0 and x!="@data"
394
- result[i,2]=[]
395
- end
396
- }
397
- result
386
+ def self.create(*args)
387
+ new(*args)
398
388
  end
399
389
 
400
390
  def ==(other)
@@ -416,6 +406,8 @@ class RedParse
416
406
  case val
417
407
  when Symbol
418
408
  val=CallNode[nil,val.to_s]
409
+ when Integer,Float
410
+ val=LiteralNode[val]
419
411
  end
420
412
  super( *args<<val )
421
413
  end
@@ -464,18 +456,84 @@ class RedParse
464
456
  return result
465
457
  end
466
458
 
467
- def inspect
468
- ivarnames=instance_variables-["@data"]
459
+ def inspect label=nil,indent=0
460
+ ivarnames=instance_variables-FlattenedIvars::EXCLUDED_IVARS
461
+ ivarnodes=[]
462
+ ivars=ivarnames.map{|ivarname|
463
+ ivar=instance_variable_get(ivarname)
464
+ if Node===ivar
465
+ ivarnodes.push [ivarname,ivar]
466
+ nil
467
+ else
468
+ ivarname[1..-1]+"="+ivar.inspect if ivar
469
+ end
470
+ }.compact.join(' ')
471
+
472
+
473
+ pos=@startline.to_s
474
+ pos<<"..#@endline" if @endline!=@startline
475
+ pos<<"@#@offset"
476
+ classname=self.class.name
477
+ classname.sub!(/^(?:RedParse::)?(.*?)(?:Node)?$/){$1}
478
+ result= [' '*indent,"+",(label+': ' if label),classname," pos=",pos," ",ivars,"\n"]
479
+ indent+=2
480
+
481
+ namelist=self.class.namelist
482
+ if namelist and !namelist.empty?
483
+ namelist.each{|name|
484
+ val=send name rescue "{{ERROR INSPECTING ATTR #{name}}}"
485
+ case val
486
+ when Node; result<< val.inspect(name,indent)
487
+ when ListInNode
488
+ result.push ' '*indent,"#{name}:\n",*val.map{|v|
489
+ v.inspect(nil,indent+2) rescue ' '*(indent+2)+"-#{v.inspect}\n"
490
+ }
491
+ when nil;
492
+ else ivars<< " #{name}=#{val.inspect}"
493
+ end
494
+ }
495
+ else
496
+ each{|val|
497
+ case val
498
+ when Node; result<< val.inspect(nil,indent)
499
+ else result<< ' '*indent+"-#{val.inspect}\n"
500
+ end
501
+ }
502
+ end
503
+
504
+ ivarnodes.each{|(name,val)|
505
+ result<< val.inspect(name,indent)
506
+ }
507
+
508
+ return result.join
509
+ end
510
+
511
+ def evalable_inspect
512
+ ivarnames=instance_variables-["@data", :@data]
469
513
  ivars=ivarnames.map{|ivarname|
470
- ":"+ivarname+"=>"+instance_variable_get(ivarname).inspect
514
+ val=instance_variable_get(ivarname)
515
+ if val.respond_to?(:evalable_inspect)
516
+ val=val.evalable_inspect
517
+ else
518
+ val=val.inspect
519
+ end
520
+ ":"+ivarname+"=>"+val
471
521
  }.join(', ')
472
- bare=super
522
+
523
+ bare="["+map{|val|
524
+ if val.respond_to?(:evalable_inspect)
525
+ val=val.evalable_inspect
526
+ else
527
+ val=val.inspect
528
+ end
529
+ }.join(", ")+"]"
530
+
473
531
  bare.gsub!(/\]\Z/, ", {"+ivars+"}]") unless ivarnames.empty?
474
532
  return self.class.name+bare
475
533
  end
476
-
534
+
477
535
  def pretty_print(q)
478
- ivarnames=instance_variables-["@data"]
536
+ ivarnames=instance_variables-["@data", :@data]
479
537
  ivars={}
480
538
  ivarnames.each{|ivarname|
481
539
  ivars[ivarname.to_sym]=instance_variable_get(ivarname)
@@ -493,29 +551,32 @@ class RedParse
493
551
  def self.param_names(*names)
494
552
  accessors=[]
495
553
  namelist=[]
496
- namelist2=[]
554
+ @namelist=[]
497
555
  names.each{|name|
498
556
  name=name.to_s
499
557
  last=name[-1]
500
558
  name.chomp! '!' and name << ?_
501
- namelist2 << name
559
+ namelist << name
502
560
  unless last==?_
503
- accessors << "def #{name.chomp('_')}; self[#{namelist.size}] end\n"
504
- accessors << "def #{name.chomp('_')}=(newval); self[#{namelist.size}]=newval end\n"
505
- namelist << name
561
+ accessors << "def #{name.chomp('_')}; self[#{@namelist.size}] end\n"
562
+ accessors << "def #{name.chomp('_')}=(newval); "+
563
+ "newval.extend ::RedParse::ListInNode if ::Array===newval and not RedParse::Node===newval;"+
564
+ "self[#{@namelist.size}]=newval "+
565
+ "end\n"
566
+ @namelist << name
506
567
  end
507
568
  }
508
569
  init="
509
- def initialize(#{namelist2.join(', ')})
510
- replace [#{namelist.size==1 ?
511
- namelist.first :
512
- namelist.join(', ')
570
+ def initialize(#{namelist.join(', ')})
571
+ replace [#{@namelist.size==1 ?
572
+ @namelist.first :
573
+ @namelist.join(', ')
513
574
  }]
514
575
  end
515
576
  alias init_data initialize
516
577
  "
517
578
 
518
- code= "class ::#{self}\n"+init+accessors.to_s+"\nend\n"
579
+ code= "class ::#{self}\n"+init+accessors.join+"\nend\n"
519
580
  if defined? DEBUGGER__ or defined? Debugger
520
581
  Tempfile.open("param_name_defs"){|f|
521
582
  f.write code
@@ -525,6 +586,15 @@ class RedParse
525
586
  else
526
587
  eval code
527
588
  end
589
+
590
+ @namelist.reject!{|name| /_\Z/===name }
591
+ end
592
+
593
+ def self.namelist
594
+ #@namelist
595
+ result=superclass.namelist||[] rescue []
596
+ result.concat @namelist if defined? @namelist
597
+ return result
528
598
  end
529
599
 
530
600
  def lhs_unparse o; unparse(o) end
@@ -584,12 +654,14 @@ class RedParse
584
654
  end
585
655
 
586
656
  def depthwalk(parent=nil,index=nil,subindex=nil,&callback)
587
- each_with_index{|datum,i|
657
+ (size-1).downto(0){|i|
658
+ datum=self[i]
588
659
  case datum
589
660
  when Node
590
661
  datum.depthwalk(self,i,&callback)
591
662
  when Array
592
- datum.each_with_index{|x,j|
663
+ (datum.size-1).downto(0){|j|
664
+ x=datum[j]
593
665
  if Node===x
594
666
  x.depthwalk(self,i,j,&callback)
595
667
  else
@@ -603,6 +675,24 @@ class RedParse
603
675
  callback[ parent,index,subindex,self ]
604
676
  end
605
677
 
678
+ def depthwalk_nodes(parent=nil,index=nil,subindex=nil,&callback)
679
+ (size-1).downto(0){|i|
680
+ datum=self[i]
681
+ case datum
682
+ when Node
683
+ datum.depthwalk_nodes(self,i,&callback)
684
+ when Array
685
+ (datum.size-1).downto(0){|j|
686
+ x=datum[j]
687
+ if Node===x
688
+ x.depthwalk_nodes(self,i,j,&callback)
689
+ end
690
+ }
691
+ end
692
+ }
693
+ callback[ parent,index,subindex,self ]
694
+ end
695
+
606
696
  def add_parent_links!
607
697
  walk{|parent,i,subi,o|
608
698
  o.parent=parent if Node===o
@@ -611,30 +701,101 @@ class RedParse
611
701
 
612
702
  attr_accessor :parent
613
703
 
614
- def xform_tree!(xformer)
704
+ def xform_tree!(*xformers)
705
+ #search tree for patterns and store results of actions in session
615
706
  session={}
616
707
  depthwalk{|parent,i,subi,o|
617
- xformer.xform!(o,session) if o
708
+ xformers.each{|xformer|
709
+ if o
710
+ tempsession={}
711
+ xformer.xform!(o,tempsession)
712
+ merge_replacement_session session, tempsession
713
+ #elsif xformer===o and Reg::Transform===xformer
714
+ # new=xformer.right
715
+ # if Reg::Formula===right
716
+ # new=new.formula_value(o,session)
717
+ # end
718
+ # subi ? parent[i][subi]=new : parent[i]=new
719
+ end
720
+ }
618
721
  }
619
722
  session["final"]=true
723
+
724
+ #apply saved-up actions stored in session, while making a copy of tree
725
+ result=::Ron::GraphWalk::graphcopy(self,old2new={}){|cntr,o,i,ty,useit|
726
+ newo=nil
727
+ replace_value o.__id__,o,session do |val|
728
+ newo=val
729
+ useit[0]=true
730
+ end
731
+ newo
732
+ }
733
+ finallys=session["finally"] #finallys too
734
+ finallys.each{|(action,arg)| action[old2new[arg.__id__],session] } if finallys
735
+
736
+ return result
737
+ =begin was
738
+ finallys=session["finally"]
739
+ finallys.each{|(action,arg)| action[arg] } if finallys
740
+
620
741
  depthwalk{|parent,i,subi,o|
621
- if session.has_key? o.__id__
622
- new= session[o.__id__]
623
- if Reg::Formula===new
624
- new=new.formula_value(o,session)
625
- end
742
+ next unless parent
743
+ replace_ivars_and_self o, session do |new|
626
744
  subi ? parent[i][subi]=new : parent[i]=new
627
745
  end
628
746
  }
629
- if session.has_key? self.__id__
630
- new= session[self.__id__]
631
- if Reg::Formula===new
632
- new=new.formula_value(self,session)
633
- end
747
+ replace_ivars_and_self self,session do |new|
748
+ fail unless new
634
749
  return new
635
- else
636
- return self
637
750
  end
751
+
752
+ return self
753
+ =end
754
+ end
755
+
756
+ def replace_ivars_and_self o,session,&replace_self_action
757
+ o.instance_variables.each{|ovname|
758
+ ov=o.instance_variable_get(ovname)
759
+
760
+ replace_value ov.__id__,ov,session do |new|
761
+ o.instance_variable_set(ovname,new)
762
+ end
763
+ }
764
+ replace_value o.__id__,o,session, &replace_self_action
765
+ end
766
+
767
+ def replace_value ovid,ov,session,&replace_action
768
+ if session.has_key? ovid
769
+ new= session[ovid]
770
+ if Reg::Formula===new
771
+ new=new.formula_value(ov,session)
772
+ end
773
+ replace_action[new]
774
+ end
775
+ end
776
+
777
+ def merge_replacement_session session,tempsession
778
+ ts_has_boundvars= !tempsession.keys.grep(::Symbol).empty?
779
+ tempsession.each_pair{|k,v|
780
+ if Integer===k
781
+ if true
782
+ v=Reg::WithBoundRefValues.new(v,tempsession) if ts_has_boundvars
783
+ else
784
+ v=Ron::GraphWalk.graphcopy(v){|cntr,o,i,ty,useit|
785
+ if Reg::BoundRef===o
786
+ useit[0]=true
787
+ tempsession[o.name]||o
788
+ end
789
+ }
790
+ end
791
+ if session.has_key? k
792
+ v=v.chain_to session[k]
793
+ end
794
+ session[k]=v
795
+ elsif "finally"==k
796
+ session["finally"]=Array(session["finally"]).concat v
797
+ end
798
+ }
638
799
  end
639
800
 
640
801
  def linerange
@@ -657,7 +818,7 @@ class RedParse
657
818
  j=nil
658
819
  list=Array.new(node)
659
820
  assignnode=nil
660
- list.each_with_index{|assignnode,jj|
821
+ list.each_with_index{|assignnode2,jj| assignnode=assignnode2
661
822
  AssignNode===assignnode and break(j=jj)
662
823
  }
663
824
  fail "CommaOpNode without any assignment in final parse tree" unless j
@@ -782,38 +943,36 @@ class RedParse
782
943
  def unary; false end
783
944
  def lvalue; nil end
784
945
 
946
+ #why not use Ron::GraphWalk.graph_copy instead here?
785
947
  def deep_copy transform={},&override
786
948
  handler=proc{|child|
787
949
  if transform.has_key? child.__id__
788
950
  transform[child.__id__]
789
951
  else
790
952
  case child
791
- when Node:
953
+ when Node
792
954
  override&&override[child] or
793
955
  child.deep_copy(transform,&override)
794
- when Array:
795
- child.map(&handler)
796
- when Integer,Symbol,Float,nil,false,true,Module:
956
+ when Array
957
+ child.clone.map!(&handler)
958
+ when Integer,Symbol,Float,nil,false,true,Module
797
959
  child
798
960
  else
799
- child.dup
961
+ child.clone
800
962
  end
801
963
  end
802
964
  }
803
965
 
804
966
  newdata=map(&handler)
805
967
 
806
- h={}
807
- result_module=nil
968
+ result=clone
808
969
  instance_variables.each{|iv|
809
- unless iv=="@data"
970
+ unless iv=="@data" or iv==:@data
810
971
  val=instance_variable_get(iv)
811
- h[iv]=handler[val]
812
- result_module=val if iv=="@module" #hacky
972
+ result.instance_variable_set(iv,handler[val])
813
973
  end
814
974
  }
815
- result= self.class[*newdata << h]
816
- result.extend result_module if result_module
975
+ result.replace newdata
817
976
  return result
818
977
  end
819
978
 
@@ -823,6 +982,7 @@ class RedParse
823
982
  when Node
824
983
  node.remove_instance_variable :@offset rescue nil
825
984
  node.remove_instance_variable :@loopword_offset rescue nil
985
+ node.remove_instance_variable :@iftok_offset rescue nil
826
986
  node.remove_instance_variable :@endline rescue nil
827
987
  node.remove_instance_variable :@lvalue rescue nil
828
988
  if node.respond_to? :lvalue
@@ -862,8 +1022,8 @@ class RedParse
862
1022
  def +@
863
1023
  node2matcher=proc{|n|
864
1024
  case n
865
- when Node: +n
866
- when Array: +[*n.map(&node2matcher)]
1025
+ when Node; +n
1026
+ when Array; +[*n.map(&node2matcher)]
867
1027
  else n
868
1028
  end
869
1029
  }
@@ -952,12 +1112,12 @@ class RedParse
952
1112
  end
953
1113
 
954
1114
  class VarNode<ValueNode
1115
+ param_names :ident
955
1116
  include FlattenedIvars
956
1117
  attr_accessor :endline,:offset
957
1118
  attr_reader :lvar_type,:in_def
958
1119
  attr_writer :lvalue
959
1120
 
960
-
961
1121
  alias == flattened_ivars_equal?
962
1122
 
963
1123
  def initialize(tok)
@@ -968,8 +1128,8 @@ class RedParse
968
1128
  @in_def=tok.in_def
969
1129
  end
970
1130
 
971
- def ident; first end
972
- def ident=x; self[0]=x end
1131
+ # def ident; first end
1132
+ # def ident=x; self[0]=x end
973
1133
  alias image ident
974
1134
  alias startline endline
975
1135
  alias name ident
@@ -977,7 +1137,7 @@ class RedParse
977
1137
 
978
1138
  def parsetree(o)
979
1139
  type=case ident[0]
980
- when ?$:
1140
+ when ?$
981
1141
  case ident[1]
982
1142
  when ?1..?9; return [:nth_ref,ident[1..-1].to_i]
983
1143
  when ?&,?+,?`,?'; return [:back_ref,ident[1].chr.to_sym] #`
@@ -1040,7 +1200,7 @@ class RedParse
1040
1200
 
1041
1201
  def dup
1042
1202
  result=super
1043
- result.ident=@ident.dup if @ident
1203
+ result.ident=ident.dup if ident
1044
1204
  return result
1045
1205
  end
1046
1206
 
@@ -1059,52 +1219,79 @@ end
1059
1219
  end
1060
1220
 
1061
1221
  #forward decls
1062
- module ArrowOpNode; end
1063
- module RangeNode; end
1064
- module LogicalNode; end
1065
- module WhileOpNode; end
1066
- module UntilOpNode; end
1067
- module IfOpNode; end
1068
- module UnlessOpNode; end
1069
- module OpNode; end
1070
- module NotEqualNode; end
1071
- module MatchNode; end
1072
- module NotMatchNode; end
1073
-
1074
- OP2MIXIN={
1075
- "=>"=>ArrowOpNode,
1076
- ".."=>RangeNode,
1077
- "..."=>RangeNode,
1078
- "&&"=>LogicalNode,
1079
- "||"=>LogicalNode,
1080
- "and"=>LogicalNode,
1081
- "or"=>LogicalNode,
1082
- "while"=>WhileOpNode,
1083
- "until"=>UntilOpNode,
1084
- "if"=>IfOpNode,
1085
- "unless"=>UnlessOpNode,
1222
+ class RawOpNode<ValueNode
1223
+ end
1224
+ class OpNode<RawOpNode
1225
+ end
1226
+ class NotEqualNode<OpNode
1227
+ end
1228
+ class MatchNode<OpNode
1229
+ end
1230
+ class NotMatchNode<OpNode
1231
+ end
1232
+ class ArrowOpNode<RawOpNode
1233
+ end
1234
+ class RescueOpNode<RawOpNode
1235
+ end
1236
+ class LogicalNode<RawOpNode
1237
+ end
1238
+ class AndNode<LogicalNode
1239
+ end
1240
+ class OrNode<LogicalNode
1241
+ end
1242
+ class RangeNode<RawOpNode
1243
+ end
1244
+ class IfOpNode<RawOpNode
1245
+ end
1246
+ class UnlessOpNode<RawOpNode
1247
+ end
1248
+ class WhileOpNode<RawOpNode
1249
+ end
1250
+ class UntilOpNode<RawOpNode
1251
+ end
1252
+
1253
+ OP2CLASS={
1086
1254
  "!="=>NotEqualNode,
1087
1255
  "!~"=>NotMatchNode,
1088
1256
  "=~"=>MatchNode,
1257
+ "if"=>IfOpNode,
1258
+ "unless"=>UnlessOpNode,
1259
+ "while"=>WhileOpNode,
1260
+ "until"=>UntilOpNode,
1261
+ ".."=>RangeNode,
1262
+ "..."=>RangeNode,
1263
+ "=>"=>ArrowOpNode,
1264
+ "&&"=>AndNode,
1265
+ "||"=>OrNode,
1266
+ "and"=>AndNode,
1267
+ "or"=>OrNode,
1268
+ "rescue"=>RescueOpNode,
1269
+ "rescue3"=>RescueOpNode,
1089
1270
  }
1090
1271
 
1091
1272
  class RawOpNode<ValueNode
1092
1273
  param_names(:left,:op,:right)
1093
- def initialize(left,op,right)
1094
- @offset=op.offset
1095
- op=op.ident
1274
+ def initialize(left,op,right=nil)
1275
+ op,right=nil,op if right.nil?
1276
+ if op.respond_to? :ident
1277
+ @offset=op.offset
1278
+ op=op.ident
1279
+ end
1096
1280
  super(left,op,right)
1097
- Array((OP2MIXIN[op]||OpNode)).each{|mod|
1098
- extend(mod)
1099
- mod.instance_method(:initialize).bind(self).call(left,op,right)
1100
- }
1101
1281
  end
1102
- def self.[](*args)
1103
- result=super
1104
- @module and extend @module
1105
- return result
1282
+
1283
+ # def initialize_copy other
1284
+ # rebuild(other.left,other.op,other.right)
1285
+ # end
1286
+
1287
+ def self.create(left,op,right)
1288
+ op_s=op.ident
1289
+ k=OP2CLASS[op_s]||OpNode
1290
+ k.new(left,op,right)
1106
1291
  end
1292
+
1107
1293
  def image; "(#{op})" end
1294
+
1108
1295
  def raw_unparse o
1109
1296
  l=left.unparse(o)
1110
1297
  l[/(~| \Z)/] and maybesp=" "
@@ -1112,10 +1299,11 @@ end
1112
1299
  end
1113
1300
  end
1114
1301
 
1115
- module OpNode
1302
+ class OpNode<RawOpNode
1116
1303
  def initialize(left,op,right)
1117
1304
  #@negative_of="="+$1 if /^!([=~])$/===op
1118
- @module=OpNode
1305
+ op=op.ident if op.respond_to? :ident
1306
+ super left,op,right
1119
1307
  end
1120
1308
  def to_lisp
1121
1309
  "(#{op} #{left.to_lisp} #{right.to_lisp})"
@@ -1141,8 +1329,13 @@ end
1141
1329
  # def unparse o=default_unparse_options; raw_unparse o end
1142
1330
  end
1143
1331
 
1144
- module MatchNode
1145
- include OpNode
1332
+ class MatchNode<OpNode
1333
+ param_names :left,:op_,:right
1334
+
1335
+ def initialize(left,op,right=nil)
1336
+ op,right=nil,op unless right
1337
+ replace [left,right]
1338
+ end
1146
1339
 
1147
1340
  def parsetree(o)
1148
1341
  if StringNode===left and left.char=='/'
@@ -1156,8 +1349,13 @@ end
1156
1349
  def op; "=~"; end
1157
1350
  end
1158
1351
 
1159
- module NotEqualNode
1160
- include OpNode
1352
+ class NotEqualNode<OpNode
1353
+ param_names :left,:op_,:right
1354
+
1355
+ def initialize(left,op,right=nil)
1356
+ op,right=nil,op unless right
1357
+ replace [left,right]
1358
+ end
1161
1359
 
1162
1360
  def parsetree(o)
1163
1361
  result=opnode_parsetree(o)
@@ -1168,8 +1366,13 @@ end
1168
1366
  def op; "!="; end
1169
1367
  end
1170
1368
 
1171
- module NotMatchNode
1172
- include NotEqualNode
1369
+ class NotMatchNode<OpNode
1370
+ param_names :left,:op_,:right
1371
+
1372
+ def initialize(left,op,right=nil)
1373
+ op,right=nil,op unless right
1374
+ replace [left,right]
1375
+ end
1173
1376
 
1174
1377
  def parsetree(o)
1175
1378
  if StringNode===left and left.char=="/"
@@ -1177,7 +1380,9 @@ end
1177
1380
  elsif StringNode===right and right.char=="/"
1178
1381
  [:not, [:match3, right.parsetree(o), left.parsetree(o)]]
1179
1382
  else
1180
- super
1383
+ result=opnode_parsetree(o)
1384
+ result[2]="=#{op[1..1]}".to_sym
1385
+ result=[:not, result]
1181
1386
  end
1182
1387
  end
1183
1388
 
@@ -1211,6 +1416,26 @@ end
1211
1416
  end
1212
1417
  attr_writer :lvalue
1213
1418
  identity_param :lvalue, nil, true
1419
+
1420
+ def extract_unbraced_hash
1421
+ param_list=Array.new(self)
1422
+ first=last=nil
1423
+ param_list.each_with_index{|param,i|
1424
+ break first=i if ArrowOpNode===param
1425
+ }
1426
+ (1..param_list.size).each{|i| param=param_list[-i]
1427
+ break last=-i if ArrowOpNode===param
1428
+ }
1429
+ if first
1430
+ arrowrange=first..last
1431
+ arrows=param_list[arrowrange]
1432
+ h=HashLiteralNode.new(nil,arrows,nil)
1433
+ h.offset=arrows.first.offset
1434
+ h.startline=arrows.first.startline
1435
+ h.endline=arrows.last.endline
1436
+ return h,arrowrange
1437
+ end
1438
+ end
1214
1439
  end
1215
1440
 
1216
1441
  class LiteralNode<ValueNode; end
@@ -1297,9 +1522,8 @@ end
1297
1522
  return "" if empty?
1298
1523
  unparse_nl(first,o,'')+first.unparse(o)+
1299
1524
  self[1..-1].map{|expr|
1300
- # p expr
1301
1525
  unparse_nl(expr,o)+expr.unparse(o)
1302
- }.to_s
1526
+ }.join
1303
1527
  end
1304
1528
  end
1305
1529
 
@@ -1316,7 +1540,7 @@ end
1316
1540
  sum=''
1317
1541
  type=:str
1318
1542
  tree=i=nil
1319
- result.each_with_index{|tree,i|
1543
+ result.each_with_index{|tree2,i2| tree,i=tree2,i2
1320
1544
  sum+=tree[1]
1321
1545
  tree.first==:str or break(type=:dstr)
1322
1546
  }
@@ -1344,42 +1568,70 @@ end
1344
1568
  end
1345
1569
  end
1346
1570
 
1347
- # class ArrowOpNode<ValueNode
1348
- # param_names(:left,:arrow_,:right)
1349
- # end
1350
- module ArrowOpNode
1351
- def initialize(*args)
1352
- @module=ArrowOpNode
1353
- end
1571
+ class ArrowOpNode
1572
+ param_names(:left,:op,:right)
1354
1573
 
1355
- def unparse(o=default_unparse_options)
1356
- left.unparse(o)+" => "+right.unparse(o)
1357
- end
1358
- end
1359
-
1360
- # class RangeNode<ValueNode
1361
- module RangeNode
1362
- # param_names(:first,:op_,:last)
1363
- def initialize(left,op_,right)
1364
- @exclude_end=!!op_[2]
1365
- @module=RangeNode
1574
+ def initialize(*args)
1575
+ super
1576
+ end
1577
+
1578
+ #def unparse(o=default_unparse_options)
1579
+ # left.unparse(o)+" => "+right.unparse(o)
1580
+ #end
1581
+ end
1582
+
1583
+ class RangeNode
1584
+ param_names(:first,:op,:last)
1585
+ def initialize(left,op,right=nil)
1586
+ op,right="..",op unless right
1587
+ op=op.ident if op.respond_to? :ident
1588
+ @exclude_end=!!op[2]
1366
1589
  @as_flow_control=false
1367
- # super(left,right)
1590
+ super(left,op,right)
1368
1591
  end
1369
- def begin; left end
1370
- def end; right end
1371
- def first; left end
1372
- def last; right end
1592
+ def begin; first end
1593
+ def end; last end
1594
+ def left; first end
1595
+ def right; last end
1373
1596
  def exclude_end?; @exclude_end end
1374
1597
 
1598
+ # def self.[] *list
1599
+ # result=RawOpNode[*list]
1600
+ # result.extend RangeNode
1601
+ # return result
1602
+ # end
1603
+
1604
+ def self.[] *list
1605
+ new(*list)
1606
+ end
1607
+
1375
1608
  def parsetree(o)
1376
1609
  first=first().parsetree(o)
1377
1610
  last=last().parsetree(o)
1378
- if :lit==first.first and :lit==last.first and
1379
- Fixnum===first.last and Fixnum===last.last
1380
- return [:lit, Range.new(first.last,last.last,@exclude_end)]
1611
+ if @as_flow_control
1612
+ if :lit==first.first and Integer===first.last
1613
+ first=[:call, [:lit, first.last], :==, [:array, [:gvar, :$.]]]
1614
+ elsif :lit==first.first && Regexp===first.last or
1615
+ :dregx==first.first || :dregx_once==first.first
1616
+ first=[:match, first]
1617
+ end
1618
+
1619
+ if :lit==last.first and Integer===last.last
1620
+ last=[:call, [:lit, last.last], :==, [:array, [:gvar, :$.]]]
1621
+ elsif :lit==last.first && Regexp===last.last or
1622
+ :dregx==last.first || :dregx_once==last.first
1623
+ last=[:match, last]
1624
+ end
1625
+
1626
+ tag="flip"
1627
+ else
1628
+ if :lit==first.first and :lit==last.first and
1629
+ Fixnum===first.last and Fixnum===last.last and
1630
+ LiteralNode===first() and LiteralNode===last()
1631
+ return [:lit, Range.new(first.last,last.last,@exclude_end)]
1632
+ end
1633
+ tag="dot"
1381
1634
  end
1382
- tag= @as_flow_control ? "flip" : "dot"
1383
1635
  count= @exclude_end ? ?3 : ?2
1384
1636
  tag << count
1385
1637
  [tag.to_sym, first, last]
@@ -1400,8 +1652,8 @@ end
1400
1652
  class UnOpNode<ValueNode
1401
1653
  param_names(:op,:val)
1402
1654
  def initialize(op,val)
1403
- @offset=op.offset
1404
- op=op.ident
1655
+ @offset||=op.offset rescue val.offset
1656
+ op=op.ident if op.respond_to? :ident
1405
1657
  /([&*])$/===op and op=$1+"@"
1406
1658
  /^(?:!|not)$/===op and
1407
1659
  val.respond_to? :special_conditions! and
@@ -1454,11 +1706,16 @@ end
1454
1706
  end
1455
1707
 
1456
1708
  class UnaryStarNode<UnOpNode
1457
- def initialize(op,val)
1458
- op.ident="*@"
1709
+ def initialize(op,val=nil)
1710
+ op,val="*@",op unless val
1711
+ op.ident="*@" if op.respond_to? :ident
1459
1712
  super(op,val)
1460
1713
  end
1461
1714
 
1715
+ class<<self
1716
+ alias [] new
1717
+ end
1718
+
1462
1719
  def parsetree(o)
1463
1720
  [:splat, val.rescue_parsetree(o)]
1464
1721
  end
@@ -1482,10 +1739,10 @@ end
1482
1739
 
1483
1740
  class DanglingStarNode<UnaryStarNode
1484
1741
  #param_names :op,:val
1485
- def initialize(star)
1486
- @offset= star.offset
1487
- replace ['*@',var=VarNode.new(VarNameToken.new('',offset))]
1488
- var.startline=var.endline=star.startline
1742
+ def initialize(star,var=nil)
1743
+ @offset= star.offset if star.respond_to? :offset
1744
+ @startline=@endline=star.startline if star.respond_to? :startline
1745
+ super('*@',var||VarNode[''])
1489
1746
  end
1490
1747
  attr :offset
1491
1748
  def lvars_defined_in; [] end
@@ -1554,6 +1811,13 @@ end
1554
1811
  end
1555
1812
  attr_writer :lvalue
1556
1813
  identity_param :lvalue, nil, true
1814
+
1815
+ def inspect label=nil,indent=0
1816
+ result=' '*indent
1817
+ result+="#{label}: " if label
1818
+ result+='Constant '
1819
+ result+=map{|name| name.inspect}.join(', ')+"\n"
1820
+ end
1557
1821
  end
1558
1822
  LookupNode=ConstantNode
1559
1823
 
@@ -1613,139 +1877,10 @@ end
1613
1877
  attr_writer :lvalue
1614
1878
  end
1615
1879
 
1616
- =begin
1617
- class OldParenedNode<ValueNode
1618
- param_names :body, :rescues, :else!, :ensure!
1619
- def initialize(*args)
1620
- @empty_ensure=@op_rescue=nil
1621
- replace(
1622
- if args.size==3 #()
1623
- if (KeywordToken===args.first and args.first.ident=='(')
1624
- [args[1]]
1625
- else
1626
- expr,rescueword,backup=*args
1627
- @op_rescue=true
1628
- [expr,[RescueNode[[],nil,backup]],nil,nil]
1629
- end
1630
- else
1631
- body,rescues,else_,ensure_=*args[1...-1]
1632
- if else_
1633
- else_=else_.val or @empty_else=true
1634
- end
1635
- if ensure_
1636
- ensure_=ensure_.val or @empty_ensure=true
1637
- end
1638
- [body,rescues,else_,ensure_]
1639
- end
1640
- )
1641
- end
1642
-
1643
- alias ensure_ ensure
1644
- alias else_ else
1645
-
1646
- attr_reader :empty_ensure, :empty_else
1647
- attr_accessor :after_comma, :after_equals
1648
- def op?; @op_rescue; end
1649
-
1650
- def image; '(begin)' end
1651
-
1652
- def special_conditions!
1653
- if size==1
1654
- node=body
1655
- node.special_conditions! if node.respond_to? :special_conditions!
1656
- end
1657
- end
1658
-
1659
- def to_lisp
1660
- huh #what about rescues, else, ensure?
1661
- body.to_lisp
1662
- end
1663
-
1664
- def parsetree(o)
1665
- if size==1
1666
- body.parsetree(o)
1667
- else
1668
- body=body()
1669
- target=result=[] #was: [:begin, ]
1670
-
1671
- #body,rescues,else_,ensure_=*self
1672
- target.push target=[:ensure, ] if ensure_ or @empty_ensure
1673
-
1674
- rescues=rescues().map{|resc| resc.parsetree(o)}
1675
- if rescues.empty?
1676
- else_ and
1677
- body=SequenceNode.new(body,nil,else_)
1678
- else_=nil
1679
- else
1680
- target.push newtarget=[:rescue, ]
1681
- else_=else_()
1682
- end
1683
- if body
1684
- needbegin= (BeginNode===body and body.after_equals)
1685
- body=body.parsetree(o)
1686
- body=[:begin, body] if needbegin and body.first!=:begin and !o[:ruby187]
1687
- (newtarget||target).push body if body
1688
- end
1689
- target.push ensure_.parsetree(o) if ensure_
1690
- target.push [:nil] if @empty_ensure
1691
- target=newtarget if newtarget
1692
-
1693
- unless rescues.empty?
1694
- target.push linked_list(rescues)
1695
- end
1696
- target.push else_.parsetree(o) if else_ #and !body
1697
- result.size==0 and result=[[:nil]]
1698
- result=result.last #if @op_rescue
1699
- result=[:begin,result] unless o[:ruby187]||op?||result==[:nil]#||result.first==:begin
1700
- result
1701
- end
1702
- end
1703
-
1704
- def rescue_parsetree o
1705
- result=parsetree o
1706
- result.first==:begin and result=result.last unless o[:ruby187]
1707
- result
1708
- end
1709
-
1710
- def begin_parsetree(o)
1711
- body,rescues,else_,ensure_=*self
1712
- needbegin=(rescues&&!rescues.empty?) || ensure_ || @empty_ensure
1713
- result=parsetree(o)
1714
- needbegin and result=[:begin, result] unless result.first==:begin
1715
- result
1716
- end
1717
-
1718
- def lvalue
1719
- return nil unless size==1
1720
- # case first
1721
- # when CommaOpNode,UnaryStarNode: #do nothing
1722
- # when ParenedNode: return first.lvalue
1723
- # else return nil
1724
- # end
1725
-
1726
- return @lvalue if defined? @lvalue
1727
- @lvalue=true
1728
- end
1729
- attr_writer :lvalue
1730
-
1731
- def unparse(o=default_unparse_options)
1732
- if size==1
1733
- "("+(body&&body.unparse(o))+")"
1734
- else
1735
- result="begin "
1736
- body&&result+= body.unparse(o)
1737
- result+=unparse_nl(rescues.first,o)
1738
- rescues.each{|resc| result+=resc.unparse(o) }
1739
- result+=unparse_nl(ensure_,o)+"ensure "+ensure_.unparse(o) if ensure_
1740
- result+=unparse_nl(else_,o)+"else "+else_.unparse(o) if else_
1741
- result+=";end"
1742
- end
1743
- end
1744
- end
1745
- =end
1746
-
1747
1880
  class ParenedNode<ValueNode
1748
- param_names :body #, :rescues, :else!, :ensure!
1881
+ param_names :body
1882
+ alias val body
1883
+ alias val= body=
1749
1884
  def initialize(lparen,body,rparen)
1750
1885
  @offset=lparen.offset
1751
1886
  self[0]=body
@@ -1825,7 +1960,11 @@ end
1825
1960
  end
1826
1961
  target.push else_.parsetree(o) if else_ #and !body
1827
1962
  result.size==0 and result=[[:nil]]
1828
- result=result.last #if @op_rescue
1963
+ if o[:ruby187] and !rescues.empty?
1964
+ result.unshift :begin
1965
+ else
1966
+ result=result.last
1967
+ end
1829
1968
  result
1830
1969
  end
1831
1970
 
@@ -1839,7 +1978,7 @@ end
1839
1978
  result+=unparse_nl(ensure_,o)+"ensure "+ensure_.unparse(o) if ensure_
1840
1979
  result+=";ensure" if @empty_ensure
1841
1980
  return result
1842
- end
1981
+ end
1843
1982
 
1844
1983
  end
1845
1984
 
@@ -1887,7 +2026,11 @@ end
1887
2026
 
1888
2027
  def parsetree(o)
1889
2028
  result=parsetree_and_rescues(o)
1890
- result=[:begin,result] unless o[:ruby187]||result==[:nil]#||result.first==:begin
2029
+ if o[:ruby187] and result.first==:begin
2030
+ result=result[1]
2031
+ else
2032
+ result=[:begin,result] unless result==[:nil]#||result.first==:begin
2033
+ end
1891
2034
  return result
1892
2035
  end
1893
2036
 
@@ -1917,8 +2060,14 @@ end
1917
2060
  end
1918
2061
  end
1919
2062
 
1920
- class RescueOpNode<ValueNode
1921
- # include OpNode
2063
+ module KeywordOpNode
2064
+ def unparse o=default_unparse_options
2065
+ [left.unparse(o),' ',op,' ',right.unparse(o)].join
2066
+ end
2067
+ end
2068
+
2069
+ class RescueOpNode<RawOpNode
2070
+ include KeywordOpNode
1922
2071
  param_names :body, :rescues #, :else!, :ensure!
1923
2072
  def initialize(expr,rescueword,backup)
1924
2073
  replace [expr,[RescueNode[[],nil,backup]].extend(ListInNode)]
@@ -1928,7 +2077,7 @@ end
1928
2077
  def ensure; nil end
1929
2078
 
1930
2079
  def left; body end
1931
- def right; rescues.action end
2080
+ def right; rescues[0].action end
1932
2081
 
1933
2082
  alias ensure_ ensure
1934
2083
  alias else_ else
@@ -2015,12 +2164,34 @@ end
2015
2164
  param_names :left,:op,:right
2016
2165
  alias lhs left
2017
2166
  alias rhs right
2167
+ def self.create(*args)
2168
+ if args.size==5
2169
+ if args[3].ident=="rescue3"
2170
+ lhs,op,rescuee,op2,rescuer=*args
2171
+ if MULTIASSIGN===lhs or !rescuee.is_list
2172
+ return RescueOpNode.new(AssignNode.new(lhs,op,rescuee),nil,rescuer)
2173
+ else
2174
+ rhs=RescueOpNode.new(rescuee.val,op2,rescuer)
2175
+ end
2176
+ else
2177
+ lhs,op,bogus1,rhs,bogus2=*args
2178
+ end
2179
+ super(lhs,op,rhs)
2180
+ else super
2181
+ end
2182
+ end
2183
+
2018
2184
  def initialize(*args)
2019
2185
 
2020
2186
  if args.size==5
2187
+ #this branch should be dead now
2021
2188
  if args[3].ident=="rescue3"
2022
2189
  lhs,op,rescuee,op2,rescuer=*args
2023
- rhs=RescueOpNode.new(rescuee.val,op2,rescuer)
2190
+ if MULTIASSIGN===lhs or rescuee.is_list?
2191
+ huh
2192
+ else
2193
+ rhs=RescueOpNode.new(rescuee.val,op2,rescuer)
2194
+ end
2024
2195
  else
2025
2196
  lhs,op,bogus1,rhs,bogus2=*args
2026
2197
  end
@@ -2033,14 +2204,20 @@ end
2033
2204
  lhs=MultiAssign.new([lhs]) unless lhs.after_comma
2034
2205
  when ParenedNode
2035
2206
  if !lhs.after_comma #look for () around lhs
2036
- if CommaOpNode===lhs.first
2037
- lhs=MultiAssign.new(Array.new(lhs.first))
2038
- else
2039
- lhs=MultiAssign.new([lhs.first])
2040
- end
2041
- @lhs_parens=true
2207
+ if CommaOpNode===lhs.first
2208
+ lhs=MultiAssign.new(Array.new(lhs.first))
2209
+ @lhs_parens=true
2210
+ elsif UnaryStarNode===lhs.first
2211
+ lhs=MultiAssign.new([lhs.first])
2212
+ @lhs_parens=true
2213
+ elsif ParenedNode===lhs.first
2214
+ @lhs_parens=true
2215
+ lhs=lhs.first
2216
+ else
2217
+ lhs=lhs.first
2218
+ end
2042
2219
  end
2043
- when CommaOpNode:
2220
+ when CommaOpNode
2044
2221
  lhs=MultiAssign.new lhs
2045
2222
  #rhs=Array.new(rhs) if CommaOpNode===rhs
2046
2223
  end
@@ -2402,8 +2579,7 @@ end
2402
2579
  # [:masgn, *super]
2403
2580
  # end
2404
2581
  def unparse o=default_unparse_options
2405
- "("+super+")"
2406
-
2582
+ "("+super+")"
2407
2583
  end
2408
2584
  end
2409
2585
 
@@ -2465,15 +2641,20 @@ end
2465
2641
  end
2466
2642
  end
2467
2643
 
2468
- module KeywordOpNode
2469
- def unparse o=default_unparse_options
2470
- [left.unparse(o),' ',op,' ',right.unparse(o)].to_s
2644
+ class LogicalNode
2645
+ include KeywordOpNode
2646
+
2647
+ def self.[](*list)
2648
+ options=list.pop if Hash===list.last
2649
+ result=allocate.replace list
2650
+ opmap=options[:@opmap] if options and options[:@opmap]
2651
+ opmap||=result.op[0,1]*(list.size-1)
2652
+ result.instance_variable_set(:@opmap, opmap)
2653
+ return result
2471
2654
  end
2472
- end
2473
2655
 
2474
- module LogicalNode
2475
- include KeywordOpNode
2476
2656
  def initialize(left,op,right)
2657
+ op=op.ident if op.respond_to? :ident
2477
2658
  @opmap=op[0,1]
2478
2659
  case op
2479
2660
  when "&&"; op="and"
@@ -2481,11 +2662,10 @@ end
2481
2662
  end
2482
2663
  #@reverse= op=="or"
2483
2664
  #@op=op
2484
- @module=LogicalNode
2485
2665
  replace [left,right]
2486
2666
  (size-1).downto(0){|i|
2487
2667
  expr=self[i]
2488
- if LogicalNode===expr and expr.op==op
2668
+ if self.class==expr.class
2489
2669
  self[i,1]=Array.new expr
2490
2670
  opmap[i,0]=expr.opmap
2491
2671
  end
@@ -2496,15 +2676,6 @@ end
2496
2676
  OP_EXPAND={?o=>"or", ?a=>"and", ?&=>"&&", ?|=>"||", nil=>""}
2497
2677
  OP_EQUIV={?o=>"or", ?a=>"and", ?&=>"and", ?|=>"or"}
2498
2678
 
2499
- def reverse
2500
- /\A[o|]/===@opmap
2501
- end
2502
- def op
2503
- OP_EQUIV[@opmap[0]]
2504
- end
2505
-
2506
- #these 3 methods are defined in RawOpNode too, hence these
2507
- #definitions are ignored. grrrrrrr.
2508
2679
  def unparse o=default_unparse_options
2509
2680
  result=''
2510
2681
 
@@ -2516,11 +2687,18 @@ end
2516
2687
  }
2517
2688
  return result
2518
2689
  end
2519
- def left(*args,&block)
2520
- method_missing(:left,*args,&block)
2690
+
2691
+ def left
2692
+ self[0]
2693
+ end
2694
+ def left= val
2695
+ self[0]=val
2521
2696
  end
2522
- def right(*args,&block)
2523
- method_missing(:right,*args,&block)
2697
+ def right
2698
+ self[1]
2699
+ end
2700
+ def right= val
2701
+ self[1]=val
2524
2702
  end
2525
2703
 
2526
2704
  def parsetree(o)
@@ -2542,21 +2720,44 @@ end
2542
2720
  end
2543
2721
  end
2544
2722
 
2545
- module WhileOpNode
2723
+ class AndNode<LogicalNode
2724
+ def reverse
2725
+ false
2726
+ end
2727
+
2728
+ def op
2729
+ "and"
2730
+ end
2731
+ end
2732
+
2733
+ class OrNode<LogicalNode
2734
+ def reverse
2735
+ true
2736
+ end
2737
+
2738
+ def op
2739
+ "or"
2740
+ end
2741
+ end
2742
+
2743
+ class WhileOpNode
2546
2744
  include KeywordOpNode
2745
+ param_names :left, :op_, :right
2547
2746
  def condition; right end
2548
2747
  def consequent; left end
2549
- def initialize(val1,op,val2)
2550
- self[1]=op
2748
+ def initialize(val1,op,val2=nil)
2749
+ op,val2=nil,op unless val2
2750
+ op=op.ident if op.respond_to? :ident
2551
2751
  @reverse=false
2552
- @module=WhileOpNode
2553
2752
  @loop=true
2554
2753
  @test_first= !( BeginNode===val1 )
2754
+ replace [val1,val2]
2555
2755
  condition.special_conditions! if condition.respond_to? :special_conditions!
2556
2756
  end
2557
2757
 
2558
2758
  def while; condition end
2559
2759
  def do; consequent end
2760
+ def op; "while" end
2560
2761
 
2561
2762
  def parsetree(o)
2562
2763
  cond=condition.rescue_parsetree(o)
@@ -2577,21 +2778,24 @@ end
2577
2778
 
2578
2779
  end
2579
2780
 
2580
- module UntilOpNode
2781
+ class UntilOpNode
2581
2782
  include KeywordOpNode
2783
+ param_names :left,:op_,:right
2582
2784
  def condition; right end
2583
2785
  def consequent; left end
2584
- def initialize(val1,op,val2)
2585
- self[1]=op
2786
+ def initialize(val1,op,val2=nil)
2787
+ op,val2=nil,op unless val2
2788
+ op=op.ident if op.respond_to? :ident
2586
2789
  @reverse=true
2587
2790
  @loop=true
2588
2791
  @test_first= !( BeginNode===val1 )
2589
- @module=UntilOpNode
2792
+ replace [val1,val2]
2590
2793
  condition.special_conditions! if condition.respond_to? :special_conditions!
2591
2794
  end
2592
2795
 
2593
2796
  def while; negate condition end
2594
2797
  def do; consequent end
2798
+ def op; "until" end
2595
2799
 
2596
2800
  def parsetree(o)
2597
2801
  cond=condition.rescue_parsetree(o)
@@ -2614,15 +2818,17 @@ end
2614
2818
  end
2615
2819
  end
2616
2820
 
2617
- module UnlessOpNode
2821
+ class UnlessOpNode
2618
2822
  include KeywordOpNode
2823
+ param_names :left, :op_, :right
2619
2824
  def condition; right end
2620
2825
  def consequent; left end
2621
- def initialize(val1,op,val2)
2622
- self[1]=op
2826
+ def initialize(val1,op,val2=nil)
2827
+ op,val2=nil,op unless val2
2828
+ op=op.ident if op.respond_to? :ident
2623
2829
  @reverse=true
2624
2830
  @loop=false
2625
- @module=UnlessOpNode
2831
+ replace [val1,val2]
2626
2832
  condition.special_conditions! if condition.respond_to? :special_conditions!
2627
2833
  end
2628
2834
 
@@ -2630,6 +2836,7 @@ end
2630
2836
  def then; nil end
2631
2837
  def else; consequent end
2632
2838
  def elsifs; [] end
2839
+ def op; "unless" end
2633
2840
 
2634
2841
  def parsetree(o)
2635
2842
  cond=condition.rescue_parsetree(o)
@@ -2642,15 +2849,17 @@ end
2642
2849
  end
2643
2850
  end
2644
2851
 
2645
- module IfOpNode
2852
+ class IfOpNode
2853
+ param_names :left,:op_,:right
2646
2854
  include KeywordOpNode
2647
2855
  def condition; right end
2648
2856
  def consequent; left end
2649
- def initialize(left,op,right)
2650
- self[1]=op
2857
+ def initialize(left,op,right=nil)
2858
+ op,right=nil,op unless right
2859
+ op=op.ident if op.respond_to? :ident
2651
2860
  @reverse=false
2652
2861
  @loop=false
2653
- @module=IfOpNode
2862
+ replace [left,right]
2654
2863
  condition.special_conditions! if condition.respond_to? :special_conditions!
2655
2864
  end
2656
2865
 
@@ -2658,6 +2867,7 @@ end
2658
2867
  def then; consequent end
2659
2868
  def else; nil end
2660
2869
  def elsifs; [] end
2870
+ def op; "if" end
2661
2871
 
2662
2872
  def parsetree(o)
2663
2873
  cond=condition.rescue_parsetree(o)
@@ -2684,23 +2894,9 @@ end
2684
2894
  #handle inlined hash pairs in param list (if any)
2685
2895
  # compr=Object.new
2686
2896
  # def compr.==(other) ArrowOpNode===other end
2897
+ h,arrowrange=param_list.extract_unbraced_hash
2687
2898
  param_list=Array.new(param_list)
2688
- first=last=nil
2689
- param_list.each_with_index{|param,i|
2690
- break first=i if ArrowOpNode===param
2691
- }
2692
- (1..param_list.size).each{|i| param=param_list[-i]
2693
- break last=-i if ArrowOpNode===param
2694
- }
2695
- if first
2696
- arrowrange=first..last
2697
- arrows=param_list[arrowrange]
2698
- h=HashLiteralNode.new(nil,arrows,nil)
2699
- h.offset=arrows.first.offset
2700
- h.startline=arrows.first.startline
2701
- h.endline=arrows.last.endline
2702
- param_list[arrowrange]=[h]
2703
- end
2899
+ param_list[arrowrange]=[h] if arrowrange
2704
2900
 
2705
2901
  when ArrowOpNode
2706
2902
  h=HashLiteralNode.new(nil,param_list,nil)
@@ -2726,11 +2922,13 @@ end
2726
2922
  method=method.ident
2727
2923
  fail unless String===method
2728
2924
  end
2925
+
2729
2926
  super(nil,method,param_list,blockparams,block)
2730
2927
  #receiver, if any, is tacked on later
2731
2928
  end
2732
2929
 
2733
2930
  def real_parens; !@not_real_parens end
2931
+ def real_parens= x; @not_real_parens=!x end
2734
2932
 
2735
2933
  def unparse o=default_unparse_options
2736
2934
  fail if block==false
@@ -2743,12 +2941,13 @@ end
2743
2941
  block&&[
2744
2942
  @do_end ? " do " : "{",
2745
2943
  block_params&&block_params.unparse(o),
2746
- " ",
2944
+ unparse_nl(block,o," "),
2747
2945
  block.unparse(o),
2946
+ unparse_nl(endline,o),
2748
2947
  @do_end ? " end" : "}"
2749
2948
  ]
2750
2949
  ]
2751
- return result.to_s
2950
+ return result.join
2752
2951
  end
2753
2952
 
2754
2953
  def image
@@ -2756,7 +2955,8 @@ end
2756
2955
  end
2757
2956
 
2758
2957
  def with_commas
2759
- !real_parens and args.size>0
2958
+ !real_parens and
2959
+ args and args.size>0
2760
2960
  end
2761
2961
 
2762
2962
  # identity_param :with_commas, false, true
@@ -2796,6 +2996,7 @@ end
2796
2996
  lasti=args.size-1
2797
2997
  end
2798
2998
  methodname= name
2999
+ methodname= methodname.chop if /^[~!]@$/===methodname
2799
3000
  methodsym=methodname.to_sym
2800
3001
  is_kw= RubyLexer::FUNCLIKE_KEYWORDS&~/^(BEGIN|END|raise)$/===methodname
2801
3002
 
@@ -2990,6 +3191,7 @@ end
2990
3191
  param_names :params,:body
2991
3192
  def initialize(open_brace,formals,stmts,close_brace)
2992
3193
  stmts||=SequenceNode[{:@offset => open_brace.offset, :@startline=>open_brace.startline}]
3194
+ stmts=SequenceNode[stmts,{:@offset => open_brace.offset, :@startline=>open_brace.startline}] unless SequenceNode===stmts
2993
3195
 
2994
3196
  formals&&=BlockParams.new(Array.new(formals))
2995
3197
  @do_end=true unless open_brace.not_real?
@@ -3147,9 +3349,9 @@ end
3147
3349
  newdata=with_string_data(*tokens)
3148
3350
 
3149
3351
  case token
3150
- when HereDocNode:
3352
+ when HereDocNode
3151
3353
  token.list_to_append=newdata
3152
- when StringNode: #do nothing
3354
+ when StringNode #do nothing
3153
3355
  else fail "non-string token class used to construct string node"
3154
3356
  end
3155
3357
  replace token.data
@@ -3167,7 +3369,7 @@ end
3167
3369
  EVEN_NUM_BSLASHES=/(^|[^\\])((?:\\\\)*)/
3168
3370
  def unparse o=default_unparse_options
3169
3371
  o[:linenum]+=@open.count("\n")
3170
- result=[@open,unparse_interior(o),@close,@modifiers].to_s
3372
+ result=[@open,unparse_interior(o),@close,@modifiers].join
3171
3373
  o[:linenum]+=@close.count("\n")
3172
3374
  return result
3173
3375
  end
@@ -3255,7 +3457,7 @@ end
3255
3457
  #parse the token list in the string inclusion
3256
3458
  parser=Thread.current[:$RedParse_parser]
3257
3459
  klass=parser.class
3258
- data[i]=klass.new(tokens, "(string inclusion)",1,[],{:rubyversion=>parser.rubyversion}).parse
3460
+ data[i]=klass.new(tokens, "(string inclusion)",1,[],:rubyversion=>parser.rubyversion,:cache_mode=>:none).parse
3259
3461
  end
3260
3462
  } #if data
3261
3463
  # was_nul_header= (String===data.first and data.first.empty?) #and o[:quirks]
@@ -3403,7 +3605,7 @@ end
3403
3605
  when '/'
3404
3606
  numopts=0
3405
3607
  charset=0
3406
- @modifiers.each_byte{|ch|
3608
+ RubyLexer::CharHandler.each_char(@modifiers){|ch|
3407
3609
  if ch==?o
3408
3610
  type=:dregx_once
3409
3611
  elsif numopt=CHAROPT2NUM[ch].nonzero?
@@ -3474,7 +3676,7 @@ end
3474
3676
  when '/'
3475
3677
  type=:dregx
3476
3678
  numopts=charset=0
3477
- @modifiers.each_byte{|ch|
3679
+ RubyLexer::CharHandler.each_char(@modifiers){|ch|
3478
3680
  if ch==?o
3479
3681
  type=:dregx_once
3480
3682
  elsif numopt=CHAROPT2NUM[ch].nonzero?
@@ -3527,7 +3729,13 @@ end
3527
3729
  end
3528
3730
 
3529
3731
  if vals.size==1
3530
- vals=[/#{vals[0]}/] if :dregx==type or :dregx_once==type
3732
+ if :dregx==type or :dregx_once==type
3733
+ lang=@modifiers.tr_s("^nesuNESU","")
3734
+ lang=lang[-1,1] unless lang.empty?
3735
+ lang.downcase!
3736
+ regex_options=nil
3737
+ vals=[Regexp_new( vals.first,numopts,lang )]
3738
+ end
3531
3739
  type=DOWNSHIFT_STRING_TYPE[type]
3532
3740
  end
3533
3741
  result= vals.unshift(type)
@@ -3536,6 +3744,25 @@ end
3536
3744
  result=[:match, result] if defined? @implicit_match and @implicit_match
3537
3745
  return result
3538
3746
  end
3747
+
3748
+ if //.respond_to? :encoding
3749
+ LETTER2ENCODING={
3750
+ ?n => Encoding::ASCII,
3751
+ ?u => Encoding::UTF_8,
3752
+ ?e => Encoding::EUC_JP,
3753
+ ?s => Encoding::SJIS,
3754
+ "" => Encoding::ASCII
3755
+ }
3756
+ def Regexp_new(src,opts,lang)
3757
+ src.encode!(LETTER2ENCODING[lang])
3758
+ Regexp.new(src,opts)
3759
+ end
3760
+ else
3761
+ def Regexp_new(src,opts,lang)
3762
+ Regexp.new(src,opts,lang)
3763
+ end
3764
+ end
3765
+
3539
3766
  end
3540
3767
 
3541
3768
  class HereDocNode<StringNode
@@ -3564,7 +3791,8 @@ end
3564
3791
  end
3565
3792
 
3566
3793
 
3567
- def flattened_ivars_equal?(other)
3794
+ #ignore instance vars in here documents when testing equality
3795
+ def flattened_ivars_equal?(other)
3568
3796
  StringNode===other
3569
3797
  end
3570
3798
 
@@ -3581,7 +3809,7 @@ end
3581
3809
  else fail
3582
3810
  end
3583
3811
 
3584
- [lead,@char, inner, @char].to_s
3812
+ [lead,@char, inner, @char].join
3585
3813
  end
3586
3814
  end
3587
3815
 
@@ -3598,17 +3826,19 @@ end
3598
3826
  assert !old_val.raw.has_str_inc?
3599
3827
  val=old_val.raw.translate_escapes(old_val.raw.elems.first).to_sym
3600
3828
  when ?" #"
3601
- if old_val.raw.has_str_inc?
3829
+ if old_val.raw.has_str_inc? or old_val.raw.elems==[""]
3602
3830
  val=StringNode.new(old_val.raw) #ugly hack: this isn't literal
3603
3831
  else
3604
3832
  val=old_val.raw.translate_escapes(old_val.raw.elems.first).to_sym
3605
3833
  end
3606
3834
  else #val=val[1..-1].to_sym
3607
- if StringToken===old_val.raw
3608
- val=old_val.raw.translate_escapes(old_val.raw.elems.first).to_sym
3609
- else
3610
- val=old_val.raw.to_sym
3835
+ val=old_val.raw
3836
+ if StringToken===val
3837
+ val=val.translate_escapes(val.elems.first)
3838
+ elsif /^[!~]@$/===val
3839
+ val=val.chop
3611
3840
  end
3841
+ val=val.to_sym
3612
3842
  end
3613
3843
  when NumberToken
3614
3844
  case val
@@ -3651,7 +3881,8 @@ end
3651
3881
  ":"+
3652
3882
  val.unparse(o)
3653
3883
  when Float
3654
- s= "%#{Float::DIG+1}.#{Float::DIG+1}f"%val
3884
+ s= val.accurate_to_s
3885
+ #why must it be *2? I wouldn't think any fudge factor would be necessary
3655
3886
  case s
3656
3887
  when /-inf/i; s="-"+Inf
3657
3888
  when /inf/i; s= Inf
@@ -3700,7 +3931,7 @@ end
3700
3931
  if name.ident=='('
3701
3932
  #simulate nil
3702
3933
  replace ['nil']
3703
- @value=false
3934
+ @value=nil
3704
3935
  else
3705
3936
  replace [name.ident]
3706
3937
  @value=name.respond_to?(:value) && name.value
@@ -3739,7 +3970,14 @@ end
3739
3970
  @offset=lbrack.offset
3740
3971
  contents or return super()
3741
3972
  if CommaOpNode===contents
3973
+ h,arrowrange=contents.extract_unbraced_hash
3974
+ contents[arrowrange]=[h] if arrowrange
3742
3975
  super( *contents )
3976
+ elsif ArrowOpNode===contents
3977
+ h=HashLiteralNode.new(nil,contents,nil)
3978
+ h.startline=contents.startline
3979
+ h.endline=contents.endline
3980
+ super HashLiteralNode.new(nil,contents,nil)
3743
3981
  else
3744
3982
  super contents
3745
3983
  end
@@ -3820,7 +4058,7 @@ end
3820
4058
  result=@reverse ? "unless " : "if "
3821
4059
  result+="#{condition.unparse o}"
3822
4060
  result+=unparse_nl(consequent,o)+"#{consequent.unparse(o)}" if consequent
3823
- result+=unparse_nl(elsifs.first,o)+elsifs.map{|n| n.unparse(o)}.to_s if elsifs
4061
+ result+=unparse_nl(elsifs.first,o)+elsifs.map{|n| n.unparse(o)}.join if elsifs
3824
4062
  result+=unparse_nl(else_,o)+"else "+else_.unparse(o) if else_
3825
4063
  result+=";else " if defined? @empty_else
3826
4064
  result+=";end"
@@ -3914,7 +4152,7 @@ end
3914
4152
  def image; "(elsif)" end
3915
4153
 
3916
4154
  def unparse o=default_unparse_options
3917
- "elsif #{condition.unparse o}#{unparse_nl(consequent,o)}#{consequent.unparse o};"
4155
+ "elsif #{condition.unparse o}#{unparse_nl(consequent,o)}#{consequent.unparse o if consequent};"
3918
4156
  end
3919
4157
 
3920
4158
  def to_lisp
@@ -3946,7 +4184,7 @@ end
3946
4184
  condition.unparse(o), unparse_nl(body||self,o),
3947
4185
  body&&body.unparse(o),
3948
4186
  ";end"
3949
- ].to_s
4187
+ ].join
3950
4188
  end
3951
4189
 
3952
4190
  def while
@@ -3982,7 +4220,10 @@ end
3982
4220
  def initialize(caseword, condition, semi, whens, otherwise, endword)
3983
4221
  @offset=caseword.offset
3984
4222
  if otherwise
3985
- otherwise=otherwise.val or @empty_else=true
4223
+ otherwise=otherwise.val
4224
+ @empty_else=!otherwise
4225
+ else
4226
+ @empty_else=false
3986
4227
  end
3987
4228
  whens.extend ListInNode
3988
4229
  super(condition,whens,otherwise)
@@ -3992,9 +4233,10 @@ end
3992
4233
 
3993
4234
  def unparse o=default_unparse_options
3994
4235
  result="case #{condition&&condition.unparse(o)}"+
3995
- whens.map{|wh| wh.unparse o}.to_s
4236
+ whens.map{|wh| wh.unparse o}.join
3996
4237
 
3997
4238
  result += unparse_nl(otherwise,o)+"else "+otherwise.unparse(o) if otherwise
4239
+ result += ";else;" if @empty_else
3998
4240
  result += ";end"
3999
4241
 
4000
4242
  return result
@@ -4013,6 +4255,7 @@ end
4013
4255
  result=[:case, condition&&condition.parsetree(o)]+
4014
4256
  whens.map{|whennode| whennode.parsetree(o)}
4015
4257
  other=otherwise&&otherwise.parsetree(o)
4258
+ return [] if result==[:case, nil] and !other
4016
4259
  if other and other[0..1]==[:case, nil] and !condition
4017
4260
  result.concat other[2..-1]
4018
4261
  else
@@ -4123,7 +4366,12 @@ end
4123
4366
  =end
4124
4367
 
4125
4368
  vars=self.for.lvalue_parsetree(o)
4126
- result=[:for, self.in.begin_parsetree(o), vars]
4369
+ collection= self.in.begin_parsetree(o)
4370
+ if ParenedNode===self.in and collection.first==:begin
4371
+ assert collection.size==2
4372
+ collection=collection[1]
4373
+ end
4374
+ result=[:for, collection, vars]
4127
4375
  result.push self.do.parsetree(o) if self.do
4128
4376
  result
4129
4377
  end
@@ -4149,11 +4397,13 @@ end
4149
4397
  data=Array[*contents]
4150
4398
  end
4151
4399
  super(*data)
4400
+ else fail
4152
4401
  end
4153
4402
  @no_braces=!open
4154
4403
  end
4155
4404
 
4156
4405
  attr :no_arrows
4406
+ attr_accessor :no_braces
4157
4407
  attr_writer :offset
4158
4408
 
4159
4409
  def image; "({})" end
@@ -4272,6 +4522,9 @@ end
4272
4522
 
4273
4523
  attr_reader :empty_ensure, :empty_else
4274
4524
 
4525
+ def self.namelist
4526
+ %w[receiver name args body rescues elses ensures]
4527
+ end
4275
4528
 
4276
4529
  # def receiver= x
4277
4530
  # self[0]=x
@@ -4296,7 +4549,7 @@ end
4296
4549
  def unparse o=default_unparse_options
4297
4550
  result=[
4298
4551
  "def ",receiver&&receiver.unparse(o)+'.',name,
4299
- args ? '('+args.map{|arg| arg.unparse o}.join(',')+')' : unparse_nl(body||self,o)
4552
+ args && '('+args.map{|arg| arg.unparse o}.join(',')+')', unparse_nl(body||self,o)
4300
4553
  ]
4301
4554
  result<<unparse_and_rescues(o)
4302
4555
  =begin
@@ -4309,7 +4562,7 @@ end
4309
4562
  result+="ensure\n" if @empty_ensure
4310
4563
  =end
4311
4564
  result<<unparse_nl(endline,o)+"end"
4312
- result.to_s
4565
+ result.join
4313
4566
  end
4314
4567
 
4315
4568
  def to_lisp
@@ -4318,7 +4571,9 @@ end
4318
4571
  end
4319
4572
 
4320
4573
  def parsetree(o)
4321
- name=name().to_sym
4574
+ name=name()
4575
+ name=name.chop if /^[!~]@$/===name
4576
+ name=name.to_sym
4322
4577
 
4323
4578
  result=[name, target=[:scope, [:block, ]] ]
4324
4579
  if receiver
@@ -4444,7 +4699,9 @@ end
4444
4699
  end
4445
4700
 
4446
4701
  def str2parsetree(str,o)
4447
- if String===str then [:lit, str.to_sym]
4702
+ if String===str
4703
+ str=str.chop if /^[!~]@$/===str
4704
+ [:lit, str.to_sym]
4448
4705
  else
4449
4706
  result=str.parsetree(o)
4450
4707
  result[0]=:dsym
@@ -4530,7 +4787,7 @@ end
4530
4787
  def image; "(module #{name})" end
4531
4788
 
4532
4789
  def unparse o=default_unparse_options
4533
- "module #{name.unparse o}#{unparse_nl(body||self,o)}#{unparse_and_rescues(o)};end"
4790
+ "module #{name.unparse o}#{unparse_nl(body||self,o)}#{unparse_and_rescues(o)}#{unparse_nl(endline,o)}end"
4534
4791
  end
4535
4792
 
4536
4793
  def parent; nil end
@@ -4581,7 +4838,10 @@ end
4581
4838
  def unparse o=default_unparse_options
4582
4839
  result="class #{name.unparse o}"
4583
4840
  result+=" < #{parent.unparse o}" if parent
4584
- result+=unparse_nl(body||self,o)+"#{unparse_and_rescues(o)};end"
4841
+ result+=unparse_nl(body||self,o)+
4842
+ unparse_and_rescues(o)+
4843
+ unparse_nl(endline,o)+
4844
+ "end"
4585
4845
  return result
4586
4846
  end
4587
4847
 
@@ -4623,6 +4883,7 @@ end
4623
4883
  alias object val
4624
4884
  alias obj val
4625
4885
  alias receiver val
4886
+ alias receiver= val=
4626
4887
  alias name val
4627
4888
 
4628
4889
  alias ensure_ ensure
@@ -4725,17 +4986,30 @@ end
4725
4986
 
4726
4987
  class BracketsGetNode<ValueNode
4727
4988
  param_names(:receiver,:lbrack_,:params,:rbrack_)
4989
+ alias args params
4728
4990
  def initialize(receiver,lbrack,params,rbrack)
4729
- params=case params
4730
- when CommaOpNode; Array.new params
4991
+ case params
4992
+ when CommaOpNode
4993
+ h,arrowrange=params.extract_unbraced_hash
4994
+ params=Array.new params
4995
+ params[arrowrange]=[h] if arrowrange
4996
+ when ArrowOpNode
4997
+ h=HashLiteralNode.new(nil,params,nil)
4998
+ h.startline=params.startline
4999
+ h.endline=params.endline
5000
+ params=[h]
4731
5001
  when nil
4732
- else [params]
5002
+ params=nil
5003
+ else
5004
+ params=[params]
4733
5005
  end
4734
5006
  params.extend ListInNode if params
4735
5007
  @offset=receiver.offset
4736
5008
  super(receiver,params)
4737
5009
  end
4738
5010
 
5011
+ def name; "[]" end
5012
+
4739
5013
  def image; "(#{receiver.image}.[])" end
4740
5014
 
4741
5015
  def unparse o=default_unparse_options
@@ -4743,7 +5017,7 @@ end
4743
5017
  '[',
4744
5018
  params&&params.map{|param| param.unparse o}.join(','),
4745
5019
  ']'
4746
- ].to_s
5020
+ ].join
4747
5021
  end
4748
5022
 
4749
5023
  def parsetree(o)
@@ -4848,7 +5122,13 @@ end
4848
5122
  alias msg error?
4849
5123
  end
4850
5124
 
4851
- # end
5125
+
5126
+ module Nodes
5127
+ ::RedParse::constants.each{|k|
5128
+ const=::RedParse::const_get(k)
5129
+ const_set( k,const ) if Module===const and ::RedParse::Node>=const
5130
+ }
5131
+ end
4852
5132
 
4853
5133
  end
4854
5134
  =begin a (formal?) description