rubymacros 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -0
- data/COPYING.LGPL +503 -158
- data/History.txt +115 -5
- data/Makefile +68 -0
- data/README.txt +29 -6
- data/TODO +1 -0
- data/bin/macroruby +69 -0
- data/example/__dir__.rb +18 -0
- data/example/__dir___wrap.rb +18 -0
- data/example/andand.rb +18 -0
- data/example/andand_wrap.rb +18 -0
- data/example/assert.rb +29 -8
- data/example/assert0.rb +11 -0
- data/example/assert0_wrap.rb +5 -0
- data/example/assert_does_nothing_when_disabled.rb +19 -0
- data/example/assert_wrap.rb +21 -0
- data/example/expected_output.txt +88 -0
- data/example/formless_macro.rb +123 -0
- data/example/formless_macro_wrap.rb +20 -0
- data/example/inline.rb +97 -0
- data/example/linenum.rb +19 -1
- data/example/linenum_user.rb +18 -0
- data/example/linenum_wrap.rb +18 -0
- data/example/loop.rb +18 -0
- data/example/loop_wrap.rb +18 -0
- data/example/meta.rb +25 -0
- data/example/meta_wrap.rb +20 -0
- data/example/nilresult.rb +26 -0
- data/example/nilresult_wrap.rb +21 -0
- data/example/pipeline.rb +37 -0
- data/example/rescuing.rb +33 -0
- data/example/rescuing_wrap.rb +21 -0
- data/example/role.rb +103 -0
- data/example/role_with_eval.rb +92 -0
- data/example/self_in_class.rb +27 -0
- data/example/separated_scope.rb +42 -0
- data/example/separated_scope_wrap.rb +20 -0
- data/example/simple.rb +18 -0
- data/example/simple_wrap.rb +18 -0
- data/example/unproc.rb +31 -0
- data/example/unproc_wrap.rb +21 -0
- data/example/unroll.rb +34 -0
- data/example/unroll_macros.rb +119 -0
- data/example/unroll_wrap.rb +22 -0
- data/example/with.rb +50 -7
- data/example/with_wrap.rb +19 -0
- data/lib/macro.rb +307 -72
- data/lib/macro/ReduceWithsFor_RedParse_RedParse__MacroMixin_RedParse__WithMacros_1_8.rb +18880 -0
- data/lib/macro/ReduceWithsFor_RedParse_RedParse__MacroMixin_RedParse__WithMacros_1_9.rb +19101 -0
- data/lib/macro/form.rb +136 -27
- data/lib/macro/node.rb +64 -0
- data/lib/macro/version.rb +2 -5
- data/lib/rubymacros.rb +19 -0
- data/lib/rubymacros/version.rb +23 -0
- data/lib/weakkeyhash.rb +18 -0
- data/rubymacros.gemspec +60 -0
- data/test/test_all.rb +27 -2
- data/test/test_examples.rb +91 -0
- data/test/test_expand.rb +56 -1
- data/test/test_form.rb +108 -10
- data/test/test_unroll.rb +120 -0
- metadata +93 -65
- data/Rakefile +0 -37
data/example/with_wrap.rb
CHANGED
@@ -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
|
|
data/lib/macro.rb
CHANGED
@@ -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
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
95
|
-
tree.
|
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
|
-
|
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
|
130
|
-
when true,false,nil
|
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
|
158
|
-
when String
|
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
|
-
|
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
|
-
|
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
|
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
|
503
|
-
|
504
|
-
|
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
|
-
|
507
|
-
|
578
|
+
end
|
579
|
+
end
|
508
580
|
|
509
|
-
|
510
|
-
|
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
|
-
|
609
|
+
end
|
538
610
|
|
539
|
-
|
540
|
-
|
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
|
-
|
583
|
-
|
584
|
-
|
654
|
+
end
|
655
|
+
class ModuleNode; include DisableMacros; end
|
656
|
+
class ClassNode; include DisableMacros; end
|
585
657
|
|
586
|
-
|
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|
|
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
|
-
|
674
|
+
end
|
596
675
|
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
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
|
-
|
714
|
+
end
|
636
715
|
|
637
|
-
|
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
|
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
|
-
"^"+
|
737
|
+
"^"+body.image
|
659
738
|
end
|
660
|
-
|
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
|
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
|
-
|
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
|
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
|
-
-[
|
750
|
-
-[Op('
|
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
|
-
-[
|
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
|
772
|
-
|
773
|
-
|
975
|
+
def reduce_withs_directory
|
976
|
+
"macro"
|
977
|
+
end
|
774
978
|
|
775
|
-
|
776
|
-
|
777
|
-
|
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
|