line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Language::AttributeGrammar; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
129803
|
use 5.006001; |
|
5
|
|
|
|
|
22
|
|
|
5
|
|
|
|
|
181
|
|
4
|
5
|
|
|
5
|
|
24
|
use strict; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
144
|
|
5
|
5
|
|
|
5
|
|
24
|
use warnings; |
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
159
|
|
6
|
5
|
|
|
5
|
|
26
|
no warnings 'uninitialized'; |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
259
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '0.08'; |
9
|
|
|
|
|
|
|
|
10
|
5
|
|
|
5
|
|
2645
|
use Language::AttributeGrammar::Parser; |
|
5
|
|
|
|
|
268932
|
|
|
5
|
|
|
|
|
229
|
|
11
|
5
|
|
|
5
|
|
66
|
use Perl6::Attributes; |
|
5
|
|
|
|
|
32
|
|
|
5
|
|
|
|
|
52
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
my $methnum = '0'; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub new { |
16
|
19
|
|
|
19
|
0
|
18638
|
my ($class, $options, $grammar) = @_; |
17
|
19
|
100
|
|
|
|
103
|
unless (ref $options eq 'HASH') { |
18
|
18
|
|
|
|
|
31
|
$grammar = $options; |
19
|
18
|
|
|
|
|
41
|
$options = {}; |
20
|
|
|
|
|
|
|
} |
21
|
|
|
|
|
|
|
|
22
|
19
|
|
|
|
|
164
|
my $engine = Language::AttributeGrammar::Parser->new($grammar, $options->{prefix}); |
23
|
18
|
|
|
|
|
113
|
my $meth = '_AG_visit_' . $methnum++; |
24
|
18
|
|
|
|
|
83
|
$engine->make_visitor($meth); |
25
|
|
|
|
|
|
|
|
26
|
18
|
|
33
|
|
|
264
|
bless { |
27
|
|
|
|
|
|
|
engine => $engine, |
28
|
|
|
|
|
|
|
meth => $meth, |
29
|
|
|
|
|
|
|
} => ref $class || $class; |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub apply { |
33
|
21
|
|
|
21
|
0
|
289
|
my ($self, $top, $attr, $topattrs) = @_; |
34
|
|
|
|
|
|
|
|
35
|
21
|
|
|
|
|
113
|
$.engine->evaluate($.meth, $top, $attr, $topattrs); |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub annotate { |
39
|
0
|
|
|
0
|
0
|
|
my ($self, $top, $topattrs) = @_; |
40
|
0
|
|
|
|
|
|
Language::AttributeGrammar::Annotator->new($.engine->annotate($.meth, $top, $topattrs)); |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
package Language::AttributeGrammar::Annotator; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub new { |
46
|
0
|
|
|
0
|
|
|
my ($class, $ann) = @_; |
47
|
|
|
|
|
|
|
|
48
|
0
|
|
0
|
|
|
|
bless { |
49
|
|
|
|
|
|
|
ann => $ann, |
50
|
|
|
|
|
|
|
} => ref $class || $class; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
our $AUTOLOAD; |
54
|
|
|
|
|
|
|
sub AUTOLOAD { |
55
|
0
|
|
|
0
|
|
|
(my $attr = $AUTOLOAD) =~ s/.*:://; |
56
|
0
|
0
|
|
|
|
|
return if $attr eq 'DESTROY'; |
57
|
|
|
|
|
|
|
|
58
|
0
|
|
|
|
|
|
my ($self, $node) = @_; |
59
|
0
|
|
|
|
|
|
$self->get($node)->get($attr)->get; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
1; |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=head1 NAME |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Language::AttributeGrammar - Attribute grammars for doing computations over trees. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=head1 SYNOPSIS |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
use Language::AttributeGrammar; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# Grammar to return a new tree that is just like the old one, except |
74
|
|
|
|
|
|
|
# every leaf's value is the value of the minimum leaf. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
my $grammar = new Language::AttributeGrammar <<'END_GRAMMAR'; |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# find the minimum of a tree from the leaves up |
79
|
|
|
|
|
|
|
Leaf: $/.min = { $ } |
80
|
|
|
|
|
|
|
Branch: $/.min = { List::Util::min($.min, $.min)) } |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# find the global minimum and propagate it back down the tree |
83
|
|
|
|
|
|
|
ROOT: $/.gmin = { $/.min } |
84
|
|
|
|
|
|
|
Branch: $.gmin = { $/.gmin } |
85
|
|
|
|
|
|
|
| $.gmin) = { $/.gmin } |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# reconstruct the tree with every leaf replaced with the minimum value |
88
|
|
|
|
|
|
|
Leaf: $/.result = { Leaf->new($/.gmin) } |
89
|
|
|
|
|
|
|
Branch: $/.result = { Branch->new($.result, $.result) } |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
END_GRAMMAR |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# This grammar expects that you define these classes: |
94
|
|
|
|
|
|
|
# Branch (with a ->left and ->right attribute) |
95
|
|
|
|
|
|
|
# Leaf (with a ->value attribute) |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# Use the grammar |
98
|
|
|
|
|
|
|
my $tree = Branch->new( Leaf->new(1), |
99
|
|
|
|
|
|
|
Branch->new( Leaf->new(2), Leaf->new(3))); |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# Apply the attribute grammar to the data structure and fetch the result |
102
|
|
|
|
|
|
|
my $result = $grammar->apply($tree, 'result'); |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=head1 DESCRIPTION |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
This module implements simple (for now) Attribute Grammar support for Perl data |
107
|
|
|
|
|
|
|
structures. An attribute grammar is a way to specify I over a |
108
|
|
|
|
|
|
|
predefined data structure, say, as generated by L. This is |
109
|
|
|
|
|
|
|
done by associating I with the nodes of the data structure. |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
There are two types of attributes: synthesized and inherited. Synthesized |
112
|
|
|
|
|
|
|
attributes propagate bottom-up, that is, they use information from the children |
113
|
|
|
|
|
|
|
of a node to infer the attribute's value on that node. Inherited attributes |
114
|
|
|
|
|
|
|
are the opposite: they use information from a node in the structure to infer |
115
|
|
|
|
|
|
|
attributes on its chilren. |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
In the example above in the synopsis, the C attribute is synthesized, |
118
|
|
|
|
|
|
|
since it takes the values at the leaves and infers the minimum at a branch. |
119
|
|
|
|
|
|
|
The C (global minimum) attribute is inherited, since it uses C that |
120
|
|
|
|
|
|
|
was computed at the root node and propagates it downward to the leaves. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=head2 Syntax |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
Some special syntax is used in throughout the definitions, borrowed from the |
125
|
|
|
|
|
|
|
syntax for Perl 6 grammars. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=over |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=item * C<$/> |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
The current node. |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=item * C<$/.attr> |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
The C attribute on the current node. |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=item * C<< $ >> |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
The child node named C of the current node. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=item * C<< $.attr >> |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
The C attribute on the child node. |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=item * C<< `arbitrary(code)`.attr >> |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
Execute C B and fetch the C attribute |
148
|
|
|
|
|
|
|
from each element. So: |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
Foo: $/.bar = { `get_child($/)`.bar } # WRONG |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
C<$/.bar> will always be 1 (the number of things C returned). If |
153
|
|
|
|
|
|
|
you want to do this right, since you are only intending to use one value: |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
Foo: $/.bar = { `get_child($/)`.bar[0] } # okay |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Also, the code inside backticks must not refer to any lexical variables or any |
158
|
|
|
|
|
|
|
attributes. That is, C<$/> and his children are the only variables you may |
159
|
|
|
|
|
|
|
refer to (but you may call methods on them, etc.). |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=back |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
The grammar definition is composed of a series of I definitions. An |
164
|
|
|
|
|
|
|
example semantic definition is: |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Foo: $/.baz = { $.baz } |
167
|
|
|
|
|
|
|
| $.quux = { $/.quux } |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
This specifies the implementations of the I C and |
170
|
|
|
|
|
|
|
the I C for nodes of type Foo. That is, you can |
171
|
|
|
|
|
|
|
find the C attribute of the current node by looking at the baz attribute |
172
|
|
|
|
|
|
|
of its child, and you can find the C attribute of any node's child by |
173
|
|
|
|
|
|
|
looking at the C attribute of the node itself. |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
The C<< $ >> notation is defined to pretty much do the right thing. |
176
|
|
|
|
|
|
|
But, in the name of predictability, here are the semantics: |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
If C<$/> has a method named C (for the attribute C<< $ >>), then |
179
|
|
|
|
|
|
|
that method is called with no arguments to fetch the attribute. Otherwise, if |
180
|
|
|
|
|
|
|
C<$/> is a blessed hash, then the module snoops inside the hash and pulls out |
181
|
|
|
|
|
|
|
the key named "child". If the hash has no such key, or the object is not a |
182
|
|
|
|
|
|
|
blessed hash (eg. a blessed array), then we give up. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
If your tree has a different convention for extracting child nodes, you may use |
185
|
|
|
|
|
|
|
the backtick syntax described above: |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
Cons: $/.sum = { `$/->get_child('head')`.sum + `$/->get_child('tail')`.sum } |
188
|
|
|
|
|
|
|
Nil: $/.sum = { 0 } |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
Cons: `$/->get_child('head')`.gsum = { $/.gsum } |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
In the future I may provide a callback that allows the user to define |
193
|
|
|
|
|
|
|
the meaning of C<< $ >>. |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
There is one special class name that can go to the left of the colon: |
196
|
|
|
|
|
|
|
C. This represents the root of the data structure you were given, |
197
|
|
|
|
|
|
|
and is used to avoid the common annoyance of creating a Root node |
198
|
|
|
|
|
|
|
class tha just bootstraps the "real" tree. So when you say: |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
ROOT: $/.gmin = { $/.min } |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
That means that when you're at the root of the data structure, the |
203
|
|
|
|
|
|
|
global minimum is equal to the local minimum. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=head2 Usage |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
After you have a grammar specification in a string, create a new grammar |
208
|
|
|
|
|
|
|
object: |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
my $grammar = Language::AttributeGrammar->new($grammar_string); |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
This contains a minimal data structure of the semantics definitions. The |
213
|
|
|
|
|
|
|
constructor also can take an options hash as its first argument: |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
my $grammar = Language::AttributeGrammar->new({ prefix => 'Foo::' }, $grammar_string); |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
The only option at the moment is C, which will prepend this |
218
|
|
|
|
|
|
|
prefix to all the types mentioned in your grammar. However, if you need |
219
|
|
|
|
|
|
|
to omit this prefix, name the type in your grammar starting with a |
220
|
|
|
|
|
|
|
C<::>, and the prefix will not be prepended. |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
In order to find an attribute on the root node of a data structure, C it |
223
|
|
|
|
|
|
|
to the data structure, giving the name of the attribute you wish to find. |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
my $attr = $grammar->apply($data, 'attr'); |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
You may set attributes on the root of the data structure by passing a hash. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
my $attr = $grammar->apply($data, 'attr', { |
230
|
|
|
|
|
|
|
starting_number => 0, |
231
|
|
|
|
|
|
|
}); |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
In order to find attributes on nodes that are lower in the structure, you must |
234
|
|
|
|
|
|
|
concoct your attribute grammar to propagate that information up the tree |
235
|
|
|
|
|
|
|
somehow. Usually this is done using a synthesized attribute that mirrors the |
236
|
|
|
|
|
|
|
given data structure. |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=head1 AUTHOR |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
Luke Palmer |