redparse 0.8.4 → 1.0.0
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.
- 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
|