line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Acme::Sub::Parms; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
11894
|
use strict; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
167
|
|
4
|
4
|
|
|
4
|
|
4556
|
use Filter::Util::Call; |
|
4
|
|
|
|
|
5985
|
|
|
4
|
|
|
|
|
624
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
BEGIN { |
7
|
4
|
|
|
4
|
|
10
|
$Acme::Sub::Parms::VERSION = '1.02'; |
8
|
4
|
|
|
|
|
26
|
%Acme::Sub::Parms::args = (); |
9
|
4
|
|
|
|
|
10
|
%Acme::Sub::Parms::raw_args = (); |
10
|
4
|
|
|
|
|
21499
|
$Acme::Sub::Parms::line_counter = 0; |
11
|
|
|
|
|
|
|
} |
12
|
|
|
|
|
|
|
|
13
|
445
|
|
|
445
|
|
801
|
sub _NORMALIZE () { return ':normalize'; }; |
14
|
473
|
|
|
473
|
|
904
|
sub _NO_VALIDATION () { return ':no_validation'; }; |
15
|
445
|
|
|
445
|
|
1031
|
sub _DUMP () { return ':dump_to_stdout'; }; |
16
|
|
|
|
|
|
|
sub _DEBUG () { 0; }; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub _legal_option { |
19
|
|
|
|
|
|
|
return { |
20
|
5
|
|
|
5
|
|
10
|
_NORMALIZE() => 1, |
21
|
|
|
|
|
|
|
_NO_VALIDATION() => 1, |
22
|
|
|
|
|
|
|
_DUMP() => 1, |
23
|
|
|
|
|
|
|
}->{$_[0]}; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
#### |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub import { |
29
|
4
|
|
|
4
|
|
67
|
local $^W = 1; # We _like_ warnings |
30
|
4
|
|
|
|
|
13
|
my $class = shift; |
31
|
4
|
|
|
|
|
21
|
my $options = { |
32
|
|
|
|
|
|
|
_NORMALIZE() => 0, |
33
|
|
|
|
|
|
|
_NO_VALIDATION() => 0, |
34
|
|
|
|
|
|
|
_DUMP() => 0, |
35
|
|
|
|
|
|
|
}; |
36
|
4
|
|
|
|
|
21
|
foreach my $item (@_) { |
37
|
5
|
50
|
|
|
|
15
|
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
|
|
|
|
|
25
|
$options->{$item} = 1; |
43
|
|
|
|
|
|
|
} |
44
|
4
|
|
|
|
|
9
|
$Acme::Sub::Parms::line_counter = 0; |
45
|
4
|
|
|
|
|
19
|
my $ref = {'options' => $options, 'bind_block' => 0 }; |
46
|
4
|
|
|
|
|
26
|
filter_add(bless $ref); # imported from Filter::Util::Call |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
#### |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub _parse_bind_spec { |
52
|
28
|
|
|
28
|
|
39
|
my ($self, $raw_spec) = @_; |
53
|
|
|
|
|
|
|
|
54
|
28
|
|
|
|
|
40
|
my $spec = $raw_spec; |
55
|
|
|
|
|
|
|
|
56
|
28
|
|
|
|
|
83
|
my $spec_tokens = { |
57
|
|
|
|
|
|
|
'is_defined' => 0, |
58
|
|
|
|
|
|
|
'required' => 1, |
59
|
|
|
|
|
|
|
'optional' => 0, |
60
|
|
|
|
|
|
|
}; |
61
|
28
|
|
|
|
|
77
|
while ($spec ne '') { |
62
|
56
|
100
|
|
|
|
5653
|
if ($spec =~ s/^required(\s*,\s*|$)//) { # 'required' flag |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
63
|
8
|
|
|
|
|
15
|
$spec_tokens->{'required'} = 1; |
64
|
8
|
|
|
|
|
25
|
$spec_tokens->{'optional'} = 0; |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
} elsif ($spec =~ s/^optional(\s*,\s*|$)//) { # 'optional' flag |
67
|
16
|
|
|
|
|
24
|
$spec_tokens->{'required'} = 0; |
68
|
16
|
|
|
|
|
42
|
$spec_tokens->{'optional'} = 1; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
} elsif ($spec =~ s/^is_defined(\s*,\s*|$)//) { # 'is_defined' flag |
71
|
8
|
|
|
|
|
25
|
$spec_tokens->{'is_defined'} = 1; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
} elsif ($spec =~ s/^(can|isa|type|callback|default)\s*=\s*//) { # 'something="somevalue"' |
74
|
24
|
|
|
|
|
45
|
my $spec_key = $1; |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# Simple unquoted text with no embedded ws |
77
|
24
|
100
|
|
|
|
313
|
if ($spec =~ s/^([^\s"',]+)(\s*,\s*|$)//) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
78
|
20
|
|
|
|
|
101
|
$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
|
|
|
|
|
11
|
my $quote = $1; |
91
|
4
|
|
|
|
|
18
|
my $upend_spec = reverse $spec; |
92
|
4
|
|
|
|
|
18
|
my $block_done = 0; |
93
|
4
|
|
|
|
|
7
|
my $escape_next = 0; |
94
|
4
|
|
|
|
|
8
|
my $token = $quote; |
95
|
4
|
|
66
|
|
|
82
|
until ($block_done || ($upend_spec eq '')) { |
96
|
32
|
|
|
|
|
52
|
my $ch = chop $upend_spec; |
97
|
32
|
50
|
33
|
|
|
119
|
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
|
|
|
|
|
18
|
$block_done = 1; |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
} else { |
109
|
28
|
|
|
|
|
111
|
$token .= $ch; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
} |
112
|
4
|
50
|
|
|
|
15
|
if ($escape_next) { |
113
|
0
|
|
|
|
|
0
|
die("Syntax error in BindParms spec: $raw_spec\n"); |
114
|
|
|
|
|
|
|
} |
115
|
4
|
|
|
|
|
10
|
$spec = reverse $upend_spec; |
116
|
4
|
|
|
|
|
23
|
$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
|
|
|
|
|
58
|
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
|
150
|
my $self = shift; |
146
|
28
|
|
|
|
|
46
|
my ($raw_spec, $field_name) = @_; |
147
|
|
|
|
|
|
|
|
148
|
28
|
|
|
|
|
80
|
my $options = $self->{'options'}; |
149
|
28
|
|
|
|
|
53
|
my $no_validation = $options->{_NO_VALIDATION()}; |
150
|
|
|
|
|
|
|
|
151
|
28
|
|
|
|
|
91
|
my $spec_tokens = $self->_parse_bind_spec($raw_spec); |
152
|
|
|
|
|
|
|
|
153
|
28
|
|
|
|
|
55
|
my $has_side_effects = 0; |
154
|
28
|
|
|
|
|
35
|
my $output = ''; |
155
|
|
|
|
|
|
|
|
156
|
28
|
|
|
|
|
305
|
my @spec_tokens_list = keys %$spec_tokens; |
157
|
28
|
50
|
33
|
|
|
146
|
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
|
|
|
|
73
|
if (defined $spec_tokens->{'default'}) { |
164
|
4
|
50
|
|
|
|
26
|
if ($spec_tokens->{'optional'}) { |
165
|
4
|
|
|
|
|
25
|
$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
|
|
|
|
|
7
|
$has_side_effects = 1; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
###################### |
173
|
|
|
|
|
|
|
# callback="some_subroutine" |
174
|
28
|
100
|
|
|
|
63
|
if ($spec_tokens->{'callback'}) { |
175
|
8
|
|
|
|
|
60
|
$output .= "\{ my (\$callback_is_valid, \$callback_error) = " |
176
|
|
|
|
|
|
|
. $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
|
|
|
|
|
13
|
$has_side_effects = 1; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
###################### |
183
|
|
|
|
|
|
|
# required |
184
|
28
|
100
|
100
|
|
|
98
|
if ((! $no_validation) && $spec_tokens->{'required'}) { |
185
|
4
|
|
|
|
|
25
|
$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
|
|
|
|
324
|
if ($spec_tokens->{'is_defined'}) { |
191
|
8
|
|
|
|
|
32
|
$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
|
|
|
|
|
45
|
my $type_requirements = $spec_tokens->{'type'}; |
195
|
28
|
|
|
|
|
41
|
my $isa_requirements = $spec_tokens->{'isa'}; |
196
|
28
|
|
|
|
|
38
|
my $can_requirements = $spec_tokens->{'can'}; |
197
|
|
|
|
|
|
|
|
198
|
28
|
100
|
100
|
|
|
188
|
if (defined ($type_requirements ) || defined($isa_requirements) || defined($can_requirements)) { |
|
|
|
100
|
|
|
|
|
199
|
12
|
|
|
|
|
39
|
$output .= "if (exists (\$Acme::Sub::Parms::args\{\'$field_name\'\})) \{"; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
##################### |
202
|
|
|
|
|
|
|
# type="SomeRefType" or type="SomeRefType, SomeOtherRefType, ..." |
203
|
12
|
100
|
|
|
|
36
|
if (defined $type_requirements) { |
204
|
4
|
|
|
|
|
12
|
$type_requirements =~ s/^['"]//; |
205
|
4
|
|
|
|
|
22
|
$type_requirements =~ s/['"]$//; |
206
|
4
|
|
|
|
|
15
|
my @type_classes = split(/[,\s]+/, $type_requirements); |
207
|
4
|
|
|
|
|
10
|
$output .= "unless ("; |
208
|
4
|
|
|
|
|
7
|
my @type_tests = (); |
209
|
4
|
|
|
|
|
9
|
foreach my $class_name (@type_classes) { |
210
|
4
|
|
|
|
|
30
|
push (@type_tests, "ref(\$Acme::Sub::Parms::args\{'$field_name'\}) eq '$class_name')"); |
211
|
|
|
|
|
|
|
} |
212
|
4
|
|
|
|
|
24
|
$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
|
|
|
|
31
|
if (defined $isa_requirements) { |
218
|
4
|
|
|
|
|
19
|
$isa_requirements =~ s/^['"]//; |
219
|
4
|
|
|
|
|
10
|
$isa_requirements =~ s/['"]$//; |
220
|
4
|
|
|
|
|
18
|
my @isa_classes = split(/[,\s]+/, $isa_requirements); |
221
|
4
|
|
|
|
|
11
|
$output .= "unless ("; |
222
|
4
|
|
|
|
|
13
|
my @isa_tests = (); |
223
|
4
|
|
|
|
|
18
|
foreach my $class_name (@isa_classes) { |
224
|
4
|
|
|
|
|
18
|
push (@isa_tests, "\$Acme::Sub::Parms::args\{'$field_name'\}->isa('$class_name')"); |
225
|
|
|
|
|
|
|
} |
226
|
4
|
|
|
|
|
30
|
$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
|
|
|
|
28
|
if (defined $can_requirements) { |
232
|
4
|
|
|
|
|
15
|
$can_requirements =~ s/^['"]//; |
233
|
4
|
|
|
|
|
12
|
$can_requirements =~ s/['"]$//; |
234
|
4
|
|
|
|
|
24
|
my @can_methods = split(/[,\s]+/, $can_requirements); |
235
|
4
|
|
|
|
|
10
|
$output .= "unless ("; |
236
|
4
|
|
|
|
|
10
|
my @can_tests = (); |
237
|
4
|
|
|
|
|
18
|
foreach my $method_name (@can_methods) { |
238
|
4
|
|
|
|
|
19
|
push (@can_tests, "\$Acme::Sub::Parms::args\{'$field_name'\}->can('$method_name')"); |
239
|
|
|
|
|
|
|
} |
240
|
4
|
|
|
|
|
49
|
$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
|
|
|
|
|
21
|
$output .= "\}"; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
28
|
|
|
|
|
142
|
return ($has_side_effects,$output); |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
#### |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub filter { |
252
|
436
|
|
|
436
|
0
|
1436
|
local $^W = 1; # We _like_ warnings |
253
|
436
|
|
|
|
|
556
|
my $self = shift; |
254
|
|
|
|
|
|
|
|
255
|
436
|
|
|
|
|
748
|
my $options = $self->{'options'}; |
256
|
436
|
|
|
|
|
967
|
my $dump_to_stdout = $options->{_DUMP()}; |
257
|
436
|
|
|
|
|
774
|
my $normalize = $options->{_NORMALIZE()}; |
258
|
436
|
|
|
|
|
715
|
my $no_validation = $options->{_NO_VALIDATION()}; |
259
|
436
|
|
|
|
|
669
|
my $bind_block = $self->{'bind_block'}; |
260
|
|
|
|
|
|
|
|
261
|
436
|
|
|
|
|
467
|
my $status; |
262
|
|
|
|
|
|
|
|
263
|
436
|
100
|
|
|
|
2992
|
if ($status = filter_read() > 0) { # imported from Filter::Util::Call |
264
|
432
|
|
|
|
|
484
|
$Acme::Sub::Parms::line_counter++; |
265
|
|
|
|
|
|
|
|
266
|
432
|
|
|
|
|
387
|
if (_DEBUG) { |
267
|
|
|
|
|
|
|
print STDERR "input line $Acme::Sub::Parms::line_counter: $_"; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
############################################# |
271
|
|
|
|
|
|
|
# If we are in a bind block, handle it |
272
|
432
|
100
|
|
|
|
687
|
if ($bind_block) { |
273
|
36
|
|
|
|
|
56
|
my $bind_entries = $self->{'bind_entries'}; |
274
|
36
|
|
|
|
|
50
|
my $simple_bind = $self->{'simple_bind'}; |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
############################## |
277
|
|
|
|
|
|
|
# Last line of the bind block? Generate the working code. |
278
|
36
|
100
|
|
|
|
470
|
if (m/^\s*\)(\s*$|\s*#.*$)/) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
279
|
|
|
|
|
|
|
|
280
|
4
|
|
|
|
|
12
|
my $block_trailing_comment = $2; |
281
|
4
|
50
|
|
|
|
25
|
$block_trailing_comment = defined($block_trailing_comment) ? $block_trailing_comment : ''; |
282
|
4
|
|
|
|
|
14
|
$block_trailing_comment =~ s/[\r\n]+$//s; |
283
|
4
|
|
|
|
|
9
|
my $side_effects = 0; |
284
|
4
|
|
|
|
|
9
|
my $args = 'local %Acme::Sub::Parms::args; '; # needed? |
285
|
4
|
100
|
|
|
|
13
|
if ($normalize) { |
286
|
2
|
|
|
|
|
7
|
$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"; |
287
|
|
|
|
|
|
|
} else { |
288
|
2
|
|
|
|
|
5
|
$args .= '%Acme::Sub::Parms::args = @_;' . "\n"; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
# If we have validation or defaults, handle them |
291
|
4
|
|
|
|
|
9
|
my $padding_lines = 0; |
292
|
4
|
50
|
|
|
|
14
|
if (! $simple_bind) { |
293
|
4
|
|
|
|
|
8
|
my @parm_declarations = (); |
294
|
4
|
|
|
|
|
12
|
foreach my $entry (@$bind_entries) { |
295
|
32
|
|
|
|
|
70
|
my $variable_decl = $entry->{'variable'}; |
296
|
32
|
|
|
|
|
43
|
my $field_name = $entry->{'field'}; |
297
|
32
|
|
|
|
|
191
|
my $spec = $entry->{'spec'}; |
298
|
32
|
|
|
|
|
141
|
my $trailing_comment = $entry->{'trailing_comment'}; |
299
|
32
|
100
|
66
|
|
|
190
|
if ( (! defined($spec)) || ($spec eq '')) { |
300
|
|
|
|
|
|
|
# push(@parm_declarations, $trailing_comment); |
301
|
4
|
|
|
|
|
13
|
next; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
# The hard case. We have validation requirements. |
304
|
28
|
|
|
|
|
88
|
my ($has_side_effects, $bind_spec_output) = $self->bind_spec($spec, $field_name); |
305
|
28
|
|
|
|
|
56
|
$side_effects += $has_side_effects; |
306
|
28
|
|
|
|
|
82
|
push (@parm_declarations, "$bind_spec_output$trailing_comment"); |
307
|
|
|
|
|
|
|
} |
308
|
4
|
|
|
|
|
55
|
$args .= join("\n",@parm_declarations,''); |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# Generate the actual parameter data binding |
312
|
4
|
|
|
|
|
10
|
my @var_declarations = (); |
313
|
4
|
|
|
|
|
10
|
my @hard_var_declarations = (); |
314
|
4
|
|
|
|
|
8
|
my @field_declarations = (); |
315
|
4
|
|
|
|
|
9
|
my @fields_list = (); |
316
|
4
|
|
|
|
|
10
|
foreach my $entry (@$bind_entries) { |
317
|
32
|
|
|
|
|
61
|
my $spec = $entry->{'spec'}; |
318
|
32
|
100
|
66
|
|
|
159
|
next if ((not defined $spec) || ($spec eq '')); |
319
|
28
|
|
|
|
|
46
|
my $raw_var = $entry->{'variable'}; |
320
|
28
|
|
|
|
|
37
|
my $field_name = $entry->{'field'}; |
321
|
|
|
|
|
|
|
|
322
|
28
|
|
|
|
|
56
|
push (@fields_list, "'$field_name'"); |
323
|
28
|
|
|
|
|
105
|
my ($variable_name) = $raw_var =~ m/^my\s+(\S+)$/; |
324
|
28
|
50
|
|
|
|
52
|
if (defined $variable_name) { # simple 'my $variable :' entries are special-cased for performance |
325
|
28
|
|
|
|
|
62
|
push (@var_declarations, $variable_name); |
326
|
28
|
|
|
|
|
83
|
push (@field_declarations, "'$field_name'"); |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
} else { # Otherwise make a seperate entry for this binding |
329
|
0
|
|
|
|
|
0
|
push (@hard_var_declarations, "$raw_var = \$Acme::Sub::Parms::args\{$field_name\};"); |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
} |
332
|
4
|
|
|
|
|
12
|
my $hard_args = join(' ',@hard_var_declarations); |
333
|
4
|
|
|
|
|
9
|
my $arg_line = ''; |
334
|
4
|
50
|
|
|
|
14
|
if (0 < @var_declarations) { |
335
|
|
|
|
|
|
|
|
336
|
4
|
50
|
33
|
|
|
34
|
if ($simple_bind && (! $normalize) && $no_validation && (0 == $side_effects) && (0 == @hard_var_declarations)) { |
|
|
|
33
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
337
|
0
|
|
|
|
|
0
|
$args = "\n my (" . join(",", @var_declarations) . ') = @{{@_}}{' . join(',',@field_declarations) . '}; '; |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
} else { |
340
|
|
|
|
|
|
|
|
341
|
4
|
|
|
|
|
30
|
$arg_line = 'my (' . join(",", @var_declarations) . ') = @Acme::Sub::Parms::args{' . join(',',@field_declarations) . '}; '; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
} |
344
|
4
|
|
|
|
|
10
|
my $unknown_parms_check = ''; |
345
|
4
|
100
|
|
|
|
14
|
unless ($no_validation) { |
346
|
2
|
|
|
|
|
9
|
$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)); } '; |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
} |
349
|
4
|
|
|
|
|
13
|
$self->{'bind_block'} = 0; |
350
|
4
|
|
|
|
|
11
|
my $original_block_length = $Acme::Sub::Parms::line_counter - $self->{'line_block_start'}; |
351
|
4
|
|
|
|
|
53
|
my $new_block = $args . join(' ',$arg_line, $hard_args, $unknown_parms_check) . "$block_trailing_comment\n"; |
352
|
4
|
|
|
|
|
81
|
$new_block =~ s/\n+/\n/gs; |
353
|
4
|
|
|
|
|
20
|
my $new_block_lines = $new_block =~ m/\n/gs; |
354
|
|
|
|
|
|
|
|
355
|
4
|
|
|
|
|
8
|
my $additional_lines = $original_block_length - $new_block_lines; |
356
|
|
|
|
|
|
|
#warn("Need $additional_lines extra lines\n---\n$new_block---\n"); |
357
|
4
|
50
|
|
|
|
14
|
if ($additional_lines > 0) { |
358
|
4
|
|
|
|
|
67
|
$_ = $new_block . ("\n" x $additional_lines); |
359
|
|
|
|
|
|
|
} else { |
360
|
0
|
|
|
|
|
0
|
$_ = $new_block; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
######################## |
364
|
|
|
|
|
|
|
# Bind block parameter line |
365
|
|
|
|
|
|
|
} elsif (my($bind_var, $bind_field,$trailing_comment) = m/^\s*(\S.*?)\s+:\s+([^'"\s\[]+.*?)\s*(;\s*|;\s*#.*)$/) { |
366
|
28
|
50
|
|
|
|
71
|
$trailing_comment = defined($trailing_comment) ? $trailing_comment : ''; |
367
|
28
|
|
|
|
|
16357
|
$trailing_comment =~ s/[\r\n]+$//s; |
368
|
28
|
|
|
|
|
77
|
$trailing_comment =~ s/^;//; |
369
|
28
|
|
|
|
|
984
|
my $bind_entry = { 'variable' => $bind_var, 'field' => $bind_field, trailing_comment => $trailing_comment }; |
370
|
28
|
|
|
|
|
60
|
push (@$bind_entries, $bind_entry); |
371
|
28
|
50
|
|
|
|
235
|
if ($bind_var !~ m/^my \$\S+$/) { |
372
|
0
|
|
|
|
|
0
|
$self->{'simple_bind'} = 0; |
373
|
|
|
|
|
|
|
} |
374
|
28
|
100
|
|
|
|
128
|
if ($bind_field =~ m/^(\S+)\s*\[(.*)\]$/) { # Complex spec |
|
|
50
|
|
|
|
|
|
375
|
26
|
|
|
|
|
75
|
$bind_entry->{'field'} = $1; |
376
|
26
|
|
|
|
|
77
|
$bind_entry->{'spec'} = $2; |
377
|
26
|
100
|
100
|
|
|
140
|
unless ($no_validation && ($bind_field !~ m/[\s\[,](default|callback)\s*=\s*/)) { |
378
|
18
|
|
|
|
|
39
|
$self->{'simple_bind'} = 0; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
} elsif ($bind_field =~ m/^\w+$/) { # my $thing : something; |
381
|
2
|
|
|
|
|
5
|
$bind_entry->{'spec'} = 'required'; |
382
|
2
|
50
|
|
|
|
9
|
unless ($no_validation) { |
383
|
0
|
|
|
|
|
0
|
$self->{'simple_bind'} = 0; |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
} else { |
386
|
0
|
|
|
|
|
0
|
die("Failed to parse BindParms block line $Acme::Sub::Parms::line_counter: $_"); |
387
|
|
|
|
|
|
|
} |
388
|
28
|
|
|
|
|
44
|
undef $trailing_comment; |
389
|
28
|
|
|
|
|
45
|
undef $bind_var; |
390
|
28
|
|
|
|
|
33
|
undef $bind_field; |
391
|
28
|
|
|
|
|
56
|
$_ = ''; |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
############################ |
394
|
|
|
|
|
|
|
# Blank and comment only lines |
395
|
|
|
|
|
|
|
} elsif (m/^(\s*|\s*#.*)$/) { |
396
|
4
|
|
|
|
|
12
|
my $trailing_comment = $1; |
397
|
4
|
50
|
|
|
|
21
|
$trailing_comment = defined ($trailing_comment) ? $trailing_comment : ''; |
398
|
4
|
|
|
|
|
29
|
$trailing_comment =~ s/[\r\n]+$//s; |
399
|
|
|
|
|
|
|
|
400
|
4
|
|
|
|
|
17
|
my $bind_entry = { spec => '', trailing_comment => $trailing_comment}; |
401
|
4
|
|
|
|
|
13
|
push (@$bind_entries, $bind_entry); |
402
|
4
|
|
|
|
|
11
|
$_ = ''; |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
} else { |
405
|
0
|
|
|
|
|
0
|
die("Failed to parse BindParms block line $Acme::Sub::Parms::line_counter: $_"); |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
} else { # Start of a bind block |
409
|
396
|
100
|
|
|
|
1411
|
if (m/^\s*BindParms\s+:\s+\((\s*#.*$|\s*$)/) { |
410
|
4
|
|
|
|
|
14
|
$self->{'simple_bind'} = 1; |
411
|
4
|
|
|
|
|
11
|
$self->{'bind_entries'} = []; |
412
|
4
|
|
|
|
|
24
|
$self->{'bind_block'} = 1; |
413
|
4
|
|
|
|
|
11
|
$self->{'line_block_start'} = $Acme::Sub::Parms::line_counter; |
414
|
4
|
|
|
|
|
15
|
my $block_head_comment = $2; |
415
|
4
|
50
|
|
|
|
17
|
$block_head_comment = defined ($block_head_comment) ? $block_head_comment : ''; |
416
|
4
|
|
|
|
|
9
|
$block_head_comment =~ s/[\r\n]+$//s; |
417
|
4
|
|
|
|
|
9
|
$_ = $block_head_comment; |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
####### |
420
|
|
|
|
|
|
|
# ################################ |
421
|
|
|
|
|
|
|
# # Invokation : $self; |
422
|
|
|
|
|
|
|
# } elsif (my ($ihead,$ivar,$itail) = m/^(\s*)Invokation\s+:\s+(\S+.*?)\s*;(.*)$/) { |
423
|
|
|
|
|
|
|
# $_ = $ihead . " my $ivar = shift @_;$itail\n"; |
424
|
|
|
|
|
|
|
# |
425
|
|
|
|
|
|
|
# ################################ |
426
|
|
|
|
|
|
|
# # ParmsHash : %args; |
427
|
|
|
|
|
|
|
# } elsif (my ($fhead,$func_hash_ident,$ftail) = m/^(\s*)ParmsHash\s+:\s+(\S+.*?)\s*;(.*)$/) { |
428
|
|
|
|
|
|
|
# if ($normalize) { |
429
|
|
|
|
|
|
|
# $_ = "${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"; |
430
|
|
|
|
|
|
|
# } else { |
431
|
|
|
|
|
|
|
# $_ = "${fhead}my $func_hash_ident = \@\_;$ftail\n"; |
432
|
|
|
|
|
|
|
# } |
433
|
|
|
|
|
|
|
# |
434
|
|
|
|
|
|
|
# ################################ |
435
|
|
|
|
|
|
|
# # MethodParms : $self, %args; |
436
|
|
|
|
|
|
|
# } elsif (my ($mhead,$method_invokation,$method_hash_ident,$mtail) = m/^(\s*)MethodParms\s+:\s+(\S+.*?)\s*,\s*(\S+.*?)\s*;(.*)$/) { |
437
|
|
|
|
|
|
|
# if ($normalize) { |
438
|
|
|
|
|
|
|
# $_ = "${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"; |
439
|
|
|
|
|
|
|
# } else { |
440
|
|
|
|
|
|
|
# $_ = "${mhead}my $method_invokation = shift; my $method_hash_ident = \@\_; $mtail\n"; |
441
|
|
|
|
|
|
|
# } |
442
|
|
|
|
|
|
|
####### |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
} |
446
|
436
|
|
|
|
|
538
|
if (_DEBUG) { |
447
|
|
|
|
|
|
|
print STDERR "output as: $_"; |
448
|
|
|
|
|
|
|
} |
449
|
436
|
100
|
|
|
|
1257
|
if ($dump_to_stdout) { print $_; } |
|
110
|
|
|
|
|
159
|
|
450
|
|
|
|
|
|
|
|
451
|
436
|
|
|
|
|
18236
|
return $status; |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
#### |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
1; |
457
|
|
|
|
|
|
|
|