line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Acme::Sub::Parms; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
7530
|
use strict; |
|
4
|
|
|
|
|
23
|
|
|
4
|
|
|
|
|
114
|
|
4
|
4
|
|
|
4
|
|
18
|
use warnings; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
106
|
|
5
|
4
|
|
|
4
|
|
2222
|
use Filter::Util::Call; |
|
4
|
|
|
|
|
4066
|
|
|
4
|
|
|
|
|
404
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
BEGIN { |
8
|
4
|
|
|
4
|
|
15
|
$Acme::Sub::Parms::VERSION = '1.03'; |
9
|
4
|
|
|
|
|
7
|
%Acme::Sub::Parms::args = (); |
10
|
4
|
|
|
|
|
15
|
%Acme::Sub::Parms::raw_args = (); |
11
|
4
|
|
|
|
|
12179
|
$Acme::Sub::Parms::line_counter = 0; |
12
|
|
|
|
|
|
|
} |
13
|
|
|
|
|
|
|
|
14
|
445
|
|
|
445
|
|
644
|
sub _NORMALIZE () { return ':normalize'; }; |
15
|
473
|
|
|
473
|
|
582
|
sub _NO_VALIDATION () { return ':no_validation'; }; |
16
|
445
|
|
|
445
|
|
834
|
sub _DUMP () { return ':dump_to_stdout'; }; |
17
|
|
|
|
|
|
|
sub _DEBUG () { 0; }; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub _legal_option { |
20
|
|
|
|
|
|
|
return { |
21
|
|
|
|
|
|
|
_NORMALIZE() => 1, |
22
|
|
|
|
|
|
|
_NO_VALIDATION() => 1, |
23
|
|
|
|
|
|
|
_DUMP() => 1, |
24
|
5
|
|
|
5
|
|
7
|
}->{$_[0]}; |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
#### |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub import { |
30
|
4
|
|
|
4
|
|
41
|
my $class = shift; |
31
|
4
|
|
|
|
|
13
|
my $options = { |
32
|
|
|
|
|
|
|
_NORMALIZE() => 0, |
33
|
|
|
|
|
|
|
_NO_VALIDATION() => 0, |
34
|
|
|
|
|
|
|
_DUMP() => 0, |
35
|
|
|
|
|
|
|
}; |
36
|
4
|
|
|
|
|
15
|
foreach my $item (@_) { |
37
|
5
|
50
|
|
|
|
11
|
if (not _legal_option($item)) { |
38
|
0
|
|
|
|
|
0
|
my $package = __PACKAGE__; |
39
|
0
|
|
|
|
|
0
|
require Carp; |
40
|
0
|
|
|
|
|
0
|
Carp::croak("'$item' not a valid option for 'use $package'\n"); |
41
|
|
|
|
|
|
|
} |
42
|
5
|
|
|
|
|
13
|
$options->{$item} = 1; |
43
|
|
|
|
|
|
|
} |
44
|
4
|
|
|
|
|
10
|
$Acme::Sub::Parms::line_counter = 0; |
45
|
4
|
|
|
|
|
9
|
my $ref = {'options' => $options, 'bind_block' => 0 }; |
46
|
4
|
|
|
|
|
13
|
filter_add(bless $ref); # imported from Filter::Util::Call |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
#### |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub _parse_bind_spec { |
52
|
28
|
|
|
28
|
|
40
|
my ($self, $raw_spec) = @_; |
53
|
|
|
|
|
|
|
|
54
|
28
|
|
|
|
|
36
|
my $spec = $raw_spec; |
55
|
|
|
|
|
|
|
|
56
|
28
|
|
|
|
|
62
|
my $spec_tokens = { |
57
|
|
|
|
|
|
|
'is_defined' => 0, |
58
|
|
|
|
|
|
|
'required' => 1, |
59
|
|
|
|
|
|
|
'optional' => 0, |
60
|
|
|
|
|
|
|
}; |
61
|
28
|
|
|
|
|
66
|
while ($spec ne '') { |
62
|
56
|
100
|
|
|
|
291
|
if ($spec =~ s/^required(\s*,\s*|$)//) { # 'required' flag |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
63
|
8
|
|
|
|
|
13
|
$spec_tokens->{'required'} = 1; |
64
|
8
|
|
|
|
|
16
|
$spec_tokens->{'optional'} = 0; |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
} elsif ($spec =~ s/^optional(\s*,\s*|$)//) { # 'optional' flag |
67
|
16
|
|
|
|
|
36
|
$spec_tokens->{'required'} = 0; |
68
|
16
|
|
|
|
|
32
|
$spec_tokens->{'optional'} = 1; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
} elsif ($spec =~ s/^is_defined(\s*,\s*|$)//) { # 'is_defined' flag |
71
|
8
|
|
|
|
|
18
|
$spec_tokens->{'is_defined'} = 1; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
} elsif ($spec =~ s/^(can|isa|type|callback|default)\s*=\s*//) { # 'something="somevalue"' |
74
|
24
|
|
|
|
|
53
|
my $spec_key = $1; |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# Simple unquoted text with no embedded ws |
77
|
24
|
100
|
|
|
|
128
|
if ($spec =~ s/^([^\s"',]+)(\s*,\s*|$)//) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
78
|
20
|
|
|
|
|
67
|
$spec_tokens->{$spec_key} = $1; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# Single quoted text with no embedded quotes |
81
|
|
|
|
|
|
|
} elsif ($spec =~ s/^'([^'\/]+)'\s*,\s*//) { |
82
|
0
|
|
|
|
|
0
|
$spec_tokens->{$spec_key} = "'$1'"; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# Double quoted text with no embedded quotes or escapes |
85
|
|
|
|
|
|
|
} elsif ($spec =~ s/^"([^"\/]+)"\s*,\s*//) { |
86
|
0
|
|
|
|
|
0
|
$spec_tokens->{$spec_key} = '"' . $1 . '"'; |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# It is a tricky case with quoted characters. One character at a time it is. |
89
|
|
|
|
|
|
|
} elsif ($spec =~ s/^(['"])//) { |
90
|
4
|
|
|
|
|
10
|
my $quote = $1; |
91
|
4
|
|
|
|
|
8
|
my $upend_spec = reverse $spec; |
92
|
4
|
|
|
|
|
8
|
my $block_done = 0; |
93
|
4
|
|
|
|
|
4
|
my $escape_next = 0; |
94
|
4
|
|
|
|
|
8
|
my $token = $quote; |
95
|
4
|
|
66
|
|
|
50
|
until ($block_done || ($upend_spec eq '')) { |
96
|
32
|
|
|
|
|
61
|
my $ch = chop $upend_spec; |
97
|
32
|
50
|
33
|
|
|
88
|
if ($escape_next) { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
98
|
0
|
|
|
|
|
0
|
$token .= $ch; |
99
|
0
|
|
|
|
|
0
|
$escape_next = 0; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
} elsif (($ch eq "\\") && (not $escape_next)) { |
102
|
0
|
|
|
|
|
0
|
$token .= $ch; |
103
|
0
|
|
|
|
|
0
|
$escape_next = 1; |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
} elsif ($ch eq $quote) { |
106
|
4
|
|
|
|
|
12
|
$block_done = 1; |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
} else { |
109
|
28
|
|
|
|
|
74
|
$token .= $ch; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
} |
112
|
4
|
50
|
|
|
|
10
|
if ($escape_next) { |
113
|
0
|
|
|
|
|
0
|
die("Syntax error in BindParms spec: $raw_spec\n"); |
114
|
|
|
|
|
|
|
} |
115
|
4
|
|
|
|
|
8
|
$spec = reverse $upend_spec; |
116
|
4
|
|
|
|
|
25
|
$spec_tokens->{$spec_key} = $token . $quote; |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
} else { |
119
|
0
|
|
|
|
|
0
|
die("Syntax error in BindParms spec: $raw_spec\n"); |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
} else { |
122
|
0
|
|
|
|
|
0
|
die("Syntax error in BindParms spec: $raw_spec\n"); |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
} |
125
|
28
|
|
|
|
|
57
|
return $spec_tokens; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
############################################################################### |
129
|
|
|
|
|
|
|
# bind_spec is intentionally a a non-POD documented'public' method. It can be overridden in a sub-class |
130
|
|
|
|
|
|
|
# to provide alternative features. |
131
|
|
|
|
|
|
|
# |
132
|
|
|
|
|
|
|
# It takes two parameters: |
133
|
|
|
|
|
|
|
# |
134
|
|
|
|
|
|
|
# $raw_spec - this is the content of the [....] block (not including the '[' and ']' block delimitters) |
135
|
|
|
|
|
|
|
# $field_name - the hash key for the field being processed |
136
|
|
|
|
|
|
|
# |
137
|
|
|
|
|
|
|
# As each line of the BindParms block is processed the two parameters for each line are passed to the bind_spec |
138
|
|
|
|
|
|
|
# method for evaluation. bind_spec should return a string containing any Perl code generated as a result of |
139
|
|
|
|
|
|
|
# the bind specification. |
140
|
|
|
|
|
|
|
# |
141
|
|
|
|
|
|
|
# Good style dictates that the returned output should be *ONE* line (it could be a very *long* line) |
142
|
|
|
|
|
|
|
# so that line numbering in the source file is preserved for any error messages. |
143
|
|
|
|
|
|
|
# |
144
|
|
|
|
|
|
|
sub bind_spec { |
145
|
28
|
|
|
28
|
0
|
34
|
my $self = shift; |
146
|
28
|
|
|
|
|
43
|
my ($raw_spec, $field_name) = @_; |
147
|
|
|
|
|
|
|
|
148
|
28
|
|
|
|
|
36
|
my $options = $self->{'options'}; |
149
|
28
|
|
|
|
|
42
|
my $no_validation = $options->{_NO_VALIDATION()}; |
150
|
|
|
|
|
|
|
|
151
|
28
|
|
|
|
|
187
|
my $spec_tokens = $self->_parse_bind_spec($raw_spec); |
152
|
|
|
|
|
|
|
|
153
|
28
|
|
|
|
|
34
|
my $has_side_effects = 0; |
154
|
28
|
|
|
|
|
32
|
my $output = ''; |
155
|
|
|
|
|
|
|
|
156
|
28
|
|
|
|
|
93
|
my @spec_tokens_list = keys %$spec_tokens; |
157
|
28
|
0
|
33
|
|
|
89
|
if ((0 == @spec_tokens_list) || ((1 == @spec_tokens_list) && ($spec_tokens->{'optional'}))) { |
|
|
|
33
|
|
|
|
|
158
|
0
|
|
|
|
|
0
|
return; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
###################### |
162
|
|
|
|
|
|
|
# default="some value" |
163
|
28
|
100
|
|
|
|
56
|
if (defined $spec_tokens->{'default'}) { |
164
|
4
|
50
|
|
|
|
12
|
if ($spec_tokens->{'optional'}) { |
165
|
4
|
|
|
|
|
30
|
$output .= "unless (exists (\$Acme::Sub::Parms::args\{'$field_name'\})) \{ \$Acme::Sub::Parms::args\{'$field_name'\} = " . $spec_tokens->{'default'} . ";\} "; |
166
|
|
|
|
|
|
|
} else { # required |
167
|
0
|
|
|
|
|
0
|
$output .= "unless (defined (\$Acme::Sub::Parms::args\{'$field_name'\})) \{ \$Acme::Sub::Parms::args\{'$field_name'\} = " . $spec_tokens->{'default'} . ";\} "; |
168
|
|
|
|
|
|
|
} |
169
|
4
|
|
|
|
|
8
|
$has_side_effects = 1; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
###################### |
173
|
|
|
|
|
|
|
# callback="some_subroutine" |
174
|
28
|
100
|
|
|
|
45
|
if ($spec_tokens->{'callback'}) { |
175
|
|
|
|
|
|
|
$output .= "\{ my (\$callback_is_valid, \$callback_error) = " |
176
|
8
|
|
|
|
|
59
|
. $spec_tokens->{'callback'} |
177
|
|
|
|
|
|
|
. "(\'$field_name\', \$Acme::Sub::Parms::args\{\'$field_name\'\}, \\\%Acme::Sub::Parms::args);" |
178
|
|
|
|
|
|
|
. "unless (\$callback_is_valid) { require Carp; Carp::croak(\"$field_name error: \$callback_error\"); }} "; |
179
|
8
|
|
|
|
|
14
|
$has_side_effects = 1; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
###################### |
183
|
|
|
|
|
|
|
# required |
184
|
28
|
100
|
100
|
|
|
89
|
if ((! $no_validation) && $spec_tokens->{'required'}) { |
185
|
4
|
|
|
|
|
20
|
$output .= "unless (exists (\$Acme::Sub::Parms::args\{\'$field_name\'\})) { require Carp; Carp::croak(\"Missing required parameter \'$field_name\'\"); } "; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
###################### |
189
|
|
|
|
|
|
|
# is_defined |
190
|
28
|
100
|
|
|
|
47
|
if ($spec_tokens->{'is_defined'}) { |
191
|
8
|
|
|
|
|
29
|
$output .= "if (exists (\$Acme::Sub::Parms::args\{\'$field_name\'\}) and (! defined (\$Acme::Sub::Parms::args\{\'$field_name\'\}))) { require Carp; Carp::croak(\"parameter \'$field_name\' cannot be undef\"); } "; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
28
|
|
|
|
|
36
|
my $type_requirements = $spec_tokens->{'type'}; |
195
|
28
|
|
|
|
|
37
|
my $isa_requirements = $spec_tokens->{'isa'}; |
196
|
28
|
|
|
|
|
30
|
my $can_requirements = $spec_tokens->{'can'}; |
197
|
|
|
|
|
|
|
|
198
|
28
|
100
|
100
|
|
|
118
|
if (defined ($type_requirements ) || defined($isa_requirements) || defined($can_requirements)) { |
|
|
|
100
|
|
|
|
|
199
|
12
|
|
|
|
|
37
|
$output .= "if (exists (\$Acme::Sub::Parms::args\{\'$field_name\'\})) \{"; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
##################### |
202
|
|
|
|
|
|
|
# type="SomeRefType" or type="SomeRefType, SomeOtherRefType, ..." |
203
|
12
|
100
|
|
|
|
25
|
if (defined $type_requirements) { |
204
|
4
|
|
|
|
|
9
|
$type_requirements =~ s/^['"]//; |
205
|
4
|
|
|
|
|
8
|
$type_requirements =~ s/['"]$//; |
206
|
4
|
|
|
|
|
11
|
my @type_classes = split(/[,\s]+/, $type_requirements); |
207
|
4
|
|
|
|
|
15
|
$output .= "unless ("; |
208
|
4
|
|
|
|
|
8
|
my @type_tests = (); |
209
|
4
|
|
|
|
|
6
|
foreach my $class_name (@type_classes) { |
210
|
4
|
|
|
|
|
14
|
push (@type_tests, "ref(\$Acme::Sub::Parms::args\{'$field_name'\}) eq '$class_name')"); |
211
|
|
|
|
|
|
|
} |
212
|
4
|
|
|
|
|
19
|
$output .= join(' || ',@type_tests) . " \{ require Carp; Carp::croak(\'parameter \\\'$field_name\\\' must be a " . join(' or ',@type_classes) . "\'); \}"; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
##################### |
216
|
|
|
|
|
|
|
# isa="SomeRefType" or isa="SomeRefType, SomeOtherRefType, ..." |
217
|
12
|
100
|
|
|
|
34
|
if (defined $isa_requirements) { |
218
|
4
|
|
|
|
|
17
|
$isa_requirements =~ s/^['"]//; |
219
|
4
|
|
|
|
|
9
|
$isa_requirements =~ s/['"]$//; |
220
|
4
|
|
|
|
|
15
|
my @isa_classes = split(/[,\s]+/, $isa_requirements); |
221
|
4
|
|
|
|
|
8
|
$output .= "unless ("; |
222
|
4
|
|
|
|
|
8
|
my @isa_tests = (); |
223
|
4
|
|
|
|
|
7
|
foreach my $class_name (@isa_classes) { |
224
|
4
|
|
|
|
|
23
|
push (@isa_tests, "\$Acme::Sub::Parms::args\{'$field_name'\}->isa('$class_name')"); |
225
|
|
|
|
|
|
|
} |
226
|
4
|
|
|
|
|
21
|
$output .= join(' || ',@isa_tests) . ") \{ require Carp; Carp::croak(\'parameter \\\'$field_name\\\' must be a " . join(' or ',@isa_classes) . " instance or subclass\'); \}"; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
##################### |
230
|
|
|
|
|
|
|
# can="somemethod" or can="somemethod, someothermethod, ..." |
231
|
12
|
100
|
|
|
|
39
|
if (defined $can_requirements) { |
232
|
4
|
|
|
|
|
13
|
$can_requirements =~ s/^['"]//; |
233
|
4
|
|
|
|
|
18
|
$can_requirements =~ s/['"]$//; |
234
|
4
|
|
|
|
|
22
|
my @can_methods = split(/[,\s]+/, $can_requirements); |
235
|
4
|
|
|
|
|
35
|
$output .= "unless ("; |
236
|
4
|
|
|
|
|
17
|
my @can_tests = (); |
237
|
4
|
|
|
|
|
8
|
foreach my $method_name (@can_methods) { |
238
|
4
|
|
|
|
|
15
|
push (@can_tests, "\$Acme::Sub::Parms::args\{'$field_name'\}->can('$method_name')"); |
239
|
|
|
|
|
|
|
} |
240
|
4
|
|
|
|
|
28
|
$output .= join(' && ',@can_tests) . ") \{ require Carp; Carp::croak(\'parameter \\\'$field_name\\\' must be an object with a " . join(' and a ',@can_methods) . " method\'); \}"; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
12
|
|
|
|
|
19
|
$output .= "\}"; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
28
|
|
|
|
|
132
|
return ($has_side_effects,$output); |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
#### |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub filter { |
252
|
436
|
|
|
436
|
0
|
803
|
my $self = shift; |
253
|
|
|
|
|
|
|
|
254
|
436
|
|
|
|
|
518
|
my $options = $self->{'options'}; |
255
|
436
|
|
|
|
|
597
|
my $dump_to_stdout = $options->{_DUMP()}; |
256
|
436
|
|
|
|
|
570
|
my $normalize = $options->{_NORMALIZE()}; |
257
|
436
|
|
|
|
|
522
|
my $no_validation = $options->{_NO_VALIDATION()}; |
258
|
436
|
|
|
|
|
464
|
my $bind_block = $self->{'bind_block'}; |
259
|
|
|
|
|
|
|
|
260
|
436
|
|
|
|
|
422
|
my $status; |
261
|
|
|
|
|
|
|
|
262
|
436
|
100
|
|
|
|
1430
|
if ($status = filter_read() > 0) { # imported from Filter::Util::Call |
263
|
432
|
|
|
|
|
485
|
$Acme::Sub::Parms::line_counter++; |
264
|
|
|
|
|
|
|
|
265
|
432
|
|
|
|
|
390
|
if (_DEBUG) { |
266
|
|
|
|
|
|
|
print STDERR "input line $Acme::Sub::Parms::line_counter: $_"; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
############################################# |
270
|
|
|
|
|
|
|
# If we are in a bind block, handle it |
271
|
432
|
100
|
|
|
|
539
|
if ($bind_block) { |
272
|
36
|
|
|
|
|
46
|
my $bind_entries = $self->{'bind_entries'}; |
273
|
36
|
|
|
|
|
37
|
my $simple_bind = $self->{'simple_bind'}; |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
############################## |
276
|
|
|
|
|
|
|
# Last line of the bind block? Generate the working code. |
277
|
36
|
100
|
|
|
|
373
|
if (m/^\s*\)(\s*$|\s*#.*$)/) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
278
|
|
|
|
|
|
|
|
279
|
4
|
|
|
|
|
10
|
my $block_trailing_comment = $2; |
280
|
4
|
50
|
|
|
|
13
|
$block_trailing_comment = defined($block_trailing_comment) ? $block_trailing_comment : ''; |
281
|
4
|
|
|
|
|
8
|
$block_trailing_comment =~ s/[\r\n]+$//s; |
282
|
4
|
|
|
|
|
22
|
my $side_effects = 0; |
283
|
4
|
|
|
|
|
7
|
my $args = 'local %Acme::Sub::Parms::args; '; # needed? |
284
|
4
|
100
|
|
|
|
10
|
if ($normalize) { |
285
|
2
|
|
|
|
|
6
|
$args .= '{ local $_; local %Acme::Sub::Parms::raw_args = @_; %Acme::Sub::Parms::args = map { lc($_) => $Acme::Sub::Parms::raw_args{$_} } keys %Acme::Sub::Parms::raw_args; }' . "\n"; |
286
|
|
|
|
|
|
|
} else { |
287
|
2
|
|
|
|
|
7
|
$args .= '%Acme::Sub::Parms::args = @_;' . "\n"; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
# If we have validation or defaults, handle them |
290
|
4
|
|
|
|
|
4
|
my $padding_lines = 0; |
291
|
4
|
50
|
|
|
|
12
|
if (! $simple_bind) { |
292
|
4
|
|
|
|
|
9
|
my @parm_declarations = (); |
293
|
4
|
|
|
|
|
9
|
foreach my $entry (@$bind_entries) { |
294
|
32
|
|
|
|
|
49
|
my $variable_decl = $entry->{'variable'}; |
295
|
32
|
|
|
|
|
41
|
my $field_name = $entry->{'field'}; |
296
|
32
|
|
|
|
|
34
|
my $spec = $entry->{'spec'}; |
297
|
32
|
|
|
|
|
39
|
my $trailing_comment = $entry->{'trailing_comment'}; |
298
|
32
|
100
|
66
|
|
|
129
|
if ( (! defined($spec)) || ($spec eq '')) { |
299
|
|
|
|
|
|
|
# push(@parm_declarations, $trailing_comment); |
300
|
4
|
|
|
|
|
11
|
next; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
# The hard case. We have validation requirements. |
303
|
28
|
|
|
|
|
61
|
my ($has_side_effects, $bind_spec_output) = $self->bind_spec($spec, $field_name); |
304
|
28
|
|
|
|
|
40
|
$side_effects += $has_side_effects; |
305
|
28
|
|
|
|
|
90
|
push (@parm_declarations, "$bind_spec_output$trailing_comment"); |
306
|
|
|
|
|
|
|
} |
307
|
4
|
|
|
|
|
58
|
$args .= join("\n",@parm_declarations,''); |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
# Generate the actual parameter data binding |
311
|
4
|
|
|
|
|
12
|
my @var_declarations = (); |
312
|
4
|
|
|
|
|
6
|
my @hard_var_declarations = (); |
313
|
4
|
|
|
|
|
8
|
my @field_declarations = (); |
314
|
4
|
|
|
|
|
5
|
my @fields_list = (); |
315
|
4
|
|
|
|
|
8
|
foreach my $entry (@$bind_entries) { |
316
|
32
|
|
|
|
|
43
|
my $spec = $entry->{'spec'}; |
317
|
32
|
100
|
66
|
|
|
122
|
next if ((not defined $spec) || ($spec eq '')); |
318
|
28
|
|
|
|
|
35
|
my $raw_var = $entry->{'variable'}; |
319
|
28
|
|
|
|
|
34
|
my $field_name = $entry->{'field'}; |
320
|
|
|
|
|
|
|
|
321
|
28
|
|
|
|
|
57
|
push (@fields_list, "'$field_name'"); |
322
|
28
|
|
|
|
|
110
|
my ($variable_name) = $raw_var =~ m/^my\s+(\S+)$/; |
323
|
28
|
50
|
|
|
|
53
|
if (defined $variable_name) { # simple 'my $variable :' entries are special-cased for performance |
324
|
28
|
|
|
|
|
33
|
push (@var_declarations, $variable_name); |
325
|
28
|
|
|
|
|
61
|
push (@field_declarations, "'$field_name'"); |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
} else { # Otherwise make a seperate entry for this binding |
328
|
0
|
|
|
|
|
0
|
push (@hard_var_declarations, "$raw_var = \$Acme::Sub::Parms::args\{$field_name\};"); |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
} |
331
|
4
|
|
|
|
|
17
|
my $hard_args = join(' ',@hard_var_declarations); |
332
|
4
|
|
|
|
|
6
|
my $arg_line = ''; |
333
|
4
|
50
|
|
|
|
44
|
if (0 < @var_declarations) { |
334
|
|
|
|
|
|
|
|
335
|
4
|
50
|
33
|
|
|
60
|
if ($simple_bind && (! $normalize) && $no_validation && (0 == $side_effects) && (0 == @hard_var_declarations)) { |
|
|
|
33
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
336
|
0
|
|
|
|
|
0
|
$args = "\n my (" . join(",", @var_declarations) . ') = @{{@_}}{' . join(',',@field_declarations) . '}; '; |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
} else { |
339
|
|
|
|
|
|
|
|
340
|
4
|
|
|
|
|
52
|
$arg_line = 'my (' . join(",", @var_declarations) . ') = @Acme::Sub::Parms::args{' . join(',',@field_declarations) . '}; '; |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
} |
343
|
4
|
|
|
|
|
11
|
my $unknown_parms_check = ''; |
344
|
4
|
100
|
|
|
|
13
|
unless ($no_validation) { |
345
|
2
|
|
|
|
|
13
|
$unknown_parms_check = 'delete @Acme::Sub::Parms::args{' . join(',',@fields_list) . '}; if (0 < @Acme::Sub::Parms::args) { require Carp; Carp::croak(\'Unexpected parameters passed: \' . join(\', \',@Acme::Sub::Parms::args)); } '; |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
} |
348
|
4
|
|
|
|
|
10
|
$self->{'bind_block'} = 0; |
349
|
4
|
|
|
|
|
8
|
my $original_block_length = $Acme::Sub::Parms::line_counter - $self->{'line_block_start'}; |
350
|
4
|
|
|
|
|
43
|
my $new_block = $args . join(' ',$arg_line, $hard_args, $unknown_parms_check) . "$block_trailing_comment\n"; |
351
|
4
|
|
|
|
|
65
|
$new_block =~ s/\n+/\n/gs; |
352
|
4
|
|
|
|
|
19
|
my $new_block_lines = $new_block =~ m/\n/gs; |
353
|
|
|
|
|
|
|
|
354
|
4
|
|
|
|
|
8
|
my $additional_lines = $original_block_length - $new_block_lines; |
355
|
|
|
|
|
|
|
#warn("Need $additional_lines extra lines\n---\n$new_block---\n"); |
356
|
4
|
50
|
|
|
|
23
|
if ($additional_lines > 0) { |
357
|
4
|
|
|
|
|
65
|
$_ = $new_block . ("\n" x $additional_lines); |
358
|
|
|
|
|
|
|
} else { |
359
|
0
|
|
|
|
|
0
|
$_ = $new_block; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
######################## |
363
|
|
|
|
|
|
|
# Bind block parameter line |
364
|
|
|
|
|
|
|
} elsif (my($bind_var, $bind_field,$trailing_comment) = m/^\s*(\S.*?)\s+:\s+([^'"\s\[]+.*?)\s*(;\s*|;\s*#.*)$/) { |
365
|
28
|
50
|
|
|
|
72
|
$trailing_comment = defined($trailing_comment) ? $trailing_comment : ''; |
366
|
28
|
|
|
|
|
90
|
$trailing_comment =~ s/[\r\n]+$//s; |
367
|
28
|
|
|
|
|
64
|
$trailing_comment =~ s/^;//; |
368
|
28
|
|
|
|
|
110
|
my $bind_entry = { 'variable' => $bind_var, 'field' => $bind_field, trailing_comment => $trailing_comment }; |
369
|
28
|
|
|
|
|
50
|
push (@$bind_entries, $bind_entry); |
370
|
28
|
50
|
|
|
|
88
|
if ($bind_var !~ m/^my \$\S+$/) { |
371
|
0
|
|
|
|
|
0
|
$self->{'simple_bind'} = 0; |
372
|
|
|
|
|
|
|
} |
373
|
28
|
100
|
|
|
|
97
|
if ($bind_field =~ m/^(\S+)\s*\[(.*)\]$/) { # Complex spec |
|
|
50
|
|
|
|
|
|
374
|
26
|
|
|
|
|
62
|
$bind_entry->{'field'} = $1; |
375
|
26
|
|
|
|
|
68
|
$bind_entry->{'spec'} = $2; |
376
|
26
|
100
|
100
|
|
|
119
|
unless ($no_validation && ($bind_field !~ m/[\s\[,](default|callback)\s*=\s*/)) { |
377
|
18
|
|
|
|
|
26
|
$self->{'simple_bind'} = 0; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
} elsif ($bind_field =~ m/^\w+$/) { # my $thing : something; |
380
|
2
|
|
|
|
|
4
|
$bind_entry->{'spec'} = 'required'; |
381
|
2
|
50
|
|
|
|
7
|
unless ($no_validation) { |
382
|
0
|
|
|
|
|
0
|
$self->{'simple_bind'} = 0; |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
} else { |
385
|
0
|
|
|
|
|
0
|
die("Failed to parse BindParms block line $Acme::Sub::Parms::line_counter: $_"); |
386
|
|
|
|
|
|
|
} |
387
|
28
|
|
|
|
|
53
|
undef $trailing_comment; |
388
|
28
|
|
|
|
|
33
|
undef $bind_var; |
389
|
28
|
|
|
|
|
64
|
undef $bind_field; |
390
|
28
|
|
|
|
|
60
|
$_ = ''; |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
############################ |
393
|
|
|
|
|
|
|
# Blank and comment only lines |
394
|
|
|
|
|
|
|
} elsif (m/^(\s*|\s*#.*)$/) { |
395
|
4
|
|
|
|
|
22
|
my $trailing_comment = $1; |
396
|
4
|
50
|
|
|
|
14
|
$trailing_comment = defined ($trailing_comment) ? $trailing_comment : ''; |
397
|
4
|
|
|
|
|
15
|
$trailing_comment =~ s/[\r\n]+$//s; |
398
|
|
|
|
|
|
|
|
399
|
4
|
|
|
|
|
12
|
my $bind_entry = { spec => '', trailing_comment => $trailing_comment}; |
400
|
4
|
|
|
|
|
8
|
push (@$bind_entries, $bind_entry); |
401
|
4
|
|
|
|
|
8
|
$_ = ''; |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
} else { |
404
|
0
|
|
|
|
|
0
|
die("Failed to parse BindParms block line $Acme::Sub::Parms::line_counter: $_"); |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
} else { # Start of a bind block |
408
|
396
|
100
|
|
|
|
741
|
if (m/^\s*BindParms\s+:\s+\((\s*#.*$|\s*$)/) { |
409
|
4
|
|
|
|
|
12
|
$self->{'simple_bind'} = 1; |
410
|
4
|
|
|
|
|
10
|
$self->{'bind_entries'} = []; |
411
|
4
|
|
|
|
|
8
|
$self->{'bind_block'} = 1; |
412
|
4
|
|
|
|
|
15
|
$self->{'line_block_start'} = $Acme::Sub::Parms::line_counter; |
413
|
4
|
|
|
|
|
23
|
my $block_head_comment = $2; |
414
|
4
|
50
|
|
|
|
26
|
$block_head_comment = defined ($block_head_comment) ? $block_head_comment : ''; |
415
|
4
|
|
|
|
|
8
|
$block_head_comment =~ s/[\r\n]+$//s; |
416
|
4
|
|
|
|
|
9
|
$_ = $block_head_comment; |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
####### |
419
|
|
|
|
|
|
|
# ################################ |
420
|
|
|
|
|
|
|
# # Invokation : $self; |
421
|
|
|
|
|
|
|
# } elsif (my ($ihead,$ivar,$itail) = m/^(\s*)Invokation\s+:\s+(\S+.*?)\s*;(.*)$/) { |
422
|
|
|
|
|
|
|
# $_ = $ihead . " my $ivar = shift @_;$itail\n"; |
423
|
|
|
|
|
|
|
# |
424
|
|
|
|
|
|
|
# ################################ |
425
|
|
|
|
|
|
|
# # ParmsHash : %args; |
426
|
|
|
|
|
|
|
# } elsif (my ($fhead,$func_hash_ident,$ftail) = m/^(\s*)ParmsHash\s+:\s+(\S+.*?)\s*;(.*)$/) { |
427
|
|
|
|
|
|
|
# if ($normalize) { |
428
|
|
|
|
|
|
|
# $_ = "${fhead}my $func_hash_ident; { local \%Acme::Sub::Parms::raw_args = \@\_; $func_hash_ident = map \{ lc(\$\_\) \=\> \$Acme::Sub::Parms::raw_args\{\$\_\} \} keys \%Acme::Sub::Parms::raw_args; } $ftail\n"; |
429
|
|
|
|
|
|
|
# } else { |
430
|
|
|
|
|
|
|
# $_ = "${fhead}my $func_hash_ident = \@\_;$ftail\n"; |
431
|
|
|
|
|
|
|
# } |
432
|
|
|
|
|
|
|
# |
433
|
|
|
|
|
|
|
# ################################ |
434
|
|
|
|
|
|
|
# # MethodParms : $self, %args; |
435
|
|
|
|
|
|
|
# } elsif (my ($mhead,$method_invokation,$method_hash_ident,$mtail) = m/^(\s*)MethodParms\s+:\s+(\S+.*?)\s*,\s*(\S+.*?)\s*;(.*)$/) { |
436
|
|
|
|
|
|
|
# if ($normalize) { |
437
|
|
|
|
|
|
|
# $_ = "${mhead}my $method_invokation = shift; my $method_hash_ident; { local \$_; local \%Acme::Sub::Parms::raw_args = \@\_; $method_hash_ident = map \{ lc(\$\_\) \=\> \$Acme::Sub::Parms::raw_args\{\$\_\} \} keys \%Acme::Sub::Parms::raw_args; } $mtail\n"; |
438
|
|
|
|
|
|
|
# } else { |
439
|
|
|
|
|
|
|
# $_ = "${mhead}my $method_invokation = shift; my $method_hash_ident = \@\_; $mtail\n"; |
440
|
|
|
|
|
|
|
# } |
441
|
|
|
|
|
|
|
####### |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
} |
445
|
436
|
|
|
|
|
413
|
if (_DEBUG) { |
446
|
|
|
|
|
|
|
print STDERR "output as: $_"; |
447
|
|
|
|
|
|
|
} |
448
|
436
|
100
|
|
|
|
562
|
if ($dump_to_stdout) { print $_; } |
|
110
|
|
|
|
|
154
|
|
449
|
|
|
|
|
|
|
|
450
|
436
|
|
|
|
|
11578
|
return $status; |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
#### |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
1; |
456
|
|
|
|
|
|
|
|