redparse 0.8.2 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt CHANGED
@@ -1,3 +1,17 @@
1
+ === 0.8.3 / 2009-07-01
2
+ * 7 Minor Enhancements:
3
+ * most nodes now have startline, endline, and offset
4
+ * Node.[] is more fun to use now (most attributes can be left off)
5
+ * a SequenceNode inserted into a SequenceNode now gets inlined
6
+ * new ListInNode module for the various vanilla arrays found in node trees
7
+ * HashLiteralNode#get; retrieve values from hash literal kinda like from a hash
8
+ * Nodes can be catenated with the + operator now
9
+ * Symbols inserted into a tree are converted to CallSiteNodes
10
+
11
+ * 2 Bugfixes:
12
+ * more faithful ParseTree emulation in a couple of cases
13
+ * minor fixes in node processing for some rare conditions
14
+
1
15
  === 0.8.2 / 2009-04-21
2
16
  * 14 Minor Enhancements:
3
17
  * should be no tokens left in Node tree now
data/README.txt CHANGED
@@ -60,7 +60,7 @@ Please see COPYING.LGPL for details.
60
60
 
61
61
  == Drawbacks:
62
62
 
63
- * Pathetically, rediculously slow (ok, compiler-compilers are hard...)
63
+ * Pathetically, ridiculously slow (ok, compiler-compilers are hard...)
64
64
  * Error handling is very minimal right now.
65
65
  * No warnings at all.
66
66
  * Some expressions aren't parsed correctly. see below.
@@ -82,8 +82,8 @@ Please see COPYING.LGPL for details.
82
82
 
83
83
  tree.walk{|parent,i,subi,node|
84
84
  case node
85
- when CallNode: #... do something with method calls
86
- when AssignNode: #... maybe alter assignments somehow
85
+ when RedParse::CallNode: #... do something with method calls
86
+ when RedParse::AssignNode: #... maybe alter assignments somehow
87
87
  #.... and so on
88
88
  end
89
89
  }
@@ -203,13 +203,13 @@ existing format in the future, but no incompatibility-creating changes.
203
203
  ||+BlockParams #block formal parameter list
204
204
  |+CallSiteNode #abstract, method calls
205
205
  ||| (receiver: Expr|nil, name: String, params: nil|Array[Expr+,UnaryStarNode?,UnAmpNode?],
206
- ||| block_params: BlockParams, block: Expr)
206
+ ||| blockparams: BlockParams|nil, block: Expr|nil)
207
207
  ||+CallNode #normal method calls
208
208
  ||+KWCallNode #keywords that look (more or less) like methods (BEGIN END yield return break continue next)
209
209
  |+ArrayLiteralNode #[..]
210
210
  || (Array[Expr*])
211
211
  |+IfNode #if..end and unless..end
212
- || (if: Expr, then: Expr|nil, elsifs: Array[ElsifNode+]|Nil, else: Expr|nil)
212
+ || (if: Expr, then: Expr|nil, elsifs: Array[ElsifNode+]|nil, else: Expr|nil)
213
213
  |+LoopNode #while..end and until..end
214
214
  || (while: Expr, do: Expr:nil)
215
215
  |+CaseNode #case..end
data/Rakefile CHANGED
@@ -24,7 +24,6 @@ end
24
24
  _.url = ["http://github.com/coatl/redparse/", "http://rubyforge.org/projects/redparse/"]
25
25
  _.extra_deps << ['rubylexer', '>= 0.7.4']
26
26
  _.extra_deps << ['reg', '>= 0.4.7']
27
- _.extra_deps << 'Ron'
28
27
  # _.test_globs=["test/*"]
29
28
  _.description=desc
30
29
  _.summary=desc[/\A[^.]+\./]
data/bin/redparse CHANGED
@@ -95,9 +95,12 @@ while /^-/===ARGV.first
95
95
  when "--vsparsetree"; output=:vsparsetree
96
96
  when "--vsparsetree2"; output=:vsparsetree2
97
97
  when "--update-problemfiles"; problemfiles=ProblemFiles.new
98
+ when "--tokens"; ENV['PRINT_TOKENS']='1'
99
+ when "--rawtokens"; ENV['RAW_PRINT_TOKENS']='1'
100
+ when "--stack"; ENV['PRINT_STACK']='1'
98
101
  when "--unparse"; output=:unparse
99
102
  when "--compile", "-c"; compile=true
100
- when "--macros", "--macro", "-m":
103
+ when "--macros", "--macro", "-m";
101
104
  require 'rubygems'
102
105
  require 'macro'
103
106
  parserclass=Macro::RedParseWithMacros
data/lib/redparse.rb CHANGED
@@ -296,7 +296,7 @@ end
296
296
  #do something with error nodes
297
297
  msgs=[]
298
298
  result.walk{|parent,i,subi,node|
299
- not if node.respond_to? :error and node.error?(@rubyversion)
299
+ not if node.respond_to? :error? and node.error?(@rubyversion)
300
300
  msgs<< @filename+":"+node.blame.msg
301
301
  end
302
302
  } if result.respond_to? :walk #hack hack
data/lib/redparse/node.rb CHANGED
@@ -360,6 +360,18 @@ class RedParse
360
360
  attr :string
361
361
  end
362
362
 
363
+ module ListInNode
364
+ def []=(*args)
365
+ val=args.pop
366
+ #inline symbols as callnodes
367
+ case val
368
+ when Symbol
369
+ val=CallNode[nil,val.to_s]
370
+ end
371
+ super( *args<<val )
372
+ end
373
+ end
374
+
363
375
  class Node<Array
364
376
  include Stackable
365
377
  extend Stackable::Meta
@@ -369,6 +381,12 @@ class RedParse
369
381
  replace data
370
382
  end
371
383
 
384
+ def initialize_ivars
385
+ @offset||=0
386
+ @startline||=0
387
+ @endline||=0
388
+ end
389
+
372
390
  def flattened_ivars
373
391
  result=super
374
392
  result.each_with_index{|x,i|
@@ -383,6 +401,25 @@ class RedParse
383
401
  super and flattened_ivars_equal?(other)
384
402
  end
385
403
 
404
+ def +(other)
405
+ if SequenceNode===other
406
+ SequenceNode[self,*other]
407
+ else
408
+ SequenceNode[self,other]
409
+ end
410
+ end
411
+
412
+ alias original_brackets_assign []= #needed by LiteralNode
413
+ def []=(*args)
414
+ val=args.pop
415
+ #inline symbols as callnodes
416
+ case val
417
+ when Symbol
418
+ val=CallNode[nil,val.to_s]
419
+ end
420
+ super( *args<<val )
421
+ end
422
+
386
423
  def image; "(#{inspect})" end
387
424
 
388
425
  def error? x; false end
@@ -403,9 +440,19 @@ class RedParse
403
440
  end
404
441
  attr_accessor :endline
405
442
  attr_accessor :errors
443
+ attr_reader :offset
444
+
445
+ def self.inline_symbols data
446
+ data.map!{|datum|
447
+ Symbol===datum ?
448
+ CallNode[nil,datum.to_s,nil,nil,nil] :
449
+ datum
450
+ }
451
+ end
406
452
 
407
453
  def self.[](*data)
408
454
  options=data.pop if Hash===data.last
455
+ inline_symbols data
409
456
  result=allocate
410
457
  result.instance_eval{
411
458
  replace data
@@ -413,6 +460,7 @@ class RedParse
413
460
  instance_variable_set name,val
414
461
  } if options
415
462
  }
463
+ result.initialize_ivars
416
464
  return result
417
465
  end
418
466
 
@@ -433,7 +481,7 @@ class RedParse
433
481
  ivars[ivarname.to_sym]=instance_variable_get(ivarname)
434
482
  }
435
483
  q.group(1, self.class.name+'[', ']') {
436
- displaylist= ivars.empty? ? self : self+[ivars]
484
+ displaylist= ivars.empty? ? self : dup<<ivars
437
485
  q.seplist(displaylist) {|v|
438
486
  q.pp v
439
487
  }
@@ -905,8 +953,8 @@ class RedParse
905
953
 
906
954
  class VarNode<ValueNode
907
955
  include FlattenedIvars
908
- attr_accessor :endline
909
- attr_reader :lvar_type,:in_def,:offset
956
+ attr_accessor :endline,:offset
957
+ attr_reader :lvar_type,:in_def
910
958
  attr_writer :lvalue
911
959
 
912
960
 
@@ -916,7 +964,7 @@ class RedParse
916
964
  super(tok.ident)
917
965
  @lvar_type=tok.lvar_type
918
966
  @offset=tok.offset
919
- @endline=tok.endline
967
+ @endline=@startline=tok.endline
920
968
  @in_def=tok.in_def
921
969
  end
922
970
 
@@ -924,6 +972,8 @@ class RedParse
924
972
  def ident=x; self[0]=x end
925
973
  alias image ident
926
974
  alias startline endline
975
+ alias name ident
976
+ alias name= ident=
927
977
 
928
978
  def parsetree(o)
929
979
  type=case ident[0]
@@ -999,10 +1049,6 @@ class RedParse
999
1049
  def unparse o=default_unparse_options; ident end
1000
1050
  alias lhs_unparse unparse
1001
1051
 
1002
- # def delete_extraneous_ivars!
1003
- # remove_instance_variable :@lvalue
1004
- # super
1005
- # end
1006
1052
 
1007
1053
  if false
1008
1054
  def walk #is this needed?
@@ -1174,6 +1220,30 @@ end
1174
1220
  class VarLikeNode<ValueNode; end #nil,false,true,__FILE__,__LINE__,self
1175
1221
 
1176
1222
  class SequenceNode<ListOpNode
1223
+ def initialize(*args)
1224
+ super
1225
+ @offset=self.first.offset
1226
+ end
1227
+ def +(other)
1228
+ if SequenceNode===other
1229
+ dup.push( *other )
1230
+ else
1231
+ dup.push other
1232
+ end
1233
+ end
1234
+
1235
+ def []=(*args)
1236
+ val=args.pop
1237
+ if SequenceNode===val
1238
+ val=Array.new(val)
1239
+ #munge args too
1240
+ if args.size==1 and Integer===args.first
1241
+ args<<1
1242
+ end
1243
+ end
1244
+ super( *args<<val )
1245
+ end
1246
+
1177
1247
  def image; '(;)' end
1178
1248
  def to_lisp
1179
1249
  "#{map{|x| x.to_lisp}.join("\n")}"
@@ -1224,7 +1294,12 @@ end
1224
1294
  end
1225
1295
 
1226
1296
  def unparse o=default_unparse_options
1227
- map{|expr| unparse_nl(expr,o)+expr.unparse(o)}.to_s
1297
+ return "" if empty?
1298
+ unparse_nl(first,o,'')+first.unparse(o)+
1299
+ self[1..-1].map{|expr|
1300
+ # p expr
1301
+ unparse_nl(expr,o)+expr.unparse(o)
1302
+ }.to_s
1228
1303
  end
1229
1304
  end
1230
1305
 
@@ -1325,6 +1400,7 @@ end
1325
1400
  class UnOpNode<ValueNode
1326
1401
  param_names(:op,:val)
1327
1402
  def initialize(op,val)
1403
+ @offset=op.offset
1328
1404
  op=op.ident
1329
1405
  /([&*])$/===op and op=$1+"@"
1330
1406
  /^(?:!|not)$/===op and
@@ -1408,7 +1484,8 @@ end
1408
1484
  #param_names :op,:val
1409
1485
  def initialize(star)
1410
1486
  @offset= star.offset
1411
- replace ['*@',VarNode.new(VarNameToken.new('',offset))]
1487
+ replace ['*@',var=VarNode.new(VarNameToken.new('',offset))]
1488
+ var.startline=var.endline=star.startline
1412
1489
  end
1413
1490
  attr :offset
1414
1491
  def lvars_defined_in; [] end
@@ -1434,6 +1511,7 @@ end
1434
1511
 
1435
1512
  class ConstantNode<ListOpNode
1436
1513
  def initialize(*args)
1514
+ @offset=args.first.offset
1437
1515
  args.unshift nil if args.size==2
1438
1516
  args.map!{|node|
1439
1517
  if VarNode===node and (?A..?Z)===node.ident[0]
@@ -1669,6 +1747,7 @@ end
1669
1747
  class ParenedNode<ValueNode
1670
1748
  param_names :body #, :rescues, :else!, :ensure!
1671
1749
  def initialize(lparen,body,rparen)
1750
+ @offset=lparen.offset
1672
1751
  self[0]=body
1673
1752
  end
1674
1753
 
@@ -1723,8 +1802,9 @@ end
1723
1802
 
1724
1803
  rescues=rescues().map{|resc| resc.parsetree(o)}
1725
1804
  if rescues.empty?
1726
- else_ and
1727
- body=SequenceNode.new(body,nil,else_)
1805
+ if else_
1806
+ body= body ? SequenceNode.new(body,nil,else_) : else_
1807
+ end
1728
1808
  else_=nil
1729
1809
  else
1730
1810
  target.push newtarget=[:rescue, ]
@@ -1767,15 +1847,17 @@ end
1767
1847
  include HasRescue
1768
1848
  param_names :body, :rescues, :else!, :ensure!
1769
1849
  def initialize(*args)
1850
+ @offset=args.first.offset
1770
1851
  @empty_ensure=@empty_else=@op_rescue=nil
1771
- body,rescues,else_,ensure_=*args[1...-1]
1772
- if else_
1773
- else_=else_.val or @empty_else=true
1774
- end
1775
- if ensure_
1776
- ensure_=ensure_.val or @empty_ensure=true
1777
- end
1778
- replace [body,rescues,else_,ensure_]
1852
+ body,rescues,else_,ensure_=*args[1...-1]
1853
+ rescues.extend ListInNode
1854
+ if else_
1855
+ else_=else_.val or @empty_else=true
1856
+ end
1857
+ if ensure_
1858
+ ensure_=ensure_.val or @empty_ensure=true
1859
+ end
1860
+ replace [body,rescues,else_,ensure_]
1779
1861
  end
1780
1862
 
1781
1863
  def op?; false end
@@ -1793,7 +1875,7 @@ end
1793
1875
  def special_conditions!; nil end
1794
1876
 
1795
1877
  def non_empty
1796
- body.size+rescues.size > 0 or !!ensures
1878
+ rescues.size > 0 or !!ensures or body
1797
1879
  end
1798
1880
 
1799
1881
  identity_param :non_empty, false, true
@@ -1839,7 +1921,7 @@ end
1839
1921
  # include OpNode
1840
1922
  param_names :body, :rescues #, :else!, :ensure!
1841
1923
  def initialize(expr,rescueword,backup)
1842
- replace [expr,[RescueNode[[],nil,backup]]]
1924
+ replace [expr,[RescueNode[[],nil,backup]].extend(ListInNode)]
1843
1925
  end
1844
1926
 
1845
1927
  def else; nil end
@@ -1910,7 +1992,7 @@ end
1910
1992
  class AssignmentRhsNode < Node #not to appear in final parse tree
1911
1993
  param_names :open_, :val, :close_
1912
1994
  def initialize(*args)
1913
- if args.size==1: super args.first
1995
+ if args.size==1; super args.first
1914
1996
  else super args[1]
1915
1997
  end
1916
1998
  end
@@ -1970,6 +2052,11 @@ end
1970
2052
 
1971
2053
  op=op.ident
1972
2054
 
2055
+ if Array==rhs.class
2056
+ rhs.extend ListInNode
2057
+ end
2058
+
2059
+ @offset=lhs.offset
1973
2060
  return super(lhs,op,rhs)
1974
2061
  #punting, i hope the next layer can handle += and the like
1975
2062
 
@@ -2128,7 +2215,7 @@ end
2128
2215
  UnaryStarNode===right and rhs=[:svalue, rhs]
2129
2216
 
2130
2217
  # case left
2131
- # when VarNode:
2218
+ # when VarNode;
2132
2219
  [node_type, left.ident.to_sym, rhs]
2133
2220
  # else [node_type, left.data[0].parsetree(o), left.data[1].data[0].ident.+('=').to_sym ,[:array, rhs]]
2134
2221
  # end
@@ -2222,6 +2309,9 @@ end
2222
2309
  end
2223
2310
  }
2224
2311
  replace data
2312
+ @offset=self.first.offset
2313
+ @startline=self.first.startline
2314
+ @endline=self.last.endline
2225
2315
  end
2226
2316
 
2227
2317
  def unparse o=default_unparse_options
@@ -2329,7 +2419,7 @@ end
2329
2419
  @had_parens=true
2330
2420
  end
2331
2421
 
2332
- super(data)
2422
+ super(data) unless data.empty?
2333
2423
  end
2334
2424
 
2335
2425
  def unparse o=default_unparse_options
@@ -2606,6 +2696,7 @@ end
2606
2696
  arrowrange=first..last
2607
2697
  arrows=param_list[arrowrange]
2608
2698
  h=HashLiteralNode.new(nil,arrows,nil)
2699
+ h.offset=arrows.first.offset
2609
2700
  h.startline=arrows.first.startline
2610
2701
  h.endline=arrows.last.endline
2611
2702
  param_list[arrowrange]=[h]
@@ -2623,14 +2714,18 @@ end
2623
2714
  param_list=[param_list]
2624
2715
  end
2625
2716
 
2717
+ param_list.extend ListInNode if param_list
2718
+
2626
2719
  if block
2627
2720
  @do_end=block.do_end
2628
2721
  blockparams=block.params
2629
- block=SequenceNode[*block.body] #||[]
2722
+ block=block.body #||[]
2630
2723
  end
2631
2724
  @offset=method.offset
2632
- method=method.ident
2633
- fail unless String===method
2725
+ if Token===method
2726
+ method=method.ident
2727
+ fail unless String===method
2728
+ end
2634
2729
  super(nil,method,param_list,blockparams,block)
2635
2730
  #receiver, if any, is tacked on later
2636
2731
  end
@@ -2860,7 +2955,6 @@ end
2860
2955
 
2861
2956
  class CallNode<CallSiteNode #normal method calls
2862
2957
  def initialize(method,open_paren,param_list,close_paren,block)
2863
- MethNameToken===method or fail
2864
2958
  super
2865
2959
  end
2866
2960
  end
@@ -2895,11 +2989,7 @@ end
2895
2989
  class BlockNode<ValueNode #not to appear in final parse tree
2896
2990
  param_names :params,:body
2897
2991
  def initialize(open_brace,formals,stmts,close_brace)
2898
- case stmts
2899
- when SequenceNode; stmts=Array.new(stmts)
2900
- when nil; stmts=[]
2901
- else stmts=[stmts]
2902
- end
2992
+ stmts||=SequenceNode[{:@offset => open_brace.offset, :@startline=>open_brace.startline}]
2903
2993
 
2904
2994
  formals&&=BlockParams.new(Array.new(formals))
2905
2995
  @do_end=true unless open_brace.not_real?
@@ -2935,6 +3025,7 @@ end
2935
3025
 
2936
3026
  class NopNode<ValueNode
2937
3027
  def initialize(*args)
3028
+ @startline=@endline=1
2938
3029
  super()
2939
3030
  end
2940
3031
 
@@ -2994,6 +3085,7 @@ end
2994
3085
 
2995
3086
  @open=token.open
2996
3087
  @close=token.close
3088
+ @offset=token.offset
2997
3089
  @bs_handler=str.bs_handler
2998
3090
 
2999
3091
  if /[\[{]/===@char
@@ -3019,6 +3111,16 @@ end
3019
3111
  =end
3020
3112
  end
3021
3113
 
3114
+ def initialize_ivars
3115
+ @char||='"'
3116
+ @open||='"'
3117
+ @close||='"'
3118
+ @bs_handler||=:dquote_esc_seq
3119
+ if /[\[{]/===@char
3120
+ @parses_like||=split_into_words(str)
3121
+ end
3122
+ end
3123
+
3022
3124
  def translate_escapes(str)
3023
3125
  rl=RubyLexer.new("(string escape translation hack...)",'')
3024
3126
  result=str.dup
@@ -3101,13 +3203,8 @@ end
3101
3203
 
3102
3204
  def image; '(#@char)' end
3103
3205
 
3104
- def delete_extraneous_ivars!
3105
- @parses_like.delete_extraneous_ivars! if defined? @parses_like
3106
- return super
3107
- end
3108
-
3109
3206
  def walk(*args,&callback)
3110
- return @parses_like.walk(*args,&callback) if defined? @parses_like
3207
+ @parses_like.walk(*args,&callback) if defined? @parses_like
3111
3208
  super
3112
3209
  end
3113
3210
 
@@ -3152,7 +3249,8 @@ end
3152
3249
 
3153
3250
  if tokens.size==1 and VarNameToken===tokens.first
3154
3251
  data[i]=VarNode.new tokens.first
3155
- data[i].endline=token.endline
3252
+ data[i].startline=data[i].endline=token.endline
3253
+ data[i].offset=tokens.first.offset
3156
3254
  else
3157
3255
  #parse the token list in the string inclusion
3158
3256
  parser=Thread.current[:$RedParse_parser]
@@ -3211,6 +3309,7 @@ end
3211
3309
  ]omx
3212
3310
  SQ_ODD=/#{SQ_EVEN}#{SQ_ESC}/omx
3213
3311
  def split_into_words strtok
3312
+ @offset=strtok.offset
3214
3313
  return unless /[{\[]/===@char
3215
3314
  result=ArrayLiteralNode[]
3216
3315
  result << StringNode['',{:@char=>'"',:@open=>@open,:@close=>@close,:@bs_handler=>@bs_handler}]
@@ -3343,14 +3442,14 @@ end
3343
3442
  each{|elem|
3344
3443
  case elem
3345
3444
  when String
3445
+ was_esc_nl= (elem=="\\\n") #ick
3346
3446
  elem=translate_escapes elem
3347
3447
  if saw_string
3348
- result=[:str, elem]
3448
+ vals.push [:str, elem] if !elem.empty? or was_esc_nl
3349
3449
  else
3350
3450
  saw_string=true
3351
- result=elem
3451
+ vals.push elem
3352
3452
  end
3353
- vals.push result
3354
3453
  when NopNode
3355
3454
  vals.push [:evstr]
3356
3455
  when Node #,VarNameToken
@@ -3384,7 +3483,7 @@ end
3384
3483
  charset=set
3385
3484
  end
3386
3485
  }
3387
- vals.push numopts|charset unless numopts|charset==0
3486
+ regex_options= numopts|charset unless numopts|charset==0
3388
3487
  val=/#{val}/
3389
3488
  type
3390
3489
  when '{'
@@ -3432,6 +3531,7 @@ end
3432
3531
  type=DOWNSHIFT_STRING_TYPE[type]
3433
3532
  end
3434
3533
  result= vals.unshift(type)
3534
+ result.push regex_options if regex_options
3435
3535
  end
3436
3536
  result=[:match, result] if defined? @implicit_match and @implicit_match
3437
3537
  return result
@@ -3520,6 +3620,15 @@ end
3520
3620
  super(val)
3521
3621
  end
3522
3622
 
3623
+ def self.inline_symbols data
3624
+ #don't mangle symbols when constructing node like: LiteralNode[:foo]
3625
+ data
3626
+ end
3627
+
3628
+ def []=(*args)
3629
+ original_brackets_assign( *args )
3630
+ end
3631
+
3523
3632
  def bare_method
3524
3633
  Symbol===val || StringNode===val
3525
3634
  end
@@ -3587,6 +3696,7 @@ end
3587
3696
  class VarLikeNode<ValueNode #nil,false,true,__FILE__,__LINE__,self
3588
3697
  param_names :name
3589
3698
  def initialize(name,*more)
3699
+ @offset=name.offset
3590
3700
  if name.ident=='('
3591
3701
  #simulate nil
3592
3702
  replace ['nil']
@@ -3626,6 +3736,7 @@ end
3626
3736
 
3627
3737
  class ArrayLiteralNode<ValueNode
3628
3738
  def initialize(lbrack,contents,rbrack)
3739
+ @offset=lbrack.offset
3629
3740
  contents or return super()
3630
3741
  if CommaOpNode===contents
3631
3742
  super( *contents )
@@ -3683,10 +3794,12 @@ end
3683
3794
  class IfNode < ValueNode
3684
3795
  param_names :condition,:consequent,:elsifs,:otherwise
3685
3796
  def initialize(iftok,condition,thentok,consequent,elsifs,else_,endtok)
3797
+ @offset=iftok.offset
3686
3798
  if else_
3687
3799
  else_=else_.val or @empty_else=true
3688
3800
  end
3689
3801
  condition.special_conditions! if condition.respond_to? :special_conditions!
3802
+ elsifs.extend ListInNode if elsifs
3690
3803
  super(condition,consequent,elsifs,else_)
3691
3804
  @reverse= iftok.ident=="unless"
3692
3805
  if @reverse
@@ -3789,6 +3902,7 @@ end
3789
3902
  class ElsifNode<Node
3790
3903
  param_names(:elsifword_,:condition,:thenword_,:consequent)
3791
3904
  def initialize(elsifword,condition,thenword,consequent)
3905
+ @offset=elsifword.offset
3792
3906
  condition.special_conditions! if condition.respond_to? :special_conditions!
3793
3907
  super(condition,consequent)
3794
3908
  end
@@ -3816,6 +3930,7 @@ end
3816
3930
  #this class should be abstract and have 2 concrete descendants for while and until
3817
3931
  param_names :condition, :body
3818
3932
  def initialize(loopword,condition,thenword,body,endtok)
3933
+ @offset=loopword.offset
3819
3934
  condition.special_conditions! if condition.respond_to? :special_conditions!
3820
3935
  super(condition,body)
3821
3936
  @reverse= loopword.ident=="until"
@@ -3865,9 +3980,11 @@ end
3865
3980
  alias otherwise else
3866
3981
 
3867
3982
  def initialize(caseword, condition, semi, whens, otherwise, endword)
3983
+ @offset=caseword.offset
3868
3984
  if otherwise
3869
3985
  otherwise=otherwise.val or @empty_else=true
3870
3986
  end
3987
+ whens.extend ListInNode
3871
3988
  super(condition,whens,otherwise)
3872
3989
  end
3873
3990
 
@@ -3893,16 +4010,24 @@ end
3893
4010
  end
3894
4011
 
3895
4012
  def parsetree(o)
3896
- [:case, condition&&condition.parsetree(o)]+
3897
- whens.map{|whennode| whennode.parsetree(o)}+
3898
- [otherwise&&otherwise.parsetree(o)]
4013
+ result=[:case, condition&&condition.parsetree(o)]+
4014
+ whens.map{|whennode| whennode.parsetree(o)}
4015
+ other=otherwise&&otherwise.parsetree(o)
4016
+ if other and other[0..1]==[:case, nil] and !condition
4017
+ result.concat other[2..-1]
4018
+ else
4019
+ result<<other
4020
+ end
4021
+ return result
3899
4022
  end
3900
4023
  end
3901
4024
 
3902
4025
  class WhenNode<Node #not to appear in final tree?
3903
4026
  param_names(:whenword_,:when!,:thenword_,:then!)
3904
4027
  def initialize(whenword,when_,thenword,then_)
4028
+ @offset=whenword.offset
3905
4029
  when_=Array.new(when_) if CommaOpNode===when_
4030
+ when_.extend ListInNode if when_.class==Array
3906
4031
  super(when_,then_)
3907
4032
  end
3908
4033
  alias body then
@@ -3952,6 +4077,7 @@ end
3952
4077
  class ForNode<ValueNode
3953
4078
  param_names(:forword_,:for!,:inword_,:in!,:doword_,:do!,:endword_)
3954
4079
  def initialize(forword,for_,inword,in_,doword,do_,endword)
4080
+ @offset=forword.offset
3955
4081
  #elide 1 layer of parens if present
3956
4082
  for_=for_.first if ParenedNode===for_
3957
4083
  for_=CommaOpNode===for_ ? Array.new(for_) : [for_]
@@ -4007,6 +4133,7 @@ end
4007
4133
 
4008
4134
  class HashLiteralNode<ValueNode
4009
4135
  def initialize(open,contents,close)
4136
+ @offset=open.offset rescue contents.first.offset
4010
4137
  case contents
4011
4138
  when nil; super()
4012
4139
  when ArrowOpNode; super(contents.first,contents.last)
@@ -4027,6 +4154,7 @@ end
4027
4154
  end
4028
4155
 
4029
4156
  attr :no_arrows
4157
+ attr_writer :offset
4030
4158
 
4031
4159
  def image; "({})" end
4032
4160
 
@@ -4044,12 +4172,36 @@ end
4044
4172
  return result
4045
4173
  end
4046
4174
 
4175
+ def get k
4176
+ case k
4177
+ when Node;
4178
+ k.delete_extraneous_ivars!
4179
+ k.delete_linenums!
4180
+ when Symbol, Numeric; k=LiteralNode[k]
4181
+ when true,false,nil; k=VarLikeNode[k.inspect]
4182
+ else raise ArgumentError
4183
+ end
4184
+ return as_h[k]
4185
+ end
4186
+
4187
+ def as_h
4188
+ return @h if defined? @h
4189
+ @h={}
4190
+ (0...size).step(2){|i|
4191
+ k=self[i].dup
4192
+ k.delete_extraneous_ivars!
4193
+ k.delete_linenums!
4194
+ @h[k]=self[i+1]
4195
+ }
4196
+ return @h
4197
+ end
4198
+
4047
4199
  def parsetree(o)
4048
4200
  map{|elem| elem.rescue_parsetree(o)}.unshift :hash
4049
4201
  end
4050
4202
 
4051
4203
  def error? rubyversion=1.8
4052
- return true if @no_arrows and rubyversion>=1.9
4204
+ return true if defined?(@no_arrows) and rubyversion>=1.9
4053
4205
  return super
4054
4206
  end
4055
4207
  end
@@ -4062,6 +4214,7 @@ end
4062
4214
  def initialize(if_,qm,then_,colon,else_)
4063
4215
  super(if_,then_,else_)
4064
4216
  condition.special_conditions! if condition.respond_to? :special_conditions!
4217
+ @offset=self.first.offset
4065
4218
  end
4066
4219
 
4067
4220
  def image; "(?:)" end
@@ -4088,8 +4241,9 @@ end
4088
4241
  alias else elses
4089
4242
  alias params args
4090
4243
 
4091
- def initialize(defword_,header,maybe_eq_,semi_,
4244
+ def initialize(defword,header,maybe_eq_,semi_,
4092
4245
  body,rescues,else_,ensure_,endword_)
4246
+ @offset=defword.offset
4093
4247
  @empty_else=@empty_ensure=nil
4094
4248
  # if DotCallNode===header
4095
4249
  # header=header.data[1]
@@ -4111,6 +4265,8 @@ end
4111
4265
  if ensure_
4112
4266
  ensure_=ensure_.val or @empty_ensure=true
4113
4267
  end
4268
+ args.extend ListInNode if args
4269
+ rescues.extend ListInNode if rescues
4114
4270
  replace [receiver,header,args,body,rescues,else_,ensure_]
4115
4271
  end
4116
4272
 
@@ -4194,11 +4350,11 @@ end
4194
4350
  case arg
4195
4351
  when VarNode
4196
4352
  args.push arg.ident.to_sym
4197
- when UnaryStarNode:
4353
+ when UnaryStarNode
4198
4354
  args.push "*#{arg.val.ident}".to_sym
4199
- when UnOpNode:
4355
+ when UnOpNode
4200
4356
  nil
4201
- when AssignNode:
4357
+ when AssignNode
4202
4358
  initvals << arg.parsetree(o)
4203
4359
  initvals[-1][-1]=arg.right.rescue_parsetree(o) #ugly
4204
4360
  args.push arg[0].ident.to_sym
@@ -4301,6 +4457,7 @@ end
4301
4457
  include BareSymbolUtils
4302
4458
  param_names(:aliasword_,:to,:from)
4303
4459
  def initialize(aliasword,to,from)
4460
+ @offset=aliasword.offset
4304
4461
  to=baresym2str(to)
4305
4462
  from=baresym2str(from)
4306
4463
  super(to,from)
@@ -4323,6 +4480,7 @@ end
4323
4480
  class UndefNode < ValueNode
4324
4481
  include BareSymbolUtils
4325
4482
  def initialize(first,middle,last=nil)
4483
+ @offset=first.offset
4326
4484
  if last
4327
4485
  node,newsym=first,last
4328
4486
  super(*node << baresym2str(newsym))
@@ -4359,8 +4517,10 @@ end
4359
4517
  param_names(:name,:body,:rescues,:else!,:ensure!)
4360
4518
 
4361
4519
  def initialize moduleword,name,semiword,body,rescues,else_,ensure_,endword
4520
+ @offset=moduleword.offset
4362
4521
  else_=else_.val if else_
4363
4522
  ensure_=ensure_.val if ensure_
4523
+ rescues.extend ListInNode if rescues
4364
4524
  super(name,body,rescues,else_,ensure_)
4365
4525
  end
4366
4526
 
@@ -4402,12 +4562,14 @@ end
4402
4562
  class ClassNode<NamespaceNode
4403
4563
  param_names(:name,:parent,:body,:rescues,:else!,:ensure!)
4404
4564
  def initialize(classword,name,semi,body,rescues, else_, ensure_, endword)
4565
+ @offset=classword.offset
4405
4566
  if OpNode===name
4406
4567
  name,op,parent=*name
4407
4568
  op=="<" or fail "invalid superclass expression: #{name}"
4408
4569
  end
4409
4570
  else_=else_.val if else_
4410
4571
  ensure_=ensure_.val if ensure_
4572
+ rescues.extend ListInNode if rescues
4411
4573
  super(name,parent,body,rescues,else_,ensure_)
4412
4574
  end
4413
4575
 
@@ -4450,8 +4612,10 @@ end
4450
4612
  class MetaClassNode<NamespaceNode
4451
4613
  param_names :val, :body, :rescues,:else!,:ensure!
4452
4614
  def initialize classword, leftleftword, val, semiword, body, rescues,else_,ensure_, endword
4615
+ @offset=classword.offset
4453
4616
  else_=else_.val if else_
4454
4617
  ensure_=ensure_.val if ensure_
4618
+ rescues.extend ListInNode if rescues
4455
4619
  super(val,body,rescues,else_,ensure_)
4456
4620
  end
4457
4621
 
@@ -4480,15 +4644,16 @@ end
4480
4644
  class RescueHeaderNode<Node #not to appear in final tree
4481
4645
  param_names :exceptions,:varname
4482
4646
  def initialize(rescueword,arrowword,exceptions,thenword)
4647
+ @offset=rescueword.offset
4483
4648
  case exceptions
4484
4649
  when nil
4485
- when VarNode:
4650
+ when VarNode
4486
4651
  if arrowword
4487
4652
  exvarname=exceptions
4488
4653
  exceptions=nil
4489
4654
  arrowword=nil
4490
4655
  end
4491
- when ArrowOpNode:
4656
+ when ArrowOpNode
4492
4657
  exvarname=exceptions.last
4493
4658
  exceptions=exceptions.first
4494
4659
  when CommaOpNode
@@ -4510,9 +4675,11 @@ end
4510
4675
  class RescueNode<Node
4511
4676
  param_names :exceptions,:varname,:action
4512
4677
  def initialize(rescuehdr,action,semi)
4678
+ @offset=rescuehdr.offset
4513
4679
  exlist=rescuehdr.exceptions||[]
4514
4680
  exlist=[exlist] unless exlist.class==Array
4515
4681
  fail unless exlist.class==Array
4682
+ exlist.extend ListInNode
4516
4683
  super(exlist,rescuehdr.varname,action)
4517
4684
  end
4518
4685
 
@@ -4564,6 +4731,8 @@ end
4564
4731
  when nil
4565
4732
  else [params]
4566
4733
  end
4734
+ params.extend ListInNode if params
4735
+ @offset=receiver.offset
4567
4736
  super(receiver,params)
4568
4737
  end
4569
4738
 
@@ -1,3 +1,3 @@
1
1
  class RedParse
2
- VERSION='0.8.2'
2
+ VERSION='0.8.3'
3
3
  end
@@ -89,6 +89,7 @@ class Test::Unit::TestCase
89
89
  end
90
90
  end
91
91
 
92
+ #print output immediately on failing test (at end too....)
92
93
  require 'test/unit/ui/console/testrunner'
93
94
  class Test::Unit::UI::Console::TestRunner
94
95
  alias add_fault__no_immed_output add_fault
@@ -99,6 +100,55 @@ class Test::Unit::UI::Console::TestRunner
99
100
  end
100
101
  end
101
102
 
103
+ =begin nice idea, don't work yet
104
+ class Test::Unit::TestResult
105
+ @@FAILING_CASES=[]
106
+
107
+ begin
108
+ huh #but this is running at the wrong time...
109
+ huh #need to run before tests are run but after defined
110
+ eval Marshal.load(huh).map{|name,case|
111
+ name=huh quote name
112
+ "
113
+ class #{case}
114
+ alias_method :'first_off_#{name}', :'#{name}'
115
+ undef_method :'#{name}'
116
+ end
117
+ "
118
+ }.to_s
119
+
120
+ in_a_loop{
121
+ huh #ensure methods named first_off_test* get run first
122
+ some_test_case._method=name
123
+ some_test_case.run(huh result){huh}
124
+ }
125
+
126
+ rescue Exception
127
+ #ignore it
128
+ end
129
+
130
+ alias add_error__no_error_memory add_error
131
+ def add_error x
132
+ name=x.test_name
133
+ i=name.rindex('(')
134
+ @@FAILING_CASES.push [name[0...i],name[i..-1]]
135
+
136
+ add_error__no_error_memory x
137
+ end
138
+
139
+ alias add_failure__no_error_memory add_failure
140
+ def add_failure x
141
+ name=x.test_name
142
+ i=name.rindex('(')
143
+ @@FAILING_CASES.push [name[0...i],name[i..-1]]
144
+
145
+ add_failure__no_error_memory x
146
+ end
147
+
148
+ at_exit {huh @@FAILING_CASES}
149
+ end
150
+ =end
151
+
102
152
  class ParseTree
103
153
  def put o
104
154
  o=Marshal.dump o
@@ -196,6 +246,16 @@ class RedParseTest<Test::Unit::TestCase
196
246
  FAILURE_EXAMPLES=[
197
247
  ]
198
248
  RUBYBUG_EXAMPLES=[
249
+ ' case
250
+ when 0
251
+ guecoding
252
+ else case
253
+ when eucjp_match_length
254
+ guing
255
+ end
256
+ end',
257
+
258
+ 'case; when false; else case; when nil; else 5; end; end',
199
259
  'def foo(a=b=c={}) end',
200
260
  "$11111111111111111111111111111111111111111111111111111111111111111111",
201
261
  "c do p (110).m end",
@@ -211,6 +271,23 @@ class RedParseTest<Test::Unit::TestCase
211
271
  ]
212
272
 
213
273
  ONELINERS=[
274
+ 'p (a,b=c,d); a +h'...'',
275
+ 'x{return (a,b=c,d)}'...'',
276
+ 'x{r (a,b=c,d)}'...'',
277
+ 'x{return (a,b=c,d)|1}'...'',
278
+ 'x{r (a,b=c,d)|1}'...'',
279
+ 'case; when false; else case; when nil; else 5; end; end'...'',
280
+ 'case;else case; else; end;end'...'',
281
+ 'case; else; end'...'',
282
+ 'c while d and 2.a?(b)..8'...'',
283
+ 'c while d and 888888888888888888888888888888888888888888888888888888..2.a?(b)'...'',
284
+ 'c while d and 8.8..2.a?(b)'...'',
285
+ 'c while d and 8..2.a?(b)'...'',
286
+ 'c while d and :a8..2.a?(b)'...'',
287
+ 'c while d and /8/..2.a?(b)'...'',
288
+ 'c while d and /8/../2.a?(b)/'...'',
289
+ 'c while d and 8../2.a?(b)/'...'',
290
+ 'c while d and a8../2.a?(b)/'...'',
214
291
  'z = valueo_s rescue "?"'...'',
215
292
  '"#{publi}#{}>"'...'',
216
293
  'return (@images = @old_imgs)'...'',
@@ -2742,6 +2819,24 @@ class RedParseTest<Test::Unit::TestCase
2742
2819
  END
2743
2820
 
2744
2821
  STANZAS=PASSTHRU_BSLASHES_ENTIRE+%q[
2822
+ module
2823
+ =begin =end
2824
+ =end
2825
+ A; end
2826
+
2827
+ module A
2828
+ =begin =end
2829
+ =end
2830
+ ::B; end
2831
+
2832
+ module A::
2833
+ =begin =end
2834
+ =end
2835
+ B; end
2836
+
2837
+ =begin =end
2838
+ =end
2839
+
2745
2840
  return @senders[1] =
2746
2841
  2
2747
2842
 
@@ -3747,7 +3842,7 @@ EOS
3747
3842
  end
3748
3843
  end
3749
3844
 
3750
- BEGIN{p Dir.getwd; File.unlink "problemexprs" rescue nil}
3845
+ BEGIN{File.unlink "problemexprs" rescue nil}
3751
3846
  def problem_exprs
3752
3847
  @problem_exprs||=nil
3753
3848
  return @problem_exprs if @problem_exprs
@@ -3832,9 +3927,6 @@ EOS
3832
3927
 
3833
3928
  end #until output.equal? tree
3834
3929
 
3835
- # puts "warning: unparser tests disabled for now"
3836
- # return #skip unparse tests for now
3837
-
3838
3930
  return unless nodes
3839
3931
  begin
3840
3932
  unparsed=nodes.unparse
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redparse
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Caleb Clausen
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin/
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-22 00:00:00 -07:00
12
+ date: 2009-07-06 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,16 +32,6 @@ dependencies:
32
32
  - !ruby/object:Gem::Version
33
33
  version: 0.4.7
34
34
  version:
35
- - !ruby/object:Gem::Dependency
36
- name: Ron
37
- type: :runtime
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- version: "0"
44
- version:
45
35
  - !ruby/object:Gem::Dependency
46
36
  name: hoe
47
37
  type: :development