redparse 0.8.3 → 0.8.4

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.
@@ -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