line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Decl::Util;
|
2
|
|
|
|
|
|
|
|
3
|
12
|
|
|
12
|
|
72
|
use warnings;
|
|
12
|
|
|
|
|
25
|
|
|
12
|
|
|
|
|
783
|
|
4
|
12
|
|
|
12
|
|
66
|
use strict;
|
|
12
|
|
|
|
|
24
|
|
|
12
|
|
|
|
|
582
|
|
5
|
12
|
|
|
12
|
|
65
|
use base qw(Exporter);
|
|
12
|
|
|
|
|
24
|
|
|
12
|
|
|
|
|
1020
|
|
6
|
12
|
|
|
12
|
|
66
|
use vars qw(@EXPORT);
|
|
12
|
|
|
|
|
26
|
|
|
12
|
|
|
|
|
10471
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
@EXPORT = qw(car cdr popcar splitcar lazyiter escapequote hh_set hh_get);
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 NAME
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
Decl::Util - some utility functions for the declarative framework - automatically included for generated code.
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 VERSION
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Version 0.01
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=cut
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
our $VERSION = '0.01';
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
This class is a lightweight set of utilities to make things easier throughout C. I'm not yet sure what will end up here, but my
|
26
|
|
|
|
|
|
|
rule of thumb is that it's extensions I'd like to be able to use in code generators as well.
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head2 Lazy Lispy lists: car(), cdr(), popcar(), splitcar()
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
I like Higher-Order Perl, really I do - but his head/tail streams are really just car and cdr, so I'm hereby defining car and cdr as lazy-evaluated streams
|
31
|
|
|
|
|
|
|
throughout the language. Nodes are arrayrefs. Clean and simple, no object orientation required.
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=cut
|
34
|
|
|
|
|
|
|
|
35
|
23076
|
100
|
|
23076
|
1
|
83015
|
sub car ($) { return undef unless ref $_[0] eq 'ARRAY'; $_[0]->[0] }
|
|
12157
|
|
|
|
|
43481
|
|
36
|
|
|
|
|
|
|
sub cdr ($) {
|
37
|
7269
|
|
|
7269
|
1
|
22585
|
my ($s) = @_;
|
38
|
7269
|
100
|
|
|
|
16592
|
return undef unless ref $s eq 'ARRAY';
|
39
|
7262
|
100
|
|
|
|
19005
|
$s->[1] = $s->[1]->() if ref $s->[1] eq 'CODE';
|
40
|
7262
|
|
|
|
|
95679
|
$s->[1];
|
41
|
|
|
|
|
|
|
}
|
42
|
|
|
|
|
|
|
sub popcar ($) {
|
43
|
851
|
|
|
851
|
1
|
2141
|
my $p = car($_[0]);
|
44
|
851
|
|
|
|
|
2042
|
$_[0] = cdr($_[0]);
|
45
|
851
|
|
|
|
|
3791
|
return $p;
|
46
|
|
|
|
|
|
|
}
|
47
|
1231
|
|
|
1231
|
1
|
1628
|
sub splitcar ($) { @{$_[0]}; }
|
|
1231
|
|
|
|
|
4802
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=head2 lazyiter($iterator)
|
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
Takes any coderef (but especially an L) and builds a stream out of it. Invokes the coderef once to get the
|
52
|
|
|
|
|
|
|
first value in the stream.
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=cut
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub lazyiter {
|
57
|
5102
|
|
|
5102
|
1
|
6825
|
my $i = shift;
|
58
|
5102
|
|
|
|
|
18313
|
my $value = $i->();
|
59
|
5102
|
100
|
|
|
|
118017
|
return unless defined $value;
|
60
|
3029
|
|
|
3010
|
|
18886
|
[$value, sub { lazyiter ($i); }]
|
|
3010
|
|
|
|
|
5210
|
|
61
|
|
|
|
|
|
|
}
|
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=head2 escapequote($string, $quote)
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
Returns a new string with C<$quote> escaped (by default, '"' is escaped) by means of a backslash.
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=cut
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub escapequote {
|
70
|
0
|
|
|
0
|
1
|
0
|
my ($string, $quote) = @_;
|
71
|
0
|
0
|
|
|
|
0
|
$quote = '"' unless $quote;
|
72
|
0
|
|
|
|
|
0
|
$string =~ s/($quote)/\\$1/g;
|
73
|
0
|
|
|
|
|
0
|
$string
|
74
|
|
|
|
|
|
|
}
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=head2 Hierarchical values a la CSS: hh_set(hash, name, value), hh_get (hash, name), and prepare_hierarchical_value as a helper
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
You know how CSS lets you specify something like C as well as something more like C? These functions give
|
79
|
|
|
|
|
|
|
you something similar using hierarchically nested hashrefs. They allow you to mix types of addressing:
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
hh_set($h, 'border-left', 'my value');
|
82
|
|
|
|
|
|
|
hh_set($h, 'border', 'right: val1; top: val2');
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# { 'border' => {'left' => 'my value',
|
85
|
|
|
|
|
|
|
# 'right' => 'val1',
|
86
|
|
|
|
|
|
|
# 'top' => 'val2'
|
87
|
|
|
|
|
|
|
# }
|
88
|
|
|
|
|
|
|
# }
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
Clear? Then you can use C to retrieve 'border' or 'border-left' by digging down into the hashref hierarchy.
|
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
Separators for names can be anything in -./
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=cut
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub prepare_hierarchical_value {
|
97
|
28
|
|
|
28
|
1
|
48
|
my ($hash, $name) = @_;
|
98
|
28
|
100
|
|
|
|
87
|
$hash->{$name} = {} unless defined $hash->{$name};
|
99
|
28
|
100
|
|
|
|
75
|
if (not ref $hash->{$name}) {
|
100
|
3
|
|
|
|
|
9
|
my $newhash = {'*' => $hash->{$name}};
|
101
|
3
|
|
|
|
|
8
|
$hash->{$name} = $newhash;
|
102
|
|
|
|
|
|
|
}
|
103
|
28
|
|
|
|
|
118
|
return $hash->{$name};
|
104
|
|
|
|
|
|
|
}
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub hh_set {
|
107
|
43
|
|
|
43
|
1
|
75
|
my ($hash, $name, $value) = @_;
|
108
|
|
|
|
|
|
|
|
109
|
43
|
100
|
|
|
|
101
|
unless (ref $name) {
|
110
|
27
|
|
|
|
|
95
|
my @s = split /[.\-\/]/, $name;
|
111
|
27
|
|
|
|
|
60
|
$name = \@s;
|
112
|
|
|
|
|
|
|
}
|
113
|
|
|
|
|
|
|
|
114
|
43
|
|
|
|
|
97
|
my ($first, @rest) = @$name;
|
115
|
43
|
100
|
|
|
|
90
|
if (@rest) {
|
116
|
16
|
|
|
|
|
36
|
hh_set (prepare_hierarchical_value ($hash, $first), \@rest, $value);
|
117
|
|
|
|
|
|
|
} else {
|
118
|
27
|
100
|
|
|
|
89
|
if ($value =~ /:/) {
|
|
|
100
|
|
|
|
|
|
119
|
4
|
|
|
|
|
25
|
foreach (split / *; */, $value) {
|
120
|
12
|
|
|
|
|
25
|
hh_set (prepare_hierarchical_value ($hash, $first), split / *: */);
|
121
|
|
|
|
|
|
|
}
|
122
|
|
|
|
|
|
|
} elsif (ref $hash->{$first}) {
|
123
|
1
|
|
|
|
|
10
|
$hash->{$first}->{'*'} = $value;
|
124
|
|
|
|
|
|
|
} else {
|
125
|
22
|
|
|
|
|
142
|
$hash->{$first} = $value;
|
126
|
|
|
|
|
|
|
}
|
127
|
|
|
|
|
|
|
}
|
128
|
|
|
|
|
|
|
}
|
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub hh_get {
|
131
|
13
|
|
|
13
|
1
|
25
|
my ($hash, $name) = @_;
|
132
|
|
|
|
|
|
|
|
133
|
13
|
100
|
|
|
|
30
|
unless (ref $name) {
|
134
|
7
|
|
|
|
|
30
|
my @s = split /[.\-\/]/, $name;
|
135
|
7
|
|
|
|
|
15
|
$name = \@s;
|
136
|
|
|
|
|
|
|
}
|
137
|
13
|
|
|
|
|
30
|
my ($first, @rest) = @$name;
|
138
|
13
|
100
|
|
|
|
97
|
return $hash->{$first} unless @rest;
|
139
|
6
|
|
|
|
|
20
|
hh_get ($hash->{$first}, \@rest);
|
140
|
|
|
|
|
|
|
}
|
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head1 AUTHOR
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Michael Roberts, C<< >>
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head1 BUGS
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through
|
150
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll
|
151
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes.
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
Copyright 2010 Michael Roberts.
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
158
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published
|
159
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License.
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information.
|
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=cut
|
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
1; # End of Decl::Util
|