rubymacros 0.1.5 → 0.1.6

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