redparse 0.8.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -0
  2. data/COPYING.LGPL +503 -158
  3. data/History.txt +192 -0
  4. data/Makefile +9 -0
  5. data/README.txt +72 -39
  6. data/bin/redparse +108 -14
  7. data/lib/miniredparse.rb +1543 -0
  8. data/lib/redparse.rb +971 -105
  9. data/lib/redparse/ReduceWithsFor_RedParse_1_8.rb +17412 -0
  10. data/lib/redparse/ReduceWithsFor_RedParse_1_9.rb +17633 -0
  11. data/lib/redparse/babynodes.rb +17 -0
  12. data/lib/redparse/babyparser.rb +17 -0
  13. data/lib/redparse/cache.rb +290 -6
  14. data/lib/redparse/compile.rb +6 -97
  15. data/lib/redparse/decisiontree.rb +1 -1
  16. data/lib/redparse/float_accurate_to_s.rb +30 -6
  17. data/lib/redparse/generate.rb +18 -0
  18. data/lib/redparse/node.rb +415 -124
  19. data/lib/redparse/parse_tree_server.rb +20 -2
  20. data/lib/redparse/problemfiles.rb +1 -1
  21. data/lib/redparse/pthelper.rb +17 -31
  22. data/lib/redparse/reg_more_sugar.rb +1 -1
  23. data/lib/redparse/replacing/parse_tree.rb +30 -0
  24. data/lib/redparse/replacing/ripper.rb +20 -0
  25. data/lib/redparse/replacing/ruby_parser.rb +28 -0
  26. data/lib/redparse/ripper.rb +393 -0
  27. data/lib/redparse/ripper_sexp.rb +153 -0
  28. data/lib/redparse/stackableclasses.rb +113 -0
  29. data/lib/redparse/version.rb +18 -1
  30. data/redparse.gemspec +29 -9
  31. data/rplt.txt +31 -0
  32. data/test/data/hd_with_blank_string.rb +3 -0
  33. data/test/data/pt_known_output.rb +13273 -0
  34. data/test/data/wp.pp +0 -0
  35. data/test/generate_parse_tree_server_rc.rb +17 -0
  36. data/test/rp-locatetest.rb +2 -2
  37. data/test/test_1.9.rb +338 -35
  38. data/test/test_all.rb +22 -3
  39. data/test/test_part.rb +32 -0
  40. data/test/test_redparse.rb +396 -74
  41. data/test/test_xform_tree.rb +18 -0
  42. data/test/unparse_1.9_exceptions.txt +85 -0
  43. data/test/unparse_1.9_exceptions.txt.old +81 -0
  44. metadata +71 -46
  45. 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 "0.0e0" if zero?
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)\.(\d+)e(.*)$/)
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
@@ -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
@@ -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
- @startline||=endline
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 lvalue
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 inspect label=nil,indent=0
460
- ivarnames=instance_variables-FlattenedIvars::EXCLUDED_IVARS
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
- pos=@startline.to_s
474
- pos<<"..#@endline" if @endline!=@startline
475
- pos<<"@#@offset"
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," pos=",pos," ",ivars,"\n"]
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,"#{name}:\n",*val.map{|v|
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,amp
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= Integer===token ? token : token.startline rescue (return alt)
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(left,op,right=nil)
1275
- op,right=nil,op if right.nil?
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
- super(left,op,right)
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
- super
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&-{:size=>1,:char=>/^[^`\[{]$/}
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
- LITNODE=LiteralNode|NopNode|LITSTR|LITCAT|LITRANGE|(VarLikeNode&-{:name=>/^__/})
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(left,op,right=nil)
1586
- op,right="..",op unless right
1587
- op=op.ident if op.respond_to? :ident
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 initialize(op,val)
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
- super(op,val)
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 /#{LETTER}/o===op or /^[+-]/===op && LiteralNode===val
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(op,val=nil)
1710
- op,val="*@",op unless val
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
- super(op,val)
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
- result+=map{|name| name.inspect}.join(', ')+"\n"
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
- body.parsetree(o)
2057
+ body ? body.parsetree(o) : [:nil]
1907
2058
  end
1908
2059
 
1909
2060
  def rescue_parsetree o
1910
- body.rescue_parsetree o
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
- "("+(body&&body.unparse(o))+")"
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
- lhs,op,bogus1,rhs,bogus2=*args
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,op,bogus1,rhs,bogus2=*args
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
- def initialize(method,open_paren,param_list,close_paren,block)
2890
- @not_real_parens=!open_paren || open_paren.not_real?
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=block.params
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)+'.',name,
3157
+ receiver&&receiver.unparse(o)+'.',
3158
+ name=='()' ? '' : name,
2937
3159
  real_parens ? '(' : (' ' if params),
2938
- params&&params.map{|param| unparse_nl(param,o,'',"\\\n")+param.unparse(o) }.join(', '),
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
- result="(#{receiver.image if receiver}.#{name})"
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(method,open_paren,param_list,close_paren,block)
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,open_paren,param_list,close_paren,block)
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 NopNode<ValueNode
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 open[-1,1]+close}#{maybe_crunch}]/
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
- if String===substr
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
- \A |
3758
+ \G |
3500
3759
  [^\\c-] |
3501
- (?>\A|[^\\])c |
3502
- (?> [^CM] | (?>\A|[^\\])[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
- (?: \A | [^\\] ) #not esc
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 initialize(old_val)
3820
- @offset=old_val.offset
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-?0([^.]|\Z)/; val=val.oct
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
- super(val)
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
- s= val.accurate_to_s
3885
- #why must it be *2? I wouldn't think any fudge factor would be necessary
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
- fail unless [s.to_f].pack("d")==[val].pack("d")
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 initialize(name,*more)
3930
- @offset=name.offset
3931
- if name.ident=='('
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
- replace [name.ident]
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.unparse(o)}.join(', ')+"]"
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,amp=param_list_parse(self,o)
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
- if else_
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=!open
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].unparse(o)+arrow+
4418
- self[i+1].unparse(o)+', '
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 && '('+args.map{|arg| arg.unparse o}.join(',')+')', unparse_nl(body||self,o)
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(/\s+\Z/,''),
5306
+ [ receiver.unparse(o).sub(/ \z/,''),
5017
5307
  '[',
5018
5308
  params&&params.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,amp=param_list_parse(params,o)
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.image}.join(' ')}"
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