redparse 0.8.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -0
- data/COPYING.LGPL +503 -158
- data/History.txt +192 -0
- data/Makefile +9 -0
- data/README.txt +72 -39
- data/bin/redparse +108 -14
- data/lib/miniredparse.rb +1543 -0
- data/lib/redparse.rb +971 -105
- data/lib/redparse/ReduceWithsFor_RedParse_1_8.rb +17412 -0
- data/lib/redparse/ReduceWithsFor_RedParse_1_9.rb +17633 -0
- data/lib/redparse/babynodes.rb +17 -0
- data/lib/redparse/babyparser.rb +17 -0
- data/lib/redparse/cache.rb +290 -6
- data/lib/redparse/compile.rb +6 -97
- data/lib/redparse/decisiontree.rb +1 -1
- data/lib/redparse/float_accurate_to_s.rb +30 -6
- data/lib/redparse/generate.rb +18 -0
- data/lib/redparse/node.rb +415 -124
- data/lib/redparse/parse_tree_server.rb +20 -2
- data/lib/redparse/problemfiles.rb +1 -1
- data/lib/redparse/pthelper.rb +17 -31
- data/lib/redparse/reg_more_sugar.rb +1 -1
- data/lib/redparse/replacing/parse_tree.rb +30 -0
- data/lib/redparse/replacing/ripper.rb +20 -0
- data/lib/redparse/replacing/ruby_parser.rb +28 -0
- data/lib/redparse/ripper.rb +393 -0
- data/lib/redparse/ripper_sexp.rb +153 -0
- data/lib/redparse/stackableclasses.rb +113 -0
- data/lib/redparse/version.rb +18 -1
- data/redparse.gemspec +29 -9
- data/rplt.txt +31 -0
- data/test/data/hd_with_blank_string.rb +3 -0
- data/test/data/pt_known_output.rb +13273 -0
- data/test/data/wp.pp +0 -0
- data/test/generate_parse_tree_server_rc.rb +17 -0
- data/test/rp-locatetest.rb +2 -2
- data/test/test_1.9.rb +338 -35
- data/test/test_all.rb +22 -3
- data/test/test_part.rb +32 -0
- data/test/test_redparse.rb +396 -74
- data/test/test_xform_tree.rb +18 -0
- data/test/unparse_1.9_exceptions.txt +85 -0
- data/test/unparse_1.9_exceptions.txt.old +81 -0
- metadata +71 -46
- data/Rakefile +0 -35
@@ -1,6 +1,6 @@
|
|
1
1
|
=begin
|
2
2
|
redparse - a ruby parser written in ruby
|
3
|
-
Copyright (C) 2008 Caleb Clausen
|
3
|
+
Copyright (C) 2008, 2012, 2016 Caleb Clausen
|
4
4
|
|
5
5
|
This program is free software: you can redistribute it and/or modify
|
6
6
|
it under the terms of the GNU Lesser General Public License as published by
|
@@ -1,20 +1,44 @@
|
|
1
|
+
=begin
|
2
|
+
redparse - a ruby parser written in ruby
|
3
|
+
Copyright (C) 2012, 2016 Caleb Clausen
|
4
|
+
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
6
|
+
it under the terms of the GNU Lesser General Public License as published by
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
8
|
+
(at your option) any later version.
|
9
|
+
|
10
|
+
This program is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
GNU Lesser General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU Lesser General Public License
|
16
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
=end
|
18
|
+
needed= !defined?(RUBY_ENGINE) ||
|
19
|
+
(RUBY_ENGINE=='ruby' && (
|
20
|
+
RUBY_VERSION[/^\d+\.\d+/].to_f<=1.8 || #1.8 or below or
|
21
|
+
RUBY_VERSION[/^1\.9\.(\d+)/,1].to_i<2 #1.9 if < 1.9.2
|
22
|
+
))
|
23
|
+
|
24
|
+
|
1
25
|
class Float
|
2
26
|
SIZE=[1.1].pack("d").size
|
3
27
|
BITSIZE=SIZE*8
|
4
28
|
BASE10_DIGITS=(2**BITSIZE-1).to_s.size
|
5
29
|
def accurate_to_s
|
30
|
+
#this shouldn't be needed anymore after 1.9.2
|
6
31
|
return "#{'-' if self<0}Infinity" if infinite?
|
7
32
|
return "NaN" if nan?
|
8
|
-
return
|
33
|
+
return to_s if zero? #-0.0 and +0.0
|
9
34
|
|
10
35
|
as_str=sprintf("%.#{BASE10_DIGITS+2}e",self)
|
11
36
|
|
12
37
|
#decompose self into sign, mantissa, and exponent (in string form)
|
13
|
-
all,sign,first,digits,exp=*as_str.match(/^([+-]?)(\d)
|
14
|
-
digits=first<<digits
|
15
|
-
exp=exp.to_i+1
|
38
|
+
all,sign,first,digits,exp=*as_str.match(/^([+-]?)(\d+)(?:\.(\d+))?(?:[eE](.*))?$/)
|
39
|
+
digits=first<<(digits||'0')
|
40
|
+
exp=(exp||'0').to_i+1
|
16
41
|
lead=sign<<"0."
|
17
|
-
return digits=digits if as_str.to_f.zero? #hopeless
|
18
42
|
|
19
43
|
#recompose back to a float
|
20
44
|
result=[lead,digits,"e",exp].join
|
@@ -92,7 +116,7 @@ class Float
|
|
92
116
|
return [lead,digits<<last,"e",exp].join
|
93
117
|
end
|
94
118
|
end
|
95
|
-
end
|
119
|
+
end if needed
|
96
120
|
|
97
121
|
=begin not quite accurate, tho
|
98
122
|
class String
|
data/lib/redparse/generate.rb
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
=begin
|
2
|
+
redparse - a ruby parser written in ruby
|
3
|
+
Copyright (C) 2012, 2016 Caleb Clausen
|
4
|
+
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
6
|
+
it under the terms of the GNU Lesser General Public License as published by
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
8
|
+
(at your option) any later version.
|
9
|
+
|
10
|
+
This program is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
GNU Lesser General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU Lesser General Public License
|
16
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
=end
|
18
|
+
|
1
19
|
class RedParse
|
2
20
|
=begin
|
3
21
|
3 LR-Parsing Mechanics
|
data/lib/redparse/node.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
=begin
|
2
2
|
redparse - a ruby parser written in ruby
|
3
|
-
Copyright (C) 2008 Caleb Clausen
|
3
|
+
Copyright (C) 2008, 2012, 2016 Caleb Clausen
|
4
4
|
|
5
5
|
|
6
6
|
This program is free software: you can redistribute it and/or modify
|
@@ -41,9 +41,9 @@ class RedParse
|
|
41
41
|
|
42
42
|
module FlattenedIvars
|
43
43
|
EXCLUDED_IVARS=%w[@data @offset @startline @endline]
|
44
|
-
EXCLUDED_IVARS.push(*EXCLUDED_IVARS.map{|iv| iv.to_sym })
|
44
|
+
#EXCLUDED_IVARS.push(*EXCLUDED_IVARS.map{|iv| iv.to_sym })
|
45
45
|
def flattened_ivars
|
46
|
-
ivars=instance_variables
|
46
|
+
ivars=instance_variables.map{|v| v.to_s }
|
47
47
|
ivars-=EXCLUDED_IVARS
|
48
48
|
ivars.sort!
|
49
49
|
result=ivars+ivars.map{|iv|
|
@@ -165,6 +165,8 @@ class RedParse
|
|
165
165
|
extend Stackable::Meta
|
166
166
|
|
167
167
|
def image; "#{inspect}" end
|
168
|
+
|
169
|
+
def short_inspect; inspect+"\n" end
|
168
170
|
|
169
171
|
def to_parsetree(*options) #this shouldn't be needed anymore
|
170
172
|
o={}
|
@@ -184,13 +186,13 @@ class RedParse
|
|
184
186
|
def rescue_parsetree(o); parsetree(o) end
|
185
187
|
def begin_parsetree(o); parsetree(o) end
|
186
188
|
|
187
|
-
attr :line
|
188
|
-
alias endline line
|
189
|
+
#attr :line
|
190
|
+
#alias endline line
|
189
191
|
|
190
|
-
attr_writer :startline
|
191
|
-
def startline
|
192
|
-
|
193
|
-
end
|
192
|
+
#attr_writer :startline
|
193
|
+
#def startline
|
194
|
+
# @startline||=endline
|
195
|
+
#end
|
194
196
|
end
|
195
197
|
|
196
198
|
class KeywordToken
|
@@ -314,7 +316,7 @@ class RedParse
|
|
314
316
|
[varname2assigntype, ident.to_sym]
|
315
317
|
end
|
316
318
|
|
317
|
-
def
|
319
|
+
def old_unused_lvalue #i think this is the correct way, but its overridded below
|
318
320
|
return @lvalue if defined? @lvalue
|
319
321
|
@lvalue=true
|
320
322
|
end
|
@@ -346,15 +348,16 @@ class RedParse
|
|
346
348
|
end
|
347
349
|
|
348
350
|
class StringToken
|
349
|
-
attr :char
|
351
|
+
attr :char unless allocate.respond_to? :char
|
350
352
|
end
|
351
353
|
|
352
354
|
class HerePlaceholderToken
|
353
355
|
attr_accessor :node
|
354
|
-
attr :string
|
356
|
+
attr :string unless allocate.respond_to? :string
|
355
357
|
end
|
356
358
|
|
357
359
|
module ListInNode
|
360
|
+
def self.[](*args) args.extend ListInNode end
|
358
361
|
def []=(*args)
|
359
362
|
val=args.pop
|
360
363
|
#inline symbols as callnodes
|
@@ -366,6 +369,9 @@ class RedParse
|
|
366
369
|
end
|
367
370
|
super( *args<<val )
|
368
371
|
end
|
372
|
+
def ==(other)
|
373
|
+
ListInNode===other and super
|
374
|
+
end
|
369
375
|
end
|
370
376
|
|
371
377
|
class Node<Array
|
@@ -374,6 +380,12 @@ class RedParse
|
|
374
380
|
include FlattenedIvars
|
375
381
|
|
376
382
|
def initialize(*data)
|
383
|
+
if Hash===data.last
|
384
|
+
options=data.pop
|
385
|
+
options.each_pair{|name,val|
|
386
|
+
instance_variable_set name,val
|
387
|
+
}
|
388
|
+
end
|
377
389
|
replace data
|
378
390
|
end
|
379
391
|
|
@@ -414,6 +426,10 @@ class RedParse
|
|
414
426
|
|
415
427
|
def image; "(#{inspect})" end
|
416
428
|
|
429
|
+
def short_inspect(cutoff=2)
|
430
|
+
inspect.gsub(/\n {#{cutoff*2},}.*$/,'')
|
431
|
+
end
|
432
|
+
|
417
433
|
def error? x; false end
|
418
434
|
|
419
435
|
@@data_warned=nil
|
@@ -456,8 +472,27 @@ class RedParse
|
|
456
472
|
return result
|
457
473
|
end
|
458
474
|
|
459
|
-
def
|
460
|
-
|
475
|
+
def to_s #mostly for form inside #{ }
|
476
|
+
unparse
|
477
|
+
end
|
478
|
+
|
479
|
+
def classic_inspect
|
480
|
+
self.class.name.dup+'['+
|
481
|
+
map{|elem|
|
482
|
+
if elem.respond_to? :classic_inspect
|
483
|
+
elem.classic_inspect
|
484
|
+
else
|
485
|
+
elem.inspect
|
486
|
+
end
|
487
|
+
}.join(', ')+
|
488
|
+
']'
|
489
|
+
#this skips ivars, tho...
|
490
|
+
end
|
491
|
+
|
492
|
+
def inspect label=nil,indent=0,verbose=false
|
493
|
+
ivarnames=instance_variables.map{|v| v.to_s }
|
494
|
+
ivarnames-=FlattenedIvars::EXCLUDED_IVARS
|
495
|
+
ivarnames-=noinspect_instance_variables if defined? noinspect_instance_variables
|
461
496
|
ivarnodes=[]
|
462
497
|
ivars=ivarnames.map{|ivarname|
|
463
498
|
ivar=instance_variable_get(ivarname)
|
@@ -465,17 +500,21 @@ class RedParse
|
|
465
500
|
ivarnodes.push [ivarname,ivar]
|
466
501
|
nil
|
467
502
|
else
|
468
|
-
ivarname[1..-1]+"="+ivar.inspect if ivar
|
503
|
+
ivarname[1..-1]+"="+ivar.inspect if ivar and verbose
|
469
504
|
end
|
470
505
|
}.compact.join(' ')
|
471
506
|
|
472
507
|
|
473
|
-
|
474
|
-
|
475
|
-
|
508
|
+
if verbose
|
509
|
+
pos=@startline.to_s
|
510
|
+
pos<<"..#@endline" if @endline!=@startline
|
511
|
+
pos<<"@#@offset"
|
512
|
+
end
|
476
513
|
classname=self.class.name
|
477
514
|
classname.sub!(/^(?:RedParse::)?(.*?)(?:Node)?$/){$1}
|
478
|
-
result= [' '*indent,"+",(label+': ' if label),classname,
|
515
|
+
result= [' '*indent,"+",(label.to_s+': ' if label),classname,]
|
516
|
+
result+=[" pos=",pos,] if pos
|
517
|
+
result+=[" ",ivars,"\n"]
|
479
518
|
indent+=2
|
480
519
|
|
481
520
|
namelist=self.class.namelist
|
@@ -483,10 +522,10 @@ class RedParse
|
|
483
522
|
namelist.each{|name|
|
484
523
|
val=send name rescue "{{ERROR INSPECTING ATTR #{name}}}"
|
485
524
|
case val
|
486
|
-
when Node; result<< val.inspect(name,indent)
|
525
|
+
when Node; result<< val.inspect(name,indent,verbose)
|
487
526
|
when ListInNode
|
488
|
-
result.push ' '*indent,"
|
489
|
-
v.inspect(nil,indent+2) rescue ' '*(indent+2)+"-#{v.inspect}\n"
|
527
|
+
result.push ' '*indent,"+#{name}:\n",*val.map{|v|
|
528
|
+
v.inspect(nil,indent+2,verbose) rescue ' '*(indent+2)+"-#{v.inspect}\n"
|
490
529
|
}
|
491
530
|
when nil;
|
492
531
|
else ivars<< " #{name}=#{val.inspect}"
|
@@ -495,7 +534,7 @@ class RedParse
|
|
495
534
|
else
|
496
535
|
each{|val|
|
497
536
|
case val
|
498
|
-
when Node; result<< val.inspect(nil,indent)
|
537
|
+
when Node; result<< val.inspect(nil,indent,verbose)
|
499
538
|
else result<< ' '*indent+"-#{val.inspect}\n"
|
500
539
|
end
|
501
540
|
}
|
@@ -594,11 +633,14 @@ class RedParse
|
|
594
633
|
#@namelist
|
595
634
|
result=superclass.namelist||[] rescue []
|
596
635
|
result.concat @namelist if defined? @namelist
|
636
|
+
result.uniq!
|
597
637
|
return result
|
598
638
|
end
|
599
639
|
|
600
640
|
def lhs_unparse o; unparse(o) end
|
601
641
|
|
642
|
+
def to_ruby o={}; unparse(o) end
|
643
|
+
|
602
644
|
def to_parsetree(*options)
|
603
645
|
o={}
|
604
646
|
[:newlines,:quirks,:ruby187].each{|opt|
|
@@ -753,6 +795,26 @@ class RedParse
|
|
753
795
|
=end
|
754
796
|
end
|
755
797
|
|
798
|
+
def rgrep pattern
|
799
|
+
result=grep(pattern)
|
800
|
+
each{|subnode| result.concat subnode.rgrep(pattern) if subnode.respond_to? :rgrep}
|
801
|
+
return result
|
802
|
+
end
|
803
|
+
|
804
|
+
def rfind ifnone=nil, &block
|
805
|
+
result=find(proc{
|
806
|
+
find{|subnode| subnode.rfind(&block) if subnode.respond_to? :rfind}
|
807
|
+
},&block)
|
808
|
+
return result if result
|
809
|
+
return ifnone[] if ifnone
|
810
|
+
end
|
811
|
+
|
812
|
+
def rfind_all &block
|
813
|
+
result=find_all(&block)
|
814
|
+
each{|subnode| result.concat subnode.find_all(&block) if subnode.respond_to? :rfind_all}
|
815
|
+
return result
|
816
|
+
end
|
817
|
+
|
756
818
|
def replace_ivars_and_self o,session,&replace_self_action
|
757
819
|
o.instance_variables.each{|ovname|
|
758
820
|
ov=o.instance_variable_get(ovname)
|
@@ -1086,21 +1148,43 @@ end
|
|
1086
1148
|
when '&'; amp=val.parsetree(o)
|
1087
1149
|
end
|
1088
1150
|
}
|
1089
|
-
return output,star
|
1151
|
+
return output,star
|
1090
1152
|
end
|
1091
1153
|
|
1092
1154
|
def unparse_nl(token,o,alt=';',nl="\n")
|
1093
|
-
|
1155
|
+
fail unless alt
|
1094
1156
|
#should really only emit newlines
|
1095
1157
|
#to bring line count up to startline, not endline.
|
1096
1158
|
|
1097
|
-
linenum=
|
1159
|
+
linenum=
|
1160
|
+
case token
|
1161
|
+
when Integer; token
|
1162
|
+
when nil; return alt
|
1163
|
+
else token.startline rescue (return alt)
|
1164
|
+
end
|
1098
1165
|
shy=(linenum||0)-o[:linenum]
|
1166
|
+
#warn if shy<0 ???
|
1099
1167
|
return alt if shy<=0
|
1100
1168
|
o[:linenum]=linenum
|
1101
1169
|
return nl*shy
|
1102
1170
|
end
|
1103
1171
|
|
1172
|
+
def unparse_maybe_parens(o,changed=[])
|
1173
|
+
result=unparse(o)
|
1174
|
+
if !o[:exact] and
|
1175
|
+
case self
|
1176
|
+
when CallNode; params and params.size>0 and !real_parens
|
1177
|
+
when KWCallNode,AliasNode,UndefNode,SequenceNode; true
|
1178
|
+
when AssignNode; MultiAssign===left
|
1179
|
+
end
|
1180
|
+
then
|
1181
|
+
result="(#{result})"
|
1182
|
+
changed[0]=true
|
1183
|
+
end
|
1184
|
+
return result
|
1185
|
+
end
|
1186
|
+
protected :unparse_maybe_parens
|
1187
|
+
|
1104
1188
|
def default_unparse_options
|
1105
1189
|
{:linenum=>1}
|
1106
1190
|
end
|
@@ -1271,13 +1355,21 @@ end
|
|
1271
1355
|
|
1272
1356
|
class RawOpNode<ValueNode
|
1273
1357
|
param_names(:left,:op,:right)
|
1274
|
-
def initialize(
|
1275
|
-
|
1358
|
+
def initialize(*args)
|
1359
|
+
options=args.pop if Hash===args.last
|
1360
|
+
if args.size==2
|
1361
|
+
left,right=*args
|
1362
|
+
op=nil
|
1363
|
+
else
|
1364
|
+
left,op,right=*args
|
1365
|
+
end
|
1276
1366
|
if op.respond_to? :ident
|
1277
1367
|
@offset=op.offset
|
1278
1368
|
op=op.ident
|
1279
1369
|
end
|
1280
|
-
|
1370
|
+
args=left,op,right
|
1371
|
+
args.push options if options
|
1372
|
+
super( *args )
|
1281
1373
|
end
|
1282
1374
|
|
1283
1375
|
# def initialize_copy other
|
@@ -1441,12 +1533,15 @@ end
|
|
1441
1533
|
class LiteralNode<ValueNode; end
|
1442
1534
|
class StringNode<ValueNode; end
|
1443
1535
|
class StringCatNode < ValueNode; end
|
1444
|
-
class NopNode<ValueNode; end
|
1445
1536
|
class VarLikeNode<ValueNode; end #nil,false,true,__FILE__,__LINE__,self
|
1537
|
+
class SequenceNode<ListOpNode; end
|
1538
|
+
class NopNode<SequenceNode; end
|
1539
|
+
class UnOpNode<ValueNode; end
|
1446
1540
|
|
1447
1541
|
class SequenceNode<ListOpNode
|
1448
1542
|
def initialize(*args)
|
1449
|
-
|
1543
|
+
return if args.empty?
|
1544
|
+
super
|
1450
1545
|
@offset=self.first.offset
|
1451
1546
|
end
|
1452
1547
|
def +(other)
|
@@ -1480,11 +1575,18 @@ end
|
|
1480
1575
|
|
1481
1576
|
LITFIX=LiteralNode&-{:val=>Fixnum}
|
1482
1577
|
LITRANGE=RangeNode&-{:left=>LITFIX,:right=>LITFIX}
|
1483
|
-
LITSTR=StringNode&-{:
|
1578
|
+
LITSTR=Recursive(ls={},StringNode&-{:char=>/^[^`\[{]$/}&+[(String|ls).+])
|
1484
1579
|
#LITCAT=proc{|item| item.grep(~LITSTR).empty?}
|
1485
1580
|
#class<<LITCAT; alias === call; end
|
1486
1581
|
LITCAT=StringCatNode& item_that.grep(~LITSTR).empty? #+[LITSTR.+]
|
1487
|
-
|
1582
|
+
LITUPLUS=Recursive(lup={},
|
1583
|
+
UnOpNode&-{:op=>"+@", :val=>
|
1584
|
+
(LiteralNode&-{:val=>Symbol|Numeric})|
|
1585
|
+
(StringNode&-{:size=>1,:char=>"/"})|
|
1586
|
+
lup
|
1587
|
+
}
|
1588
|
+
)
|
1589
|
+
LITNODE=LiteralNode|NopNode|LITSTR|LITCAT|(VarLikeNode&-{:name=>/^__/})|LITUPLUS
|
1488
1590
|
#VarNode| #why not this too?
|
1489
1591
|
def parsetree(o)
|
1490
1592
|
data=compact
|
@@ -1509,6 +1611,7 @@ end
|
|
1509
1611
|
(items[i,1] = *header[1..-1]) if header and header.first==:block
|
1510
1612
|
}
|
1511
1613
|
end
|
1614
|
+
result=
|
1512
1615
|
if items.size>1
|
1513
1616
|
items.unshift :block
|
1514
1617
|
elsif items.size==1
|
@@ -1516,6 +1619,13 @@ end
|
|
1516
1619
|
else
|
1517
1620
|
items
|
1518
1621
|
end
|
1622
|
+
|
1623
|
+
limit=o[:quirks] ? 1 : result.size-1
|
1624
|
+
(0..limit).each{|i|
|
1625
|
+
result[i,1]=result[i][1..-1] if Array===result[i] and result[i][0]==:block
|
1626
|
+
}
|
1627
|
+
|
1628
|
+
return result
|
1519
1629
|
end
|
1520
1630
|
|
1521
1631
|
def unparse o=default_unparse_options
|
@@ -1582,12 +1692,18 @@ end
|
|
1582
1692
|
|
1583
1693
|
class RangeNode
|
1584
1694
|
param_names(:first,:op,:last)
|
1585
|
-
def initialize(
|
1586
|
-
|
1587
|
-
|
1695
|
+
def initialize(*args)
|
1696
|
+
options=Hash===args.last ? args.pop : {}
|
1697
|
+
if args.size==2
|
1698
|
+
left,right=*args
|
1699
|
+
op=".."
|
1700
|
+
else
|
1701
|
+
left,op,right=*args
|
1702
|
+
op=op.ident if op.respond_to? :ident
|
1703
|
+
end
|
1588
1704
|
@exclude_end=!!op[2]
|
1589
1705
|
@as_flow_control=false
|
1590
|
-
super(left,op,right)
|
1706
|
+
super(left,op,right,options)
|
1591
1707
|
end
|
1592
1708
|
def begin; first end
|
1593
1709
|
def end; last end
|
@@ -1651,15 +1767,26 @@ end
|
|
1651
1767
|
|
1652
1768
|
class UnOpNode<ValueNode
|
1653
1769
|
param_names(:op,:val)
|
1654
|
-
def
|
1770
|
+
def self.create(op,val)
|
1771
|
+
return UnaryStarNode.new(op,val) if /\*$/===op.ident
|
1772
|
+
return UnaryAmpNode.new(op,val) if /&$/===op.ident
|
1773
|
+
return new(op,val)
|
1774
|
+
end
|
1775
|
+
|
1776
|
+
def initialize(op,val,options=nil)
|
1655
1777
|
@offset||=op.offset rescue val.offset
|
1656
1778
|
op=op.ident if op.respond_to? :ident
|
1657
1779
|
/([&*])$/===op and op=$1+"@"
|
1658
1780
|
/^(?:!|not)$/===op and
|
1659
1781
|
val.respond_to? :special_conditions! and
|
1660
1782
|
val.special_conditions!
|
1661
|
-
|
1783
|
+
args=[op,val]
|
1784
|
+
args<<options if options
|
1785
|
+
super(*args)
|
1662
1786
|
end
|
1787
|
+
|
1788
|
+
def arg; val end
|
1789
|
+
def arg= x; self.val=x end
|
1663
1790
|
|
1664
1791
|
alias ident op
|
1665
1792
|
|
@@ -1700,16 +1827,29 @@ end
|
|
1700
1827
|
op=op()
|
1701
1828
|
op=op.chomp "@"
|
1702
1829
|
result=op
|
1703
|
-
result+=" " if
|
1830
|
+
result+=" " if /(?:#{LETTER}|[?!])$/o===op or /^[+-]/===op && LiteralNode===val
|
1704
1831
|
result+=val.unparse(o)
|
1705
1832
|
end
|
1706
1833
|
end
|
1834
|
+
UnaryOpNode=UnOpNode
|
1835
|
+
|
1836
|
+
class UnaryAmpNode<UnOpNode
|
1837
|
+
|
1838
|
+
end
|
1707
1839
|
|
1708
1840
|
class UnaryStarNode<UnOpNode
|
1709
|
-
def initialize(
|
1710
|
-
|
1841
|
+
def initialize(*args)
|
1842
|
+
options=args.pop if Hash===args.last
|
1843
|
+
if args.size==1
|
1844
|
+
op="*@"
|
1845
|
+
val=args.first
|
1846
|
+
else
|
1847
|
+
op,val=*args
|
1848
|
+
end
|
1711
1849
|
op.ident="*@" if op.respond_to? :ident
|
1712
|
-
|
1850
|
+
args=[op,val]
|
1851
|
+
args.push options if options
|
1852
|
+
super(*args)
|
1713
1853
|
end
|
1714
1854
|
|
1715
1855
|
class<<self
|
@@ -1744,6 +1884,10 @@ end
|
|
1744
1884
|
@startline=@endline=star.startline if star.respond_to? :startline
|
1745
1885
|
super('*@',var||VarNode[''])
|
1746
1886
|
end
|
1887
|
+
def self.create(star,var=nil)
|
1888
|
+
DanglingStarNode.new(star,var)
|
1889
|
+
end
|
1890
|
+
|
1747
1891
|
attr :offset
|
1748
1892
|
def lvars_defined_in; [] end
|
1749
1893
|
def parsetree(o); [:splat] end
|
@@ -1812,11 +1956,17 @@ end
|
|
1812
1956
|
attr_writer :lvalue
|
1813
1957
|
identity_param :lvalue, nil, true
|
1814
1958
|
|
1815
|
-
def inspect label=nil,indent=0
|
1959
|
+
def inspect label=nil,indent=0,verbose=false
|
1816
1960
|
result=' '*indent
|
1817
1961
|
result+="#{label}: " if label
|
1818
1962
|
result+='Constant '
|
1819
|
-
|
1963
|
+
unless String===first or nil==first
|
1964
|
+
head=first
|
1965
|
+
rest=self[1..-1]
|
1966
|
+
end
|
1967
|
+
result+=(rest||self).map{|name| name.inspect}.join(', ')+"\n"
|
1968
|
+
result+=head.inspect("head",indent+2,verbose) if head
|
1969
|
+
return result
|
1820
1970
|
end
|
1821
1971
|
end
|
1822
1972
|
LookupNode=ConstantNode
|
@@ -1881,7 +2031,8 @@ end
|
|
1881
2031
|
param_names :body
|
1882
2032
|
alias val body
|
1883
2033
|
alias val= body=
|
1884
|
-
def initialize(lparen,body,rparen)
|
2034
|
+
def initialize(lparen=nil,body=nil,rparen=nil)
|
2035
|
+
return unless body
|
1885
2036
|
@offset=lparen.offset
|
1886
2037
|
self[0]=body
|
1887
2038
|
end
|
@@ -1903,11 +2054,11 @@ end
|
|
1903
2054
|
def op?; false end
|
1904
2055
|
|
1905
2056
|
def parsetree(o)
|
1906
|
-
|
2057
|
+
body ? body.parsetree(o) : [:nil]
|
1907
2058
|
end
|
1908
2059
|
|
1909
2060
|
def rescue_parsetree o
|
1910
|
-
body.rescue_parsetree
|
2061
|
+
body ? body.rescue_parsetree(o) : [:nil]
|
1911
2062
|
# result.first==:begin and result=result.last unless o[:ruby187]
|
1912
2063
|
# result
|
1913
2064
|
end
|
@@ -1923,13 +2074,14 @@ end
|
|
1923
2074
|
identity_param :lvalue, nil, true
|
1924
2075
|
|
1925
2076
|
def unparse(o=default_unparse_options)
|
1926
|
-
"(
|
2077
|
+
"(#{body&&body.unparse(o)})"
|
1927
2078
|
end
|
1928
2079
|
end
|
1929
2080
|
|
1930
2081
|
module HasRescue
|
1931
2082
|
def parsetree_and_rescues(o)
|
1932
2083
|
body=body()
|
2084
|
+
body=body.clone if body
|
1933
2085
|
target=result=[] #was: [:begin, ]
|
1934
2086
|
|
1935
2087
|
#body,rescues,else_,ensure_=*self
|
@@ -1971,12 +2123,12 @@ end
|
|
1971
2123
|
def unparse_and_rescues(o)
|
1972
2124
|
result=" "
|
1973
2125
|
result+= body.unparse(o) if body
|
1974
|
-
result+=unparse_nl(rescues.first,o)
|
1975
|
-
rescues.each{|resc| result+=resc.unparse(o) }
|
2126
|
+
result+=unparse_nl(rescues.first,o) if rescues
|
2127
|
+
rescues.each{|resc| result+=resc.unparse(o) } if rescues
|
1976
2128
|
result+=unparse_nl(else_,o)+"else "+else_.unparse(o) if else_
|
1977
|
-
result+=";else" if @empty_else
|
2129
|
+
result+=";else" if defined? @empty_else and @empty_else
|
1978
2130
|
result+=unparse_nl(ensure_,o)+"ensure "+ensure_.unparse(o) if ensure_
|
1979
|
-
result+=";ensure" if @empty_ensure
|
2131
|
+
result+=";ensure" if defined? @empty_ensure and @empty_ensure
|
1980
2132
|
return result
|
1981
2133
|
end
|
1982
2134
|
|
@@ -2026,6 +2178,14 @@ end
|
|
2026
2178
|
|
2027
2179
|
def parsetree(o)
|
2028
2180
|
result=parsetree_and_rescues(o)
|
2181
|
+
|
2182
|
+
=begin should be something like this:
|
2183
|
+
limit=o[:quirks] ? 1 : result.size
|
2184
|
+
(0...limit).each{|i|
|
2185
|
+
result[i,1]=result[i][1..-1] if Array===result[i] and result[i][0]==:block
|
2186
|
+
}
|
2187
|
+
=end
|
2188
|
+
|
2029
2189
|
if o[:ruby187] and result.first==:begin
|
2030
2190
|
result=result[1]
|
2031
2191
|
else
|
@@ -2041,7 +2201,7 @@ end
|
|
2041
2201
|
end
|
2042
2202
|
|
2043
2203
|
def begin_parsetree(o)
|
2044
|
-
body,rescues,else_,ensure_=*self
|
2204
|
+
#body,rescues,else_,ensure_=*self
|
2045
2205
|
needbegin=(rescues&&!rescues.empty?) || ensure_ || @empty_ensure
|
2046
2206
|
result=parsetree(o)
|
2047
2207
|
needbegin and result=[:begin, result] unless result.first==:begin
|
@@ -2073,11 +2233,18 @@ end
|
|
2073
2233
|
replace [expr,[RescueNode[[],nil,backup]].extend(ListInNode)]
|
2074
2234
|
end
|
2075
2235
|
|
2236
|
+
def self.namelist
|
2237
|
+
%w[left right]
|
2238
|
+
end
|
2239
|
+
|
2076
2240
|
def else; nil end
|
2077
2241
|
def ensure; nil end
|
2078
2242
|
|
2079
2243
|
def left; body end
|
2080
2244
|
def right; rescues[0].action end
|
2245
|
+
def op; "rescue" end
|
2246
|
+
|
2247
|
+
alias rescue_with right
|
2081
2248
|
|
2082
2249
|
alias ensure_ ensure
|
2083
2250
|
alias else_ else
|
@@ -2104,7 +2271,7 @@ end
|
|
2104
2271
|
|
2105
2272
|
rescues=rescues().map{|resc| resc.parsetree(o)}
|
2106
2273
|
target.push newtarget=[:rescue, ]
|
2107
|
-
else_=nil
|
2274
|
+
#else_=nil
|
2108
2275
|
needbegin= (BeginNode===body and body.after_equals)
|
2109
2276
|
huh if needbegin and RescueOpNode===body #need test case for this
|
2110
2277
|
huh if needbegin and ParenedNode===body #need test case for this
|
@@ -2173,10 +2340,10 @@ end
|
|
2173
2340
|
else
|
2174
2341
|
rhs=RescueOpNode.new(rescuee.val,op2,rescuer)
|
2175
2342
|
end
|
2343
|
+
super(lhs,op,rhs)
|
2176
2344
|
else
|
2177
|
-
|
2345
|
+
super(args[0],args[1],args[3])
|
2178
2346
|
end
|
2179
|
-
super(lhs,op,rhs)
|
2180
2347
|
else super
|
2181
2348
|
end
|
2182
2349
|
end
|
@@ -2193,7 +2360,10 @@ end
|
|
2193
2360
|
rhs=RescueOpNode.new(rescuee.val,op2,rescuer)
|
2194
2361
|
end
|
2195
2362
|
else
|
2196
|
-
lhs
|
2363
|
+
lhs=args.shift
|
2364
|
+
op=args.shift
|
2365
|
+
args.shift #bogus1
|
2366
|
+
rhs=args.shift
|
2197
2367
|
end
|
2198
2368
|
else
|
2199
2369
|
lhs,op,rhs=*args
|
@@ -2424,7 +2594,7 @@ end
|
|
2424
2594
|
def unparse(o=default_unparse_options)
|
2425
2595
|
result=lhs.lhs_unparse(o)
|
2426
2596
|
result="(#{result})" if defined? @lhs_parens
|
2427
|
-
result+op+
|
2597
|
+
result+' '+op+' '+
|
2428
2598
|
(rhs.class==Array ?
|
2429
2599
|
rhs.map{|rv| rv.unparse o}.join(',') :
|
2430
2600
|
rhs.unparse(o)
|
@@ -2594,6 +2764,7 @@ end
|
|
2594
2764
|
data=CommaOpNode===item ? Array.new(item) : [item]
|
2595
2765
|
@had_parens=true
|
2596
2766
|
end
|
2767
|
+
data= Array.new(data) if CommaOpNode===data
|
2597
2768
|
|
2598
2769
|
super(data) unless data.empty?
|
2599
2770
|
end
|
@@ -2639,7 +2810,7 @@ end
|
|
2639
2810
|
[:op_asgn2, rcvr,prop, op.to_sym, args]
|
2640
2811
|
end
|
2641
2812
|
end
|
2642
|
-
end
|
2813
|
+
end if false
|
2643
2814
|
|
2644
2815
|
class LogicalNode
|
2645
2816
|
include KeywordOpNode
|
@@ -2757,7 +2928,10 @@ end
|
|
2757
2928
|
|
2758
2929
|
def while; condition end
|
2759
2930
|
def do; consequent end
|
2931
|
+
alias body do
|
2760
2932
|
def op; "while" end
|
2933
|
+
def reversed; false end
|
2934
|
+
attr :test_first
|
2761
2935
|
|
2762
2936
|
def parsetree(o)
|
2763
2937
|
cond=condition.rescue_parsetree(o)
|
@@ -2795,7 +2969,9 @@ end
|
|
2795
2969
|
|
2796
2970
|
def while; negate condition end
|
2797
2971
|
def do; consequent end
|
2972
|
+
alias body do
|
2798
2973
|
def op; "until" end
|
2974
|
+
def reversed; true end
|
2799
2975
|
|
2800
2976
|
def parsetree(o)
|
2801
2977
|
cond=condition.rescue_parsetree(o)
|
@@ -2881,13 +3057,48 @@ end
|
|
2881
3057
|
end
|
2882
3058
|
|
2883
3059
|
class CallSiteNode<ValueNode
|
2884
|
-
param_names :receiver, :name, :params, :blockparams, :block
|
3060
|
+
param_names :receiver, :name, :params, :blockparams, :locals, :block
|
3061
|
+
|
2885
3062
|
alias blockargs blockparams
|
2886
3063
|
alias block_args blockargs
|
2887
3064
|
alias block_params blockparams
|
2888
3065
|
|
2889
|
-
|
2890
|
-
|
3066
|
+
alias block_locals locals
|
3067
|
+
alias blocklocals locals
|
3068
|
+
alias locals_in_block locals
|
3069
|
+
|
3070
|
+
def initialize(*args)
|
3071
|
+
if KeywordToken===args.first and args.first.ident=='('
|
3072
|
+
method,open_paren,param_list,close_paren,block="()",*args
|
3073
|
+
parened=open_paren
|
3074
|
+
else
|
3075
|
+
method,open_paren,param_list,close_paren,block=*args
|
3076
|
+
@not_real_parens=!open_paren || open_paren.not_real?
|
3077
|
+
end
|
3078
|
+
|
3079
|
+
if KeywordToken===method and method.ident=='->'
|
3080
|
+
if SequenceNode===param_list
|
3081
|
+
blockparams,blocklocals,* = param_list
|
3082
|
+
if CommaOpNode===blocklocals
|
3083
|
+
blocklocals=Array(blocklocals)
|
3084
|
+
else
|
3085
|
+
blocklocals=[blocklocals]
|
3086
|
+
end
|
3087
|
+
blocklocals.map!{|bl| bl.ident}
|
3088
|
+
blocklocals.extend ListInNode
|
3089
|
+
else
|
3090
|
+
blockparams= param_list
|
3091
|
+
end
|
3092
|
+
|
3093
|
+
if CommaOpNode===blockparams
|
3094
|
+
blockparams=Array(blockparams)
|
3095
|
+
elsif blockparams
|
3096
|
+
blockparams=[blockparams]
|
3097
|
+
end
|
3098
|
+
|
3099
|
+
blockparams=BlockParams.new blockparams if blockparams
|
3100
|
+
param_list=nil
|
3101
|
+
end
|
2891
3102
|
|
2892
3103
|
case param_list
|
2893
3104
|
when CommaOpNode
|
@@ -2914,28 +3125,39 @@ end
|
|
2914
3125
|
|
2915
3126
|
if block
|
2916
3127
|
@do_end=block.do_end
|
2917
|
-
blockparams
|
3128
|
+
blockparams||=block.params
|
3129
|
+
blocklocals||=block.locals
|
2918
3130
|
block=block.body #||[]
|
2919
3131
|
end
|
2920
|
-
@offset=method.offset
|
2921
3132
|
if Token===method
|
3133
|
+
@offset=method.offset
|
2922
3134
|
method=method.ident
|
2923
3135
|
fail unless String===method
|
3136
|
+
else
|
3137
|
+
@offset=parened&&parened.offset
|
2924
3138
|
end
|
2925
3139
|
|
2926
|
-
super(nil,method,param_list,blockparams,block)
|
3140
|
+
super(nil,method,param_list,blockparams,blocklocals,block)
|
2927
3141
|
#receiver, if any, is tacked on later
|
2928
3142
|
end
|
2929
3143
|
|
2930
|
-
def real_parens; !@not_real_parens end
|
3144
|
+
def real_parens; @not_real_parens||=nil; !@not_real_parens end
|
2931
3145
|
def real_parens= x; @not_real_parens=!x end
|
3146
|
+
alias has_parens? real_parens
|
2932
3147
|
|
2933
3148
|
def unparse o=default_unparse_options
|
2934
3149
|
fail if block==false
|
3150
|
+
parensadded=[false]
|
3151
|
+
params=params()
|
3152
|
+
params&&=params.map{|param|
|
3153
|
+
unparse_nl(param,o,'',"\\\n")+param.unparse_maybe_parens(o,parensadded)
|
3154
|
+
}.join(', ')
|
3155
|
+
real_parens=real_parens() || parensadded[0]
|
2935
3156
|
result=[
|
2936
|
-
receiver&&receiver.unparse(o)+'.',
|
3157
|
+
receiver&&receiver.unparse(o)+'.',
|
3158
|
+
name=='()' ? '' : name,
|
2937
3159
|
real_parens ? '(' : (' ' if params),
|
2938
|
-
params
|
3160
|
+
params,
|
2939
3161
|
real_parens ? ')' : nil,
|
2940
3162
|
|
2941
3163
|
block&&[
|
@@ -2951,7 +3173,7 @@ end
|
|
2951
3173
|
end
|
2952
3174
|
|
2953
3175
|
def image
|
2954
|
-
|
3176
|
+
"(#{receiver.image if receiver}.#{name})"
|
2955
3177
|
end
|
2956
3178
|
|
2957
3179
|
def with_commas
|
@@ -3155,12 +3377,12 @@ end
|
|
3155
3377
|
end
|
3156
3378
|
|
3157
3379
|
class CallNode<CallSiteNode #normal method calls
|
3158
|
-
def initialize(
|
3380
|
+
def initialize(*args)
|
3159
3381
|
super
|
3160
3382
|
end
|
3161
3383
|
end
|
3162
3384
|
class KWCallNode<CallSiteNode #keywords that look (more or less) like methods
|
3163
|
-
def initialize(method
|
3385
|
+
def initialize(method,*args)
|
3164
3386
|
KeywordToken===method or fail
|
3165
3387
|
super
|
3166
3388
|
end
|
@@ -3188,14 +3410,26 @@ end
|
|
3188
3410
|
end
|
3189
3411
|
|
3190
3412
|
class BlockNode<ValueNode #not to appear in final parse tree
|
3191
|
-
param_names :params,:body
|
3413
|
+
param_names :params,:locals,:body
|
3192
3414
|
def initialize(open_brace,formals,stmts,close_brace)
|
3193
3415
|
stmts||=SequenceNode[{:@offset => open_brace.offset, :@startline=>open_brace.startline}]
|
3194
3416
|
stmts=SequenceNode[stmts,{:@offset => open_brace.offset, :@startline=>open_brace.startline}] unless SequenceNode===stmts
|
3195
3417
|
|
3418
|
+
if formals and formals.size==1 and SequenceNode===formals[0]
|
3419
|
+
formals,blocklocals,* = formals[0]
|
3420
|
+
formals&&=BlockParams[formals]
|
3421
|
+
if CommaOpNode===blocklocals
|
3422
|
+
blocklocals=Array(blocklocals)
|
3423
|
+
else
|
3424
|
+
blocklocals=[blocklocals]
|
3425
|
+
end
|
3426
|
+
blocklocals.map!{|bl| bl.ident}
|
3427
|
+
blocklocals.extend ListInNode
|
3428
|
+
end
|
3429
|
+
|
3196
3430
|
formals&&=BlockParams.new(Array.new(formals))
|
3197
3431
|
@do_end=true unless open_brace.not_real?
|
3198
|
-
super(formals,stmts)
|
3432
|
+
super(formals,blocklocals,stmts)
|
3199
3433
|
end
|
3200
3434
|
|
3201
3435
|
attr_reader :do_end
|
@@ -3225,12 +3459,31 @@ end
|
|
3225
3459
|
end
|
3226
3460
|
end
|
3227
3461
|
|
3228
|
-
class
|
3462
|
+
class ProcLiteralNode<ValueNode
|
3463
|
+
def initialize(params, other_locals, body)
|
3464
|
+
@params, @other_locals, @body= params, other_locals, body
|
3465
|
+
end
|
3466
|
+
|
3467
|
+
def self.create(arrow, lparen, params, rparen, do_word, body, endword)
|
3468
|
+
params,other_locals=*params if SequenceNode===params
|
3469
|
+
new(params,other_locals,body)
|
3470
|
+
end
|
3471
|
+
|
3472
|
+
def unparse o=default_parse_options
|
3473
|
+
huh
|
3474
|
+
end
|
3475
|
+
end
|
3476
|
+
|
3477
|
+
class NopNode<SequenceNode
|
3229
3478
|
def initialize(*args)
|
3230
3479
|
@startline=@endline=1
|
3231
3480
|
super()
|
3232
3481
|
end
|
3482
|
+
def unparse(o=default_unparse_options)
|
3483
|
+
""
|
3484
|
+
end
|
3233
3485
|
|
3486
|
+
=begin
|
3234
3487
|
def unparse o=default_unparse_options
|
3235
3488
|
''
|
3236
3489
|
end
|
@@ -3244,6 +3497,7 @@ end
|
|
3244
3497
|
def to_parsetree(*options)
|
3245
3498
|
[]
|
3246
3499
|
end
|
3500
|
+
=end
|
3247
3501
|
end
|
3248
3502
|
|
3249
3503
|
=begin
|
@@ -3318,6 +3572,7 @@ end
|
|
3318
3572
|
@open||='"'
|
3319
3573
|
@close||='"'
|
3320
3574
|
@bs_handler||=:dquote_esc_seq
|
3575
|
+
@modifiers||=nil
|
3321
3576
|
if /[\[{]/===@char
|
3322
3577
|
@parses_like||=split_into_words(str)
|
3323
3578
|
end
|
@@ -3328,7 +3583,6 @@ end
|
|
3328
3583
|
result=str.dup
|
3329
3584
|
seq=result.to_sequence
|
3330
3585
|
rl.instance_eval{@file=seq}
|
3331
|
-
repls=[]
|
3332
3586
|
i=0
|
3333
3587
|
#ugly ugly ugly... all so I can call @bs_handler
|
3334
3588
|
while i<result.size and bs_at=result.index(/\\./m,i)
|
@@ -3371,6 +3625,7 @@ end
|
|
3371
3625
|
o[:linenum]+=@open.count("\n")
|
3372
3626
|
result=[@open,unparse_interior(o),@close,@modifiers].join
|
3373
3627
|
o[:linenum]+=@close.count("\n")
|
3628
|
+
result<<" " if /\r\z/===result
|
3374
3629
|
return result
|
3375
3630
|
end
|
3376
3631
|
|
@@ -3378,8 +3633,10 @@ end
|
|
3378
3633
|
unless escapable=ESCAPABLES[open]
|
3379
3634
|
maybe_crunch='\\#' if %r{\A["`/\{]\Z} === @char and open[1] != ?q and open != "'" #"
|
3380
3635
|
#crunch (#) might need to be escaped too, depending on what @char is
|
3636
|
+
quotes=open[-1,1]
|
3637
|
+
quotes+=close unless quotes==close
|
3381
3638
|
escapable=ESCAPABLES[open]=
|
3382
|
-
/[#{Regexp.quote
|
3639
|
+
/[#{Regexp.quote(quotes)}#{maybe_crunch}]/
|
3383
3640
|
end
|
3384
3641
|
escapable
|
3385
3642
|
end
|
@@ -3387,7 +3644,8 @@ end
|
|
3387
3644
|
def unparse_interior o,open=@open,close=@close,escape=nil
|
3388
3645
|
escapable=escapable(open,close)
|
3389
3646
|
result=map{|substr|
|
3390
|
-
|
3647
|
+
case substr
|
3648
|
+
when String
|
3391
3649
|
|
3392
3650
|
#hack: this is needed for here documents only, because their
|
3393
3651
|
#delimiter is changing.
|
@@ -3396,6 +3654,8 @@ end
|
|
3396
3654
|
o[:linenum]+=substr.count("\n") if o[:linenum]
|
3397
3655
|
|
3398
3656
|
substr
|
3657
|
+
when NopNode
|
3658
|
+
'#{}'
|
3399
3659
|
else
|
3400
3660
|
['#{',substr.unparse(o),'}']
|
3401
3661
|
end
|
@@ -3427,7 +3687,7 @@ end
|
|
3427
3687
|
|
3428
3688
|
# data=tokens.inject([]){|sum,token|
|
3429
3689
|
# data=elems=token.string.elems
|
3430
|
-
data=elems=
|
3690
|
+
data= #elems=
|
3431
3691
|
case token
|
3432
3692
|
when StringToken; token.elems
|
3433
3693
|
when HerePlaceholderToken; token.string.elems
|
@@ -3439,7 +3699,6 @@ end
|
|
3439
3699
|
# endline=@endline
|
3440
3700
|
1.step(data.length-1,2){|i|
|
3441
3701
|
tokens=data[i].ident.dup
|
3442
|
-
line=data[i].linenum
|
3443
3702
|
|
3444
3703
|
#replace trailing } with EoiToken
|
3445
3704
|
(tokens.size-1).downto(0){|j|
|
@@ -3496,17 +3755,17 @@ end
|
|
3496
3755
|
DQ_ESC=/(?>\\(?>[CM]-|c)?)/
|
3497
3756
|
DQ_EVEN=%r[
|
3498
3757
|
(?:
|
3499
|
-
\
|
3758
|
+
\G |
|
3500
3759
|
[^\\c-] |
|
3501
|
-
(?>\
|
3502
|
-
(?> [^CM] | (?>\
|
3760
|
+
(?>\G|[^\\])c |
|
3761
|
+
(?> [^CM] | (?>\G|[^\\])[CM] )-
|
3503
3762
|
) #not esc
|
3504
3763
|
#{DQ_ESC}{2}* #an even number of esc
|
3505
3764
|
]omx
|
3506
3765
|
DQ_ODD=/#{DQ_EVEN}#{DQ_ESC}/omx
|
3507
3766
|
SQ_ESC=/\\/
|
3508
3767
|
SQ_EVEN=%r[
|
3509
|
-
(?: \
|
3768
|
+
(?: \G | [^\\] ) #not esc
|
3510
3769
|
#{SQ_ESC}{2}* #an even number of esc
|
3511
3770
|
]omx
|
3512
3771
|
SQ_ODD=/#{SQ_EVEN}#{SQ_ESC}/omx
|
@@ -3815,9 +4074,9 @@ end
|
|
3815
4074
|
|
3816
4075
|
class LiteralNode<ValueNode
|
3817
4076
|
param_names :val
|
3818
|
-
attr_accessor :offset
|
3819
|
-
def
|
3820
|
-
|
4077
|
+
attr_accessor :offset, :string
|
4078
|
+
def self.create(old_val)
|
4079
|
+
offset=old_val.offset
|
3821
4080
|
val=old_val.ident
|
3822
4081
|
case old_val
|
3823
4082
|
when SymbolToken
|
@@ -3842,12 +4101,15 @@ end
|
|
3842
4101
|
end
|
3843
4102
|
when NumberToken
|
3844
4103
|
case val
|
3845
|
-
when /\A
|
3846
|
-
when /[.e]/i; val=val.to_f
|
4104
|
+
when /\A[+-]?0([^.]|\Z)/; val=val.oct
|
4105
|
+
when /[.e]/i; orig=val; val=val.to_f
|
3847
4106
|
else val=val.to_i
|
3848
4107
|
end
|
3849
4108
|
end
|
3850
|
-
|
4109
|
+
result=LiteralNode.new(val)
|
4110
|
+
result.string=orig if orig
|
4111
|
+
result.offset=offset
|
4112
|
+
result
|
3851
4113
|
end
|
3852
4114
|
|
3853
4115
|
def self.inline_symbols data
|
@@ -3881,16 +4143,19 @@ end
|
|
3881
4143
|
":"+
|
3882
4144
|
val.unparse(o)
|
3883
4145
|
when Float
|
3884
|
-
|
3885
|
-
|
3886
|
-
case s
|
3887
|
-
when /-inf/i; s="-"+Inf
|
3888
|
-
when /inf/i; s= Inf
|
3889
|
-
when /nan/i; s= Nan
|
4146
|
+
if defined? @string;
|
4147
|
+
@string
|
3890
4148
|
else
|
3891
|
-
|
4149
|
+
s= val.accurate_to_s
|
4150
|
+
case s
|
4151
|
+
when /-inf/i; s="-"+Inf
|
4152
|
+
when /inf/i; s= Inf
|
4153
|
+
when /nan/i; s= Nan
|
4154
|
+
else
|
4155
|
+
fail "float coercion not stable" unless [s.to_f].pack("d")==[val].pack("d")
|
4156
|
+
end
|
4157
|
+
s
|
3892
4158
|
end
|
3893
|
-
s
|
3894
4159
|
else val.inspect
|
3895
4160
|
end
|
3896
4161
|
end
|
@@ -3926,17 +4191,18 @@ end
|
|
3926
4191
|
|
3927
4192
|
class VarLikeNode<ValueNode #nil,false,true,__FILE__,__LINE__,self
|
3928
4193
|
param_names :name
|
3929
|
-
def
|
3930
|
-
|
3931
|
-
|
3932
|
-
#simulate nil
|
3933
|
-
replace ['nil']
|
3934
|
-
@value=nil
|
4194
|
+
def self.new(name,*more)
|
4195
|
+
if name.ident=='(' #shouldn't happen now, AFAICT
|
4196
|
+
ParenedNode.new
|
3935
4197
|
else
|
3936
|
-
|
3937
|
-
@value=name.respond_to?(:value) && name.value
|
4198
|
+
super
|
3938
4199
|
end
|
3939
4200
|
end
|
4201
|
+
def initialize(name,*more)
|
4202
|
+
@offset=name.offset
|
4203
|
+
replace [name.ident]
|
4204
|
+
@value=name.respond_to?(:value) && name.value
|
4205
|
+
end
|
3940
4206
|
|
3941
4207
|
alias ident name
|
3942
4208
|
|
@@ -3986,12 +4252,12 @@ end
|
|
3986
4252
|
def image; "([])" end
|
3987
4253
|
|
3988
4254
|
def unparse o=default_unparse_options
|
3989
|
-
"["+map{|item| unparse_nl(item,o,'')+item.
|
4255
|
+
"["+map{|item| unparse_nl(item,o,'')+item.unparse_maybe_parens(o)}.join(', ')+"]"
|
3990
4256
|
end
|
3991
4257
|
|
3992
4258
|
def parsetree(o)
|
3993
4259
|
size.zero? and return [:zarray]
|
3994
|
-
normals,star
|
4260
|
+
normals,star=param_list_parse(self,o)
|
3995
4261
|
result=normals.unshift :array
|
3996
4262
|
if star
|
3997
4263
|
if size==1
|
@@ -4033,9 +4299,7 @@ end
|
|
4033
4299
|
param_names :condition,:consequent,:elsifs,:otherwise
|
4034
4300
|
def initialize(iftok,condition,thentok,consequent,elsifs,else_,endtok)
|
4035
4301
|
@offset=iftok.offset
|
4036
|
-
|
4037
|
-
else_=else_.val or @empty_else=true
|
4038
|
-
end
|
4302
|
+
@empty_else= else_ && !(else_=else_.val)
|
4039
4303
|
condition.special_conditions! if condition.respond_to? :special_conditions!
|
4040
4304
|
elsifs.extend ListInNode if elsifs
|
4041
4305
|
super(condition,consequent,elsifs,else_)
|
@@ -4060,7 +4324,7 @@ end
|
|
4060
4324
|
result+=unparse_nl(consequent,o)+"#{consequent.unparse(o)}" if consequent
|
4061
4325
|
result+=unparse_nl(elsifs.first,o)+elsifs.map{|n| n.unparse(o)}.join if elsifs
|
4062
4326
|
result+=unparse_nl(else_,o)+"else "+else_.unparse(o) if else_
|
4063
|
-
result+=";else " if defined? @empty_else
|
4327
|
+
result+=";else " if defined? @empty_else and @empty_else
|
4064
4328
|
result+=";end"
|
4065
4329
|
return result
|
4066
4330
|
end
|
@@ -4195,6 +4459,14 @@ end
|
|
4195
4459
|
@reverse ? condition : negate(condition, @loopword_offset)
|
4196
4460
|
end
|
4197
4461
|
|
4462
|
+
def reversed
|
4463
|
+
@reverse
|
4464
|
+
end
|
4465
|
+
|
4466
|
+
def test_first
|
4467
|
+
false
|
4468
|
+
end
|
4469
|
+
|
4198
4470
|
def to_lisp
|
4199
4471
|
body=body()
|
4200
4472
|
"(#{@reverse ? :until : :while} #{condition.to_lisp}\n#{body.to_lisp})"
|
@@ -4334,7 +4606,7 @@ end
|
|
4334
4606
|
def image; "(for)" end
|
4335
4607
|
|
4336
4608
|
def unparse o=default_unparse_options
|
4337
|
-
result=unparse_nl(self,o)+" for #{iterator.lhs_unparse(o)[1...-1]} in #{enumerable.unparse o}"
|
4609
|
+
result=unparse_nl(self,o,"")+" for #{iterator.lhs_unparse(o)[1...-1]} in #{enumerable.unparse o}"
|
4338
4610
|
result+=unparse_nl(body,o)+" #{body.unparse(o)}" if body
|
4339
4611
|
result+=";end"
|
4340
4612
|
end
|
@@ -4399,7 +4671,7 @@ end
|
|
4399
4671
|
super(*data)
|
4400
4672
|
else fail
|
4401
4673
|
end
|
4402
|
-
@no_braces
|
4674
|
+
@no_braces=true unless open
|
4403
4675
|
end
|
4404
4676
|
|
4405
4677
|
attr :no_arrows
|
@@ -4410,15 +4682,15 @@ end
|
|
4410
4682
|
|
4411
4683
|
def unparse o=default_unparse_options
|
4412
4684
|
result=''
|
4413
|
-
result << "{" unless @no_braces
|
4685
|
+
result << "{" unless defined? @no_braces and @no_braces
|
4414
4686
|
arrow= defined?(@no_arrows) ? " , " : " => "
|
4415
4687
|
(0...size).step(2){|i|
|
4416
4688
|
result<< unparse_nl(self[i],o,'')+
|
4417
|
-
self[i].
|
4418
|
-
self[i+1].
|
4689
|
+
self[i].unparse_maybe_parens(o)+arrow+
|
4690
|
+
self[i+1].unparse_maybe_parens(o)+', '
|
4419
4691
|
}
|
4420
4692
|
result.chomp! ', '
|
4421
|
-
result << "}" unless @no_braces
|
4693
|
+
result << "}" unless defined? @no_braces and @no_braces
|
4422
4694
|
return result
|
4423
4695
|
end
|
4424
4696
|
|
@@ -4454,6 +4726,9 @@ end
|
|
4454
4726
|
return true if defined?(@no_arrows) and rubyversion>=1.9
|
4455
4727
|
return super
|
4456
4728
|
end
|
4729
|
+
|
4730
|
+
def blame; self end
|
4731
|
+
def msg; "comma not allowed within pairs in hashes anymore" end
|
4457
4732
|
end
|
4458
4733
|
|
4459
4734
|
class TernaryNode<ValueNode
|
@@ -4499,6 +4774,7 @@ end
|
|
4499
4774
|
# header=header.data[1]
|
4500
4775
|
# end
|
4501
4776
|
if CallSiteNode===header
|
4777
|
+
@parens=header.has_parens?
|
4502
4778
|
receiver=header.receiver
|
4503
4779
|
args=header.args
|
4504
4780
|
header=header.name
|
@@ -4526,6 +4802,10 @@ end
|
|
4526
4802
|
%w[receiver name args body rescues elses ensures]
|
4527
4803
|
end
|
4528
4804
|
|
4805
|
+
def has_parens?;
|
4806
|
+
@parens if defined? @parens
|
4807
|
+
end
|
4808
|
+
|
4529
4809
|
# def receiver= x
|
4530
4810
|
# self[0]=x
|
4531
4811
|
# end
|
@@ -4548,8 +4828,9 @@ end
|
|
4548
4828
|
|
4549
4829
|
def unparse o=default_unparse_options
|
4550
4830
|
result=[
|
4551
|
-
"def ",receiver&&receiver.unparse(o)+'.',name,
|
4552
|
-
args
|
4831
|
+
"def ",receiver&&receiver.unparse(o)+'.',name, has_parens? ? '(' : ' ',
|
4832
|
+
args&&args.map{|arg| arg.unparse o}.join(','),
|
4833
|
+
(')' if has_parens?), unparse_nl(body||self,o)
|
4553
4834
|
]
|
4554
4835
|
result<<unparse_and_rescues(o)
|
4555
4836
|
=begin
|
@@ -4630,6 +4911,7 @@ end
|
|
4630
4911
|
|
4631
4912
|
target.push ensuretarget=target=[:ensure, ] if ensures or @empty_ensure
|
4632
4913
|
#simple dup won't work... won't copy extend'd modules
|
4914
|
+
#should use clone here
|
4633
4915
|
body=Marshal.load(Marshal.dump(body())) if body()
|
4634
4916
|
elses=elses()
|
4635
4917
|
if rescues.empty?
|
@@ -4647,6 +4929,11 @@ end
|
|
4647
4929
|
body.rescues.empty? and !body.ensure and !body.empty_ensure and body.body and body.body.size>1
|
4648
4930
|
wantblock=true
|
4649
4931
|
end
|
4932
|
+
if o[:quirks]
|
4933
|
+
first=body
|
4934
|
+
first=first.first if SequenceNode===first
|
4935
|
+
wantblock=true if UndefNode===first and first.size>1
|
4936
|
+
end
|
4650
4937
|
body=body.parsetree(o)
|
4651
4938
|
if body.first==:block and rescues.empty? and not ensures||@empty_ensure
|
4652
4939
|
if wantblock
|
@@ -4783,6 +5070,7 @@ end
|
|
4783
5070
|
|
4784
5071
|
alias else_ else
|
4785
5072
|
alias ensure_ ensure
|
5073
|
+
alias receiver name
|
4786
5074
|
|
4787
5075
|
def image; "(module #{name})" end
|
4788
5076
|
|
@@ -4832,6 +5120,7 @@ end
|
|
4832
5120
|
|
4833
5121
|
alias else_ else
|
4834
5122
|
alias ensure_ ensure
|
5123
|
+
alias receiver name
|
4835
5124
|
|
4836
5125
|
def image; "(class #{name})" end
|
4837
5126
|
|
@@ -4943,6 +5232,7 @@ end
|
|
4943
5232
|
exlist.extend ListInNode
|
4944
5233
|
super(exlist,rescuehdr.varname,action)
|
4945
5234
|
end
|
5235
|
+
alias name varname
|
4946
5236
|
|
4947
5237
|
def unparse o=default_unparse_options
|
4948
5238
|
xx=exceptions.map{|exc| exc.unparse o}.join(',')
|
@@ -5013,7 +5303,7 @@ end
|
|
5013
5303
|
def image; "(#{receiver.image}.[])" end
|
5014
5304
|
|
5015
5305
|
def unparse o=default_unparse_options
|
5016
|
-
[ receiver.unparse(o).sub(
|
5306
|
+
[ receiver.unparse(o).sub(/ \z/,''),
|
5017
5307
|
'[',
|
5018
5308
|
params&¶ms.map{|param| param.unparse o}.join(','),
|
5019
5309
|
']'
|
@@ -5029,7 +5319,7 @@ end
|
|
5029
5319
|
|
5030
5320
|
def parsetree_no_fcall o
|
5031
5321
|
params=params()
|
5032
|
-
output,star
|
5322
|
+
output,star=param_list_parse(params,o)
|
5033
5323
|
# receiver=receiver.parsetree(o)
|
5034
5324
|
result=[:call, receiver.rescue_parsetree(o), :[], output]
|
5035
5325
|
if params
|
@@ -5096,9 +5386,9 @@ end
|
|
5096
5386
|
module ErrorNode
|
5097
5387
|
def error?(x=nil) @error end
|
5098
5388
|
alias msg error?
|
5389
|
+
def blame; fail end
|
5099
5390
|
end
|
5100
5391
|
|
5101
|
-
|
5102
5392
|
class MisparsedNode<ValueNode
|
5103
5393
|
include ErrorNode
|
5104
5394
|
param_names :open,:middle,:close_
|
@@ -5116,8 +5406,9 @@ end
|
|
5116
5406
|
end
|
5117
5407
|
|
5118
5408
|
def error? x=nil
|
5409
|
+
@endline||=nil
|
5119
5410
|
inner=middle.grep(MisparsedNode).first and return inner.error?( x )
|
5120
|
-
"#@endline: misparsed #{what}: #{middle.map{|node| node&&node.
|
5411
|
+
"#@endline: misparsed #{what}: #{middle.map{|node| node&&(node.short_inspect rescue node.inspect)}.join}"
|
5121
5412
|
end
|
5122
5413
|
alias msg error?
|
5123
5414
|
end
|