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