File Coverage

lib/Decl/Semantics/Macro.pm
Criterion Covered Total %
statement 54 86 62.7
branch 12 40 30.0
condition 3 12 25.0
subroutine 12 13 92.3
pod 9 9 100.0
total 90 160 56.2


line stmt bran cond sub pod time code
1             package Decl::Semantics::Macro;
2            
3 12     12   73 use warnings;
  12         26  
  12         454  
4 12     12   69 use strict;
  12         26  
  12         479  
5            
6 12     12   64 use base qw(Decl::Node);
  12         26  
  12         1355  
7 12     12   80 use Data::Dumper;
  12         25  
  12         13087  
8            
9             =head1 NAME
10            
11             Decl::Semantics::Macro - defines or instantiates a macro.
12            
13             =head1 VERSION
14            
15             Version 0.01
16            
17             =cut
18            
19             our $VERSION = '0.01';
20            
21            
22             =head1 SYNOPSIS
23            
24             The C macro facility is still pretty green; it will probably go through a few iterations before I really like it.
25            
26             This initial implementation provides three tags: "define" defines a named macro that can then be used anywhere and will instantiate a new
27             node at build time based on its environment; "express" expresses a macro in situ at runtime; and "<=" defines and instantiates an anonymous
28             macro in place, also at runtime. I'm not 100% sure that the build time/runtime distinction will be terribly significant, but more use will
29             doubtlessly result in some places where it will be a useful one.
30            
31             =head2 defines(), tags_defined()
32            
33             Called by Decl::Semantics during import, to find out what xmlapi tags this plugin claims to implement.
34            
35             =cut
36 0     0 1 0 sub defines { ('define', 'express', '<=') }
37             our %build_handlers = ();
38 12     12 1 91 sub tags_defined { Decl->new_data(<
39             define
40             express
41             <=
42             EOF
43            
44             =head2 build_payload ()
45            
46             The C function is then called when this object's payload is built. It handles the three tags separately, plus any defined
47             tags we've built in the meantime.
48            
49             =cut
50             sub build_payload {
51 7     7 1 16 my ($self) = @_;
52            
53 7 100 66     35 if ($self->code || $self->bracket) { # Handle basic code macros.
54 3         16 Decl::Semantics::Code::build_macro_payload($self);
55             }
56 7         36 $self->build_children();
57 7 100       25 if ($self->is('define')) { $self->build_define; return; }
  2         9  
  2         9  
58 5 100       21 if ($self->is('<=')) { $self->build_inplace; return; }
  1         6  
  1         3  
59 4 50       13 if ($self->is('express')) { $self->build_express; return; }
  0         0  
  0         0  
60            
61 4         8 $self->{force_text} = 1; # We don't want any of our children built; they're treated as text.
62 4         16 $self->instantiate;
63 4         12 1;
64             }
65            
66             =head2 build_define - defining a macro
67            
68             Actually, definition of a macro doesn't do a lot. All the good stuff happens at instantiation.
69            
70             =cut
71            
72             sub build_define {
73 2     2 1 4 my ($self) = @_;
74 2         969 my $macroname = $self->name;
75 2         5 $self->{instantiated} = 0;
76 2         8 $self->root()->{macro_definitions}->{$macroname} = $self;
77 2         7 $self->root()->register_builder (ref ($self), $self->parameter('domain', 'core'), Decl->new_data(<<" EOF"));
78             $macroname
79             EOF
80             }
81            
82             =head2 instantiate - instantiating a macro once defined
83            
84             Once a macro is defined, its name is treated just like any other tag. When this class is called to instantiate it, we build a new
85             node based on the current environment (that is, whatever variables have already been set, including the parameters on the invocation)
86             and macro-insert it. If the inserted result is callable, then the invocation will mark it as a proxy and execute its code on "go", while
87             the result itself will be unmarked as callable - this ensures that the code will run at the point of the invocation, not at the eventual
88             place of insertion of the macro result (which is at the end of the list of children of the parent - not the right place to run it).
89            
90             =cut
91            
92             sub instantiate {
93 5     5 1 10 my ($self, $definition) = @_;
94 5 100       23 $definition = $self->root()->{macro_definitions}->{$self->tag} unless defined $definition;
95 5 50       19 return unless $definition;
96            
97 5         22 $self->{instantiates} = $definition;
98 5         14 $definition->{callable} = 0; # A macro, at least once instantiated, cannot be considered for execution.
99            
100             # First off, let's set all the parameters from the tag line - e.g. mymacro (parm1 = "something")
101             # This will make these available to template macros as well as to full-on macros.
102             #foreach my $parameter ($self->parmlist) {
103             # $definition->{hashtie}->just_store($parameter, $self->parameter($parameter));
104             #}
105            
106             # There are three varieties of macro: a code macro just runs some Perl and inserts the output; a text macro is a template that is
107             # expressed and that expression is inserted; and a nodal macro does some fancy stuff, of which more below.
108 5 50       19 if ($definition->{owncode}) { # Code macro.
109 5         12 $definition->{output} = '';
110 5         20 $definition->go($self);
111 5         22 $self->parent->macroinsert($definition->{output}, $self);
112 5         15 return 1;
113             }
114            
115 0 0       0 if ($definition->hasbody) { # Simple template.
116 0         0 my $output = $Decl::template_engine->express($definition->{body}, $self); # Instantiate template in macro definition, using instantiation as the data source.
117 0         0 $self->parent->macroinsert($output, $self);
118 0         0 return 1;
119             }
120            
121             # Complex case. Essentially, we're going to scan down the children, running callable things and treating any output and setup children
122             # as templates. Setup children are only output once.
123 0         0 foreach ($definition->nodes) {
124 0 0 0     0 if ($_->is ('yield') || $_->is('setup')) {
    0          
125 0 0 0     0 next if $_->is('setup') and $definition->{instantiated};
126 0 0       0 if ($_->{owncode}) {
    0          
127 0         0 $_->{output} = '';
128 0         0 $_->go($self);
129 0         0 $self->parent->macroinsert($_->{output}, $self);
130             } elsif ($_->hasbody) {
131 0         0 my $output = $Decl::template_engine->express($_->{body}, $self);
132 0         0 $self->parent->macroinsert($output, $self);
133             }
134             } elsif ($_->is('parameter')) {
135 0         0 my $parameter = $_->name;
136             # Can I find this parameter in the invocation?
137             #next if exists $self->{v}->{$parameter}; # If it's a tagline parameter, skip it; we already did this.
138 0         0 my $value = $self->{parameters}->{$parameter};
139 0 0       0 if (not defined $value) {
140 0 0       0 if (my $child = $self->first($parameter)) {
    0          
    0          
141 0 0       0 if ($child->label) {
    0          
142 0         0 $value = $child->label;
143             } elsif ($child->{callable} eq 1) {
144 0         0 $value = $child->go;
145             } else {
146 0         0 $value = $child->describe_content;
147             }
148             }
149             # Nope: set the default. TODO: this code could use some refactorization, couldn't it?
150             elsif (defined $_->label) {
151 0         0 $value = $_->label;
152             } elsif ($_->{callable} eq 1) {
153 0         0 $value = $_->go;
154             } else {
155 0         0 $value = $child->describe_content;
156             }
157             }
158 0         0 $definition->{hashtie}->just_store($parameter, $value);
159             } else {
160 0         0 my $return = $_->go ($self, @_);
161             }
162             }
163            
164 0         0 $definition->{instantiated} = 1; # Shut off further output of "setup" children.
165             }
166            
167             =head2 build_inplace - defining and instantiating a macro at the same time
168            
169             In-place instantiation of a "here" macro allows code to be written that expresses a macro expansion at build time.
170            
171             =cut
172            
173             sub build_inplace {
174 1     1 1 2 my ($self) = @_;
175 1         6 $self->instantiate($self);
176 1         3 1;
177             }
178            
179             =head2 build_express: instantiating a macro at runtime, *or* expressing a template, depending on what the expressed thing is.
180            
181            
182            
183            
184             =head2 output, iterate
185            
186             The C function usually diverts to writing, but for macro instantiation it is the input to creating our expression.
187             So we collect it. At the end of the instantiation, we'll evaluate it.
188            
189             The C function (normal output) is disabled for macro calls; the instantiation should do this work.
190            
191             =cut
192            
193 8     8 1 150 sub output { $_[0]->{output} .= $_[1] }
194 7     7 1 16 sub iterate { }
195            
196             =head2 go
197            
198             The C function overrides the usual running function of nodes because we're either acting as a proxy for our macro results, or we're going
199             to instantiate at runtime.
200            
201             =cut
202            
203             sub go {
204 5     5 1 11 my $self = shift;
205 5         6 my $instance = shift;
206 5         8 my $return;
207            
208             #return unless $self->{callable}; - Note that this is specifically disabled for macro definitions.
209 5 50 33     39 if ($self->{owncode} && $self->{sub}) {
210 5         10 $return = &{$self->{sub}}($instance, @_);
  5         156  
211             } else {
212 0         0 foreach ($self->nodes) {
213 0         0 $return = $_->go ($instance, @_);
214             }
215             }
216 5         11 return $return;
217             }
218            
219             =head1 AUTHOR
220            
221             Michael Roberts, C<< >>
222            
223             =head1 BUGS
224            
225             Please report any bugs or feature requests to C, or through
226             the web interface at L. I will be notified, and then you'll
227             automatically be notified of progress on your bug as I make changes.
228            
229             =head1 LICENSE AND COPYRIGHT
230            
231             Copyright 2010 Michael Roberts.
232            
233             This program is free software; you can redistribute it and/or modify it
234             under the terms of either: the GNU General Public License as published
235             by the Free Software Foundation; or the Artistic License.
236            
237             See http://dev.perl.org/licenses/ for more information.
238            
239             =cut
240            
241             1; # End of Decl::Semantics::Macro