rubymacros 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -0
  2. data/COPYING.LGPL +503 -158
  3. data/History.txt +115 -5
  4. data/Makefile +68 -0
  5. data/README.txt +29 -6
  6. data/TODO +1 -0
  7. data/bin/macroruby +69 -0
  8. data/example/__dir__.rb +18 -0
  9. data/example/__dir___wrap.rb +18 -0
  10. data/example/andand.rb +18 -0
  11. data/example/andand_wrap.rb +18 -0
  12. data/example/assert.rb +29 -8
  13. data/example/assert0.rb +11 -0
  14. data/example/assert0_wrap.rb +5 -0
  15. data/example/assert_does_nothing_when_disabled.rb +19 -0
  16. data/example/assert_wrap.rb +21 -0
  17. data/example/expected_output.txt +88 -0
  18. data/example/formless_macro.rb +123 -0
  19. data/example/formless_macro_wrap.rb +20 -0
  20. data/example/inline.rb +97 -0
  21. data/example/linenum.rb +19 -1
  22. data/example/linenum_user.rb +18 -0
  23. data/example/linenum_wrap.rb +18 -0
  24. data/example/loop.rb +18 -0
  25. data/example/loop_wrap.rb +18 -0
  26. data/example/meta.rb +25 -0
  27. data/example/meta_wrap.rb +20 -0
  28. data/example/nilresult.rb +26 -0
  29. data/example/nilresult_wrap.rb +21 -0
  30. data/example/pipeline.rb +37 -0
  31. data/example/rescuing.rb +33 -0
  32. data/example/rescuing_wrap.rb +21 -0
  33. data/example/role.rb +103 -0
  34. data/example/role_with_eval.rb +92 -0
  35. data/example/self_in_class.rb +27 -0
  36. data/example/separated_scope.rb +42 -0
  37. data/example/separated_scope_wrap.rb +20 -0
  38. data/example/simple.rb +18 -0
  39. data/example/simple_wrap.rb +18 -0
  40. data/example/unproc.rb +31 -0
  41. data/example/unproc_wrap.rb +21 -0
  42. data/example/unroll.rb +34 -0
  43. data/example/unroll_macros.rb +119 -0
  44. data/example/unroll_wrap.rb +22 -0
  45. data/example/with.rb +50 -7
  46. data/example/with_wrap.rb +19 -0
  47. data/lib/macro.rb +307 -72
  48. data/lib/macro/ReduceWithsFor_RedParse_RedParse__MacroMixin_RedParse__WithMacros_1_8.rb +18880 -0
  49. data/lib/macro/ReduceWithsFor_RedParse_RedParse__MacroMixin_RedParse__WithMacros_1_9.rb +19101 -0
  50. data/lib/macro/form.rb +136 -27
  51. data/lib/macro/node.rb +64 -0
  52. data/lib/macro/version.rb +2 -5
  53. data/lib/rubymacros.rb +19 -0
  54. data/lib/rubymacros/version.rb +23 -0
  55. data/lib/weakkeyhash.rb +18 -0
  56. data/rubymacros.gemspec +60 -0
  57. data/test/test_all.rb +27 -2
  58. data/test/test_examples.rb +91 -0
  59. data/test/test_expand.rb +56 -1
  60. data/test/test_form.rb +108 -10
  61. data/test/test_unroll.rb +120 -0
  62. metadata +93 -65
  63. data/Rakefile +0 -37
@@ -1,3 +1,22 @@
1
+ =begin
2
+ rubymacros - a macro preprocessor for ruby
3
+ Copyright (C) 2008, 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
  require 'macro'
20
+ require 'regxform'
2
21
  Macro.require 'example/with'
3
22
 
@@ -1,6 +1,6 @@
1
1
  =begin
2
2
  rubymacros - a macro preprocessor for ruby
3
- Copyright (C) 2008 Caleb Clausen
3
+ Copyright (C) 2008, 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
@@ -16,9 +16,12 @@
16
16
  along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  =end
18
18
 
19
- require 'rubygems'
19
+ begin require 'rubygems'
20
+ rescue Exception; #do nothing; hope we don't need it
21
+ end
20
22
  require 'redparse'
21
23
  require "macro/form"
24
+ require "macro/node"
22
25
  require "macro/version"
23
26
 
24
27
  class Object # :nodoc:
@@ -34,6 +37,7 @@ class Macro
34
37
  n=RedParse::const_get(k)
35
38
  self::const_set k,n if Module===n and RedParse::Node>=n
36
39
  }
40
+ ListInNode=RedParse::ListInNode #Node helper module
37
41
  #...and token classes from RubyLexer
38
42
  RubyLexer::constants.each{|k|
39
43
  t=RubyLexer::const_get(k)
@@ -66,9 +70,10 @@ class Macro
66
70
  [''].concat($:).each{|pre|
67
71
  pre+="/" unless %r{(\A|/)\Z}===pre
68
72
  if File.exist? finally=pre+filename
69
- code=File.open(finally){|fd| fd.read }
70
- #code="::Module.new do\n#{code}\nend\n" if wrap
71
- tree=Macro.expand(parse(code,filename),filename)
73
+ tree=File.open(finally){|code|
74
+ #code="::Module.new do\n#{code}\nend\n" if wrap
75
+ Macro.expand(parse(code,finally),filename)
76
+ }
72
77
 
73
78
  tree.load filename,wrap
74
79
  return true
@@ -77,6 +82,33 @@ class Macro
77
82
  raise LoadError, "no such file to load -- "+filename
78
83
  end
79
84
 
85
+ def Macro.delete(name,context=::Object)
86
+ Thread.current[:Macro_being_undefined]="macro_"+name
87
+ class<<context; remove_method(Thread.current[:Macro_being_undefined]); end
88
+ if context==::Object
89
+ Macro::GLOBALS.delete name.to_sym
90
+ end
91
+ Thread.current[:Macro_being_undefined]=nil
92
+ end
93
+
94
+ def Macro.list(*contexts)
95
+ contexts=[::Object] if contexts.empty?
96
+ contexts.map{|ctx| ctx.singleton_methods.grep(/\Amacro_/) }.flatten.map{|ctx| ctx.to_s.gsub!(/\Amacro_/,'') }
97
+ end
98
+
99
+ class ::Module
100
+ def macros
101
+ Macro.list(self)
102
+ end
103
+ end
104
+
105
+ def Macro.delete_all!(*contexts)
106
+ contexts=[::Object] if contexts.empty?
107
+ contexts.each{|ctx|
108
+ Macro.list(ctx).each{|mac| Macro.delete mac,ctx }
109
+ }
110
+ end
111
+
80
112
  #like Kernel#eval, but allows macros (and forms) as well.
81
113
  #beware: default for second argument is currently broken.
82
114
  #best practice is to pass an explicit binding (see
@@ -91,8 +123,9 @@ class Macro
91
123
  #binding should default to Binding.of_caller, but byellgch
92
124
 
93
125
  lvars=binding ? ::Kernel.eval("local_variables()",binding) : []
94
- tree=Macro.expand(parse(code,file,line,lvars),file)
95
- tree.eval binding||::Object.new_binding,file,line
126
+ code=Macro.parse(code,file,line,lvars) unless Node===code
127
+ tree=Macro.expand(code,file)
128
+ tree.eval binding,file,line
96
129
  end
97
130
 
98
131
  # A helper for Macro.eval which returns a RedParse tree for the given
@@ -113,7 +146,7 @@ class Macro
113
146
  if Binding===lvars
114
147
  lvars=eval "local_variables", lvars
115
148
  end
116
- RedParseWithMacros.new(code,file,line,lvars).parse
149
+ ::RedParse::WithMacros.new(code,file,line,lvars).parse
117
150
  end
118
151
 
119
152
  UNCOPYABLE= #Symbol|Numeric|true|false|nil|
@@ -126,12 +159,18 @@ class Macro
126
159
  def Macro.quote obj
127
160
  #result=
128
161
  case obj
129
- when Symbol,Numeric: LiteralNode[obj]
130
- when true,false,nil: VarLikeNode[obj.inspect]
131
- when String:
162
+ when Symbol,Numeric; LiteralNode[obj]
163
+ when true,false,nil; VarLikeNode[obj.inspect]
164
+ when String
132
165
  obj=obj.gsub(/['\\]/){|ch| '\\'+ch }
133
166
  StringNode[obj,{:@open=>"'", :@close=>"'"}]
134
167
 
168
+ when Reg::Formula
169
+ Reg::Deferred.defang! obj
170
+
171
+ when Reg::Reg
172
+ obj
173
+
135
174
  # TODO: The following is dead code and should be removed
136
175
  else
137
176
  #result=:(::Macro::QuotedStore[^QuotedStore.size])
@@ -154,12 +193,12 @@ class Macro
154
193
  return result if result
155
194
  result=
156
195
  case obj
157
- when Symbol,Numeric,true,false,nil: return obj
158
- when String: seen[obj.__id__]=obj.dup
159
- when Array:
196
+ when Symbol,Numeric,true,false,nil; return obj
197
+ when String; seen[obj.__id__]=obj.dup
198
+ when Array
160
199
  seen[obj.__id__]=dup=obj.dup
161
200
  dup.map!{|x| copy x,seen}
162
- when Hash:
201
+ when Hash
163
202
  result={}
164
203
  seen[obj.__id__]=result
165
204
  obj.each_pair{|k,v|
@@ -167,7 +206,7 @@ class Macro
167
206
  }
168
207
  result
169
208
  when Module,Proc,IO,Method,
170
- UnboundMethod,Thread,Continuation:
209
+ UnboundMethod,Thread,Continuation
171
210
  return obj
172
211
  else
173
212
  obj.dup
@@ -200,7 +239,7 @@ class Macro
200
239
  #
201
240
  def Macro.postpone node,session
202
241
  return node #disable postponement
203
-
242
+ =begin was
204
243
  filename=session[:filename]
205
244
  unless session[:@modpath_unsure]
206
245
  modpath=ConstantNode[nil,*session[:@modpath]]
@@ -226,6 +265,7 @@ class Macro
226
265
  HashLiteralNode[LiteralNode[:@expand_in_defs], VarLikeNode["true"]], Macro.quote(filename)],
227
266
  nil,nil]
228
267
  return CallNode[expanded,evalname,[Macro.quote( filename )],nil,nil]
268
+ =end
229
269
  end
230
270
 
231
271
  class Node
@@ -350,7 +390,10 @@ class Macro
350
390
  end
351
391
  session[:@modpath]||=[]
352
392
  session[:filename]||=filename
353
- String===tree and tree=parse(tree)
393
+ filename||="(eval)"
394
+ case tree
395
+ when String,IO; tree=parse(tree,filename)
396
+ end
354
397
  fail unless macros.__id__==Macro::GLOBALS.__id__ #for now
355
398
  tree.walk{|parent,i,subi,node|
356
399
  is_node=Node===node
@@ -369,7 +412,19 @@ class Macro
369
412
 
370
413
  if newnode
371
414
  return newnode unless parent #replacement at top level
372
- subi ? parent[i][subi]=newnode : parent[i]=newnode
415
+ if subi
416
+ target,index=parent[i],subi
417
+ else
418
+ target,index=parent,i
419
+ end
420
+ if JustNilNode===newnode and target.class==::Array ||
421
+ case target
422
+ when UndefNode,AssigneeList,SequenceNode; true
423
+ end
424
+ target.delete_at index
425
+ else
426
+ target[index]=newnode
427
+ end
373
428
  fail if recurse
374
429
  end
375
430
  else
@@ -387,7 +442,7 @@ class Macro
387
442
 
388
443
  #varargs, &args and receivers are not allowed in macro definitions (yet)
389
444
  fail "macro receivers not supported yet" if receiver
390
- if Node===args
445
+ if args
391
446
  last=args
392
447
  # else
393
448
  # last=args.last
@@ -398,8 +453,21 @@ class Macro
398
453
  #macros can't be settors
399
454
  fail "macro settors are not allowed" if /=$/===name
400
455
 
456
+ self.args||=[]
457
+ args.unshift VarNode.allocate.replace(["receiver"])
458
+ self.walk{|parent,i,subi,node| #replace self kw in body with receiver var instead
459
+ if VarLikeNode===node and node.ident=="self"
460
+ if subi
461
+ parent[i][subi]=VarNode.allocate.replace(["receiver"])
462
+ else
463
+ parent[i]=VarNode.allocate.replace(["receiver"])
464
+ end
465
+ end
466
+ true
467
+ }
468
+
401
469
  #macro definitions need to be dealt with in 2 steps: registration and activation
402
- name=self.name
470
+ # name=self.name
403
471
  self[1]="macro_"+name unless /^macro_/===name
404
472
  node=MethodNode[*self] #convert macro node to a method def node
405
473
  huh(node.receiver) if node.receiver
@@ -409,15 +477,15 @@ class Macro
409
477
  #disable postponement (delayed macros) ... i think they're not necessary
410
478
  expand=proc{|x| Node===x ? Macro.expand(x,macros,session) : x}
411
479
  node.receiver= expand[node.receiver]
412
- node.args.map! &expand if node.args
480
+ node.args.map!( &expand )if node.args
413
481
  node.body= expand[node.body]
414
- node.rescues.map! &expand if node.rescues
482
+ node.rescues.map!( &expand )if node.rescues
415
483
  node.ensure_= expand[node.ensure_]
416
484
  node.else_= expand[node.else_]
417
- node.eval
485
+ node.eval(nil,session[:filename])
418
486
  macros[name.to_sym]=::Object.method("macro_"+name)
419
487
  return node,false
420
-
488
+ =begin was
421
489
  #node.eval #no, not here....
422
490
 
423
491
  newnode=Macro.postpone node, session
@@ -441,6 +509,7 @@ class Macro
441
509
  #newnode=RedParse::VarLikeNode["nil", {:@value=>false,}]
442
510
  #subi ? parent[i][subi]=newnode : parent[i]=newnode
443
511
  return newnode,false #dont keep recursing
512
+ =end
444
513
  end
445
514
  end
446
515
 
@@ -478,12 +547,12 @@ class Macro
478
547
  #if this callsite names a macro, then it is a macro
479
548
  #macro=macros[name.to_sym]=::Object.method(macro) if String===macro
480
549
  #refuse macro calls with receivers, blocks, varargs, or &args: not supported yet
481
- fail "macro receivers not supported yet" if receiver
482
550
  fail "macro blocky args not supported yet" if UnOpNode===args.last and args.last.ident=="&@"
483
551
  fail "macro varargs calls not supported yet" if UnaryStarNode===args.last
484
552
  fail if args.class!=Array
553
+ args.unshift receiver||VarLikeNode.allocate.replace(["self"])
485
554
  if block
486
- newnode=macro.call *args do |*bparams|
555
+ newnode=macro.call( *args )do |*bparams|
487
556
  if !blockparams
488
557
  block
489
558
  else
@@ -494,28 +563,31 @@ class Macro
494
563
  end
495
564
  end
496
565
  else
497
- newnode=macro.call *args
566
+ newnode=macro.call( *args )
498
567
  end
499
568
  #subi ? parent[i][subi]=newnode : parent[i]=newnode
500
569
 
501
570
  # and keep recursing, no matter what, by all means!!
502
- newnode||=NopNode.new
503
- newnode=Macro.expand newnode,macros,session #just do it here
504
- newnode=OneLineParenedNode[newnode] #disable newlines in macro text
571
+ if newnode
572
+ newnode=Macro.expand newnode,macros,session #just do it here
573
+ newnode=OneLineParenedNode[newnode] #disable newlines in macro text
574
+ else
575
+ newnode=JustNilNode.new
576
+ end
505
577
  return newnode,false #and not in caller
506
- end
507
- end
578
+ end
579
+ end
508
580
 
509
- #postpone macro expansion in methods til method defn is executed
510
- class MethodNode
581
+ #postpone macro expansion in methods til method defn is executed
582
+ class MethodNode
511
583
  def old_macro_expand(macros,session)
512
584
  if session[:@expand_in_defs]
513
585
  session[:@expand_in_defs]=false
514
586
  expand=proc{|x| Node===x ? Macro.expand(x,macros,session) : x}
515
587
  self.receiver= expand[receiver]
516
- args.map! &expand if args
588
+ args.map!( &expand )if args
517
589
  self.body= expand[body]
518
- rescues.map! &expand if rescues
590
+ rescues.map!( &expand )if rescues
519
591
  self.ensure_= expand[ensure_]
520
592
  self.else_= expand[else_]
521
593
  session[:@expand_in_defs]=true
@@ -527,17 +599,17 @@ class Macro
527
599
  def macro_expand(macros,session)
528
600
  expand=proc{|x| Node===x ? Macro.expand(x,macros,session) : x}
529
601
  self.receiver= expand[receiver]
530
- args.map! &expand if args
602
+ args.map!( &expand )if args
531
603
  self.body= expand[body]
532
- rescues.map! &expand if rescues
604
+ rescues.map!( &expand )if rescues
533
605
  self.ensure_= expand[ensure_]
534
606
  self.else_= expand[else_]
535
607
  return self,false
536
608
  end
537
- end
609
+ end
538
610
 
539
- #disable macro definitions within classes and modules
540
- module DisableMacros
611
+ #disable macro definitions within classes and modules
612
+ module DisableMacros
541
613
  def macro_expand(macros,session)
542
614
  old_unsure=session[:@modpath_unsure]
543
615
  old_namespace_type=session[:@namespace_type]
@@ -558,7 +630,7 @@ class Macro
558
630
  else
559
631
  unwind=1
560
632
  end
561
- session[:@modpath].push *name
633
+ session[:@modpath].push( *name )
562
634
 
563
635
  map!{|n|
564
636
  case n
@@ -579,25 +651,32 @@ class Macro
579
651
 
580
652
  return nil,false #halt further recursion: already done
581
653
  end
582
- end
583
- class ModuleNode; include DisableMacros; end
584
- class ClassNode; include DisableMacros; end
654
+ end
655
+ class ModuleNode; include DisableMacros; end
656
+ class ClassNode; include DisableMacros; end
585
657
 
586
- class MetaClassNode
658
+ class MetaClassNode
587
659
  def macro_expand(macros,session)
588
660
  old_unsure=session[:@modpath_unsure]
589
661
  session[:@modpath_unsure]=true
590
- map!{|n| Macro.expand(n,macros,session) if n}
662
+ map!{|n|
663
+ case n
664
+ when nil
665
+ when Node; Macro.expand(n,macros,session)
666
+ when Array; n.map!{|nn| Macro.expand(nn,macros,session) }
667
+ else fail
668
+ end
669
+ }
591
670
  session[:@modpath_unsure]=old_unsure
592
671
 
593
672
  return nil,false #halt further recursion: already done
594
673
  end
595
- end
674
+ end
596
675
 
597
- #postpone macro expansion (and definition) in forms until they are evaled
598
- #(or returned from a macro)
599
- #but not in form parameters
600
- class FormNode < ValueNode
676
+ #postpone macro expansion (and definition) in forms until they are evaled
677
+ #(or returned from a macro)
678
+ #but not in form parameters
679
+ class FormNode < ValueNode
601
680
  def macro_expand(macros,session)
602
681
  #return text.to_sexp({})
603
682
 
@@ -632,9 +711,9 @@ class Macro
632
711
  end
633
712
  return result
634
713
  end
635
- end
714
+ end
636
715
 
637
- class FormParameterNode<ValueNode
716
+ class FormEscapeNode<ValueNode
638
717
  # Convert this node to an S-expression
639
718
  #
640
719
  # +session+:: the context in which this macro is being processed
@@ -643,7 +722,7 @@ class Macro
643
722
  nest=session[:form_nest_level]||1
644
723
  carets=0
645
724
  node=self
646
- while FormParameterNode===node
725
+ while FormEscapeNode===node
647
726
  node=node.text
648
727
  carets+=1
649
728
  end
@@ -655,9 +734,9 @@ class Macro
655
734
  end
656
735
 
657
736
  def image
658
- "^"+first.image
737
+ "^"+body.image
659
738
  end
660
- end
739
+ end
661
740
 
662
741
  class MacroNode < ValueNode
663
742
  param_names(:defword_,:receiver,:name,:args,:semi_,:body,:rescues,:elses,:ensures,:endword_)
@@ -702,7 +781,7 @@ class Macro
702
781
  alias ensure_ ensures
703
782
  alias ensure ensures
704
783
 
705
- # Performs the reverse of a parse operation (turns the node into a
784
+ # Performs the reverse of a parse operation (turns the MacroNode into a
706
785
  # string)
707
786
  #
708
787
  # +o+:: a list of options for unparse
@@ -717,7 +796,7 @@ class Macro
717
796
  result+=")"
718
797
  end
719
798
  result+=unparse_nl(body,o)+body.unparse(o) if body
720
- result+=rescues.map{|resc| resc.unparse o}.to_s
799
+ result+=rescues.map{|resc| resc.unparse o}.to_s if rescues
721
800
  result+=unparse_nl(else_,o)+"else "+else_.unparse( o )+"\n" if else_
722
801
  result+=unparse_nl(ensure_,o)+"ensure "+ensure_.unparse( o )+"\n" if ensure_
723
802
  result+=";end"
@@ -727,7 +806,8 @@ class Macro
727
806
 
728
807
  class OneLineParenedNode < ParenedNode
729
808
  #hacky way to get unparser to not emit newlines in most cases
730
- def unparse(o=default_parse_options)
809
+ #I think this isn't necessary now that forms (and subnodes) have their linenums zeroed on creation
810
+ def unparse(o=default_unparse_options)
731
811
  old_linenum=o[:linenum]
732
812
  o[:linenum]=2**128
733
813
  result=super(o)
@@ -737,22 +817,146 @@ class Macro
737
817
  end
738
818
  end
739
819
 
740
- class RedParseWithMacros < RedParse
820
+ class JustNilNode<ValueNode
821
+ def unparse(o=default_unparse_options)
822
+ "nil"
823
+ end
824
+ end
825
+
826
+ class ::RubyLexer
827
+
828
+ module MacroMixin
829
+ #-----------------------------------
830
+ #def FUNCLIKE_KEYWORDS(orig=nil) #was
831
+ # /(?:#{orig||super}|^v$)/
832
+ #end
833
+
834
+ #-----------------------------------
835
+ def rubylexer_modules_init
836
+ super
837
+
838
+ @unary_or_binary_chars.add '^'
839
+ @always_binary_chars.remove '^'
840
+
841
+ # @FUNCLIKE_KEYWORDS=FUNCLIKE_KEYWORDS @FUNCLIKE_KEYWORDS unless @FUNCLIKE_KEYWORDS==="v" #was
842
+ end
843
+ #def keyword_v(*args,&block) _keyword_funclike(*args,&block) end #was
844
+
845
+ def keyword_macro(*args)
846
+ keywords_def(*args)
847
+ end
848
+
849
+ #-----------------------------------
850
+ def method_params?
851
+ lasttok=last_token_maybe_implicit #last_operative_token
852
+ return super unless lasttok
853
+ case lasttok.ident
854
+ when ';'
855
+ if VContext===@parsestack.last
856
+ @parsestack.pop
857
+ true
858
+ #else super #need this here...? I think not ....
859
+ end
860
+ when ')'
861
+ @moretokens<<KeywordToken.new("<doubled-parens>")
862
+ @parsestack.pop if VContext===@parsestack.last
863
+ true
864
+ when '.'
865
+ true
866
+ else super
867
+ end
868
+ end
869
+
870
+ #-----------------------------------
871
+ def keyword_v(str,offset,result)
872
+ result[0]=OperatorToken.new("v",offset)
873
+ @parsestack<<VContext.new(@linenum)
874
+ return result
875
+ end
876
+
877
+ #-----------------------------------
878
+ def symbol_or_op(ch) #is this even needed?
879
+ startpos= input_position
880
+ if readahead(2)==":("
881
+ result= OperatorToken.new(read(1), startpos)
882
+ result.unary=true
883
+ return result
884
+ end
885
+ super
886
+ end
887
+
888
+ #-----------------------------------
889
+ def caret(ch) #match /^=?/ (^ or ^=) (maybe unary ^ too) #is this even needed?
890
+ if @last_token_maybe_implicit&&@last_token_maybe_implicit.ident=='(' or
891
+ unary_op_expected?(ch)
892
+ result=OperatorToken.new(read(1),input_position)
893
+ result.unary=true
894
+ result
895
+ else
896
+ super
897
+ end
898
+ end
899
+
900
+ #-----------------------------------
901
+ def callsite_symbol(x) #is this even needed?
902
+ return if nextchar==?(
903
+ super
904
+ end
905
+ end
906
+
907
+ module NestedContexts
908
+ class VContext<NestedContext
909
+ def initialize(linenum)
910
+ super("v","",linenum)
911
+ end
912
+ def see evt,lexer
913
+ lexer.parsestack.pop if evt==:semi and lexer.readahead(1)!='('
914
+ end
915
+ end
916
+ end
917
+
918
+ end
919
+
920
+ module ::RedParse::MacroMixin
921
+ RedParse.constants.each{|k|
922
+ const_set k, RedParse::const_get(k)
923
+ }
924
+
925
+ def redparse_modules_init
926
+ if defined? @lexer and @lexer.respond_to? :enable_macros!
927
+ @lexer.enable_macros!
928
+ @lexer.extend ::RubyLexer::MacroMixin
929
+ @lexer.rubylexer_modules_init
930
+ end
931
+ # binary
932
+ @unary_or_binary_op=/^([\^:]|#@unary_or_binary_op)$/
933
+
934
+
935
+ super
936
+ end
937
+
741
938
  def PRECEDENCE
742
939
  result=super
743
- return result.merge({"^@"=>result["+@"]})
940
+ return result.merge({"^@"=>result["+@"], "v"=>result[";"]})
744
941
  end
942
+
745
943
  def RULES
944
+ @@soft_nl||=KW(';')&-{:not_real? =>false}
746
945
  [
747
946
  -[KW('macro'), KW(beginsendsmatcher).~.*, KW('end'), KW(/^(do|\{)$/).~.la]>>MisparsedNode
748
947
  ]+super+[
749
- -[Op('^@'), Expr, lower_op()]>>FormParameterNode,
750
- -[Op(':@'), (ParenedNode&-{:size=>1})|(VarLikeNode&-{:ident=>"nil"})]>>FormNode,
948
+ -['<+', Expr, '+>']>>FormEscapeNode,
949
+ -[Op('v'), Expr, lower_op()]>>FormEscapeNode,
950
+ -[Op('v'), Expr, /^;$|^<doubled-parens>$/, '(', Expr.-, ')']>>FormEscapeNode, #constructor needs update
951
+ -[Op('v'), Expr, ';', KW('(').~.la]>>FormEscapeNode,
952
+ -[Op('v'), Expr, @@soft_nl.la]>>:shift,
953
+ -[Op('^@'), Expr, lower_op()]>>FormEscapeNode,
954
+ -[Op(':@'), (ParenedNode&-{:size=>(0..1)})|(SequenceNode&-{:size=>0})]>>FormNode,
751
955
  -['macro', CallSiteNode, KW(';'),
752
956
  Expr.-, RescueNode.*, ElseNode.-, EnsureNode.-,
753
957
  'end'
754
958
  ]>>MacroNode,
755
- -[ParenedNode, '(', Expr.-, ')', BlockNode.-, KW('do').~.la]>>CallNode,
959
+ -[ '(', Expr.-, ')', '<doubled-parens>', '(', Expr.-, ')', BlockNode.-, KW('do').~.la]>>CallNode, #constructor needs update
756
960
  ]
757
961
  end
758
962
  def wants_semi_context
@@ -768,14 +972,45 @@ class Macro
768
972
  return @bem||=/#{super}|^macro$/
769
973
  end
770
974
 
771
- def initialize(*args)
772
- super
773
- @lexer.enable_macros! if @lexer.respond_to? :enable_macros!
975
+ def reduce_withs_directory
976
+ "macro"
977
+ end
774
978
 
775
- # Add ^ to the list of operators that could be either unary or
776
- # binary
777
- @unary_or_binary_op=/^([\^:]|#@unary_or_binary_op)$/o
979
+ def rubyoperatorlist
980
+ super+%w[:@ ^@ v]
981
+ end
982
+
983
+ def rubykeywordlist
984
+ super+%w[macro v]
985
+ end
986
+
987
+ def addl_node_containers; [::Macro] end
988
+
989
+ def initialize(*args,&block)
990
+ super
778
991
  end
779
992
  end
993
+ Macro_ParserMixin=::RedParse::MacroMixin #old name
994
+
995
+ class ::RedParse::WithMacros < RedParse
996
+ include ::RedParse::MacroMixin
997
+ end
998
+ RedParseWithMacros=::RedParse::WithMacros #old name
780
999
  end
781
1000
 
1001
+ #hacks to allow you to use macros within irb sessions.
1002
+ #I wonder how portable this is to rubinius, jruby, mri 1.9, etc
1003
+ module IRB
1004
+ class WorkSpace
1005
+ def evaluate(context, statements, file = __FILE__, line = __LINE__)
1006
+ Macro.eval(statements, @binding, file, line)
1007
+ end
1008
+ end
1009
+ ::RubyLex::ENINDENT_CLAUSE<<"macro"
1010
+ module ::RubyToken
1011
+ def_token(:TkMACRO, TkId, "macro", EXPR_FNAME)
1012
+ end
1013
+ def IRB.require(file)
1014
+ Macro.require(file)
1015
+ end
1016
+ end if defined? IRB