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.
- data/History.txt +63 -4
- data/Makefile +43 -0
- data/README.txt +101 -166
- data/Rakefile +1 -1
- data/bin/redparse +49 -21
- data/lib/redparse.rb +88 -1654
- data/lib/redparse/cache.rb +172 -0
- data/lib/redparse/compile.rb +1648 -0
- data/lib/redparse/float_accurate_to_s.rb +162 -0
- data/lib/redparse/generate.rb +6 -2
- data/lib/redparse/node.rb +677 -397
- data/lib/redparse/parse_tree_server.rb +129 -0
- data/lib/redparse/pthelper.rb +43 -0
- data/lib/redparse/reg_more_sugar.rb +5 -5
- data/lib/redparse/version.rb +1 -1
- data/redparse.gemspec +43 -0
- data/test/data/skkdictools.rb +3 -0
- data/test/generate_parse_tree_server_rc.rb +43 -0
- data/test/rp-locatetest.rb +41 -1
- data/test/test_1.9.rb +114 -0
- data/test/test_all.rb +3 -0
- data/test/test_redparse.rb +283 -124
- data/test/test_xform_tree.rb +66 -0
- metadata +57 -56
@@ -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
|
data/lib/redparse/generate.rb
CHANGED
@@ -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){|
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
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
|
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
|
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
|
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
|
391
|
-
|
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-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
559
|
+
namelist << name
|
502
560
|
unless last==?_
|
503
|
-
accessors << "def #{name.chomp('_')}; self[#{namelist.size}] end\n"
|
504
|
-
accessors << "def #{name.chomp('_')}=(newval);
|
505
|
-
|
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(#{
|
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.
|
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
|
-
|
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.
|
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!(
|
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
|
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
|
-
|
622
|
-
|
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
|
-
|
630
|
-
new
|
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{|
|
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.
|
961
|
+
child.clone
|
800
962
|
end
|
801
963
|
end
|
802
964
|
}
|
803
965
|
|
804
966
|
newdata=map(&handler)
|
805
967
|
|
806
|
-
|
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
|
-
|
812
|
-
result_module=val if iv=="@module" #hacky
|
972
|
+
result.instance_variable_set(iv,handler[val])
|
813
973
|
end
|
814
974
|
}
|
815
|
-
result
|
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
|
866
|
-
when Array
|
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
|
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
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
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
|
-
|
1095
|
-
op
|
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
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
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
|
-
|
1302
|
+
class OpNode<RawOpNode
|
1116
1303
|
def initialize(left,op,right)
|
1117
1304
|
#@negative_of="="+$1 if /^!([=~])$/===op
|
1118
|
-
|
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
|
-
|
1145
|
-
|
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
|
-
|
1160
|
-
|
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
|
-
|
1172
|
-
|
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
|
-
|
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
|
-
}.
|
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
|
-
|
1348
|
-
|
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
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
#
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
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
|
-
|
1590
|
+
super(left,op,right)
|
1368
1591
|
end
|
1369
|
-
def begin;
|
1370
|
-
def end;
|
1371
|
-
def
|
1372
|
-
def
|
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
|
1379
|
-
|
1380
|
-
|
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
|
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
|
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
|
-
|
1488
|
-
var
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1921
|
-
|
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
|
-
|
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
|
-
|
2037
|
-
|
2038
|
-
|
2039
|
-
lhs
|
2040
|
-
|
2041
|
-
|
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
|
-
|
2469
|
-
|
2470
|
-
|
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
|
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
|
-
|
2520
|
-
|
2690
|
+
|
2691
|
+
def left
|
2692
|
+
self[0]
|
2693
|
+
end
|
2694
|
+
def left= val
|
2695
|
+
self[0]=val
|
2521
2696
|
end
|
2522
|
-
def right
|
2523
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
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
|
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].
|
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,[]
|
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
|
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
|
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
|
-
|
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
|
-
|
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].
|
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
|
-
|
3608
|
-
|
3609
|
-
|
3610
|
-
|
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=
|
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=
|
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)}.
|
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
|
-
].
|
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
|
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}.
|
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
|
-
|
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
|
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.
|
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()
|
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
|
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)}
|
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)+
|
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
|
-
|
4730
|
-
when CommaOpNode
|
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
|
-
|
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&¶ms.map{|param| param.unparse o}.join(','),
|
4745
5019
|
']'
|
4746
|
-
].
|
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
|
-
|
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
|