| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
use 5.010001; |
|
3
|
22
|
|
|
22
|
|
13758
|
use strict; |
|
|
22
|
|
|
|
|
68
|
|
|
4
|
22
|
|
|
22
|
|
102
|
use warnings; |
|
|
22
|
|
|
|
|
43
|
|
|
|
22
|
|
|
|
|
382
|
|
|
5
|
22
|
|
|
22
|
|
99
|
use Log::ger; |
|
|
22
|
|
|
|
|
35
|
|
|
|
22
|
|
|
|
|
520
|
|
|
6
|
22
|
|
|
22
|
|
100
|
|
|
|
22
|
|
|
|
|
34
|
|
|
|
22
|
|
|
|
|
127
|
|
|
7
|
|
|
|
|
|
|
use Mo qw(build default); |
|
8
|
22
|
|
|
22
|
|
4024
|
extends 'Data::Sah::Compiler'; |
|
|
22
|
|
|
|
|
51
|
|
|
|
22
|
|
|
|
|
127
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#use Digest::MD5 qw(md5_hex); |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# human compiler, to produce error messages |
|
13
|
|
|
|
|
|
|
has hc => (is => 'rw'); |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
# subclass should provide a default, choices: 'shell', 'c', 'ini', 'cpp' |
|
16
|
|
|
|
|
|
|
has comment_style => (is => 'rw'); |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
has var_sigil => (is => 'rw'); |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
has concat_op => (is => 'rw'); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
has logical_and_op => (is => 'rw', default => sub {'&&'}); |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
has logical_not_op => (is => 'rw', default => sub {'!'}); |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
#has logical_or_op => (is => 'rw', default => sub {'||'}); |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY |
|
29
|
|
|
|
|
|
|
our $DATE = '2022-08-20'; # DATE |
|
30
|
|
|
|
|
|
|
our $DIST = 'Data-Sah'; # DIST |
|
31
|
|
|
|
|
|
|
our $VERSION = '0.912'; # VERSION |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
my ($self, %args) = @_; |
|
34
|
|
|
|
|
|
|
|
|
35
|
5060
|
|
|
5060
|
0
|
32715
|
my $cd = $self->SUPER::init_cd(%args); |
|
36
|
|
|
|
|
|
|
$cd->{vars} = {}; |
|
37
|
5060
|
|
|
|
|
28370
|
|
|
38
|
5060
|
|
|
|
|
14697
|
my $hc = $self->hc; |
|
39
|
|
|
|
|
|
|
if (!$hc) { |
|
40
|
5060
|
|
|
|
|
13283
|
$hc = $self->main->get_compiler("human"); |
|
41
|
5060
|
100
|
|
|
|
23072
|
$self->hc($hc); |
|
42
|
4725
|
|
|
|
|
9992
|
} |
|
43
|
4725
|
|
|
|
|
13198
|
|
|
44
|
|
|
|
|
|
|
if (my $ocd = $cd->{outer_cd}) { |
|
45
|
|
|
|
|
|
|
$cd->{vars} = $ocd->{vars}; |
|
46
|
5060
|
100
|
|
|
|
23883
|
$cd->{modules} = $ocd->{modules}; |
|
47
|
330
|
|
|
|
|
645
|
$cd->{functions} = $ocd->{functions}; |
|
48
|
330
|
|
|
|
|
603
|
$cd->{_hc} = $ocd->{_hc}; |
|
49
|
330
|
|
|
|
|
847
|
$cd->{_hcd} = $ocd->{_hcd}; |
|
50
|
330
|
|
|
|
|
606
|
$cd->{_subdata_level} = $ocd->{_subdata_level}; |
|
51
|
330
|
|
|
|
|
526
|
$cd->{use_dpath} = 1 if $ocd->{use_dpath}; |
|
52
|
330
|
|
|
|
|
467
|
} else { |
|
53
|
330
|
100
|
|
|
|
826
|
$cd->{vars} = {}; |
|
54
|
|
|
|
|
|
|
$cd->{modules} = []; |
|
55
|
4730
|
|
|
|
|
11681
|
$cd->{functions} = {}; |
|
56
|
4730
|
|
|
|
|
10298
|
$cd->{_hc} = $hc; |
|
57
|
4730
|
|
|
|
|
9157
|
$cd->{_subdata_level} = 0; |
|
58
|
4730
|
|
|
|
|
7938
|
} |
|
59
|
4730
|
|
|
|
|
14964
|
|
|
60
|
|
|
|
|
|
|
$cd; |
|
61
|
|
|
|
|
|
|
} |
|
62
|
5060
|
|
|
|
|
24589
|
|
|
63
|
|
|
|
|
|
|
my ($self, $args) = @_; |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
return if $args->{_args_checked_Prog}++; |
|
66
|
9784
|
|
|
9784
|
0
|
20087
|
|
|
67
|
|
|
|
|
|
|
$self->SUPER::check_compile_args($args); |
|
68
|
9784
|
100
|
|
|
|
28326
|
|
|
69
|
|
|
|
|
|
|
my $ct = ($args->{code_type} //= 'validator'); |
|
70
|
4730
|
|
|
|
|
17567
|
if ($ct ne 'validator') { |
|
71
|
|
|
|
|
|
|
$self->_die({}, "code_type currently can only be 'validator'"); |
|
72
|
4730
|
|
50
|
|
|
16009
|
} |
|
73
|
4730
|
50
|
|
|
|
11173
|
for ($args->{return_type}) { |
|
74
|
0
|
|
|
|
|
0
|
$_ //= 'bool_valid'; |
|
75
|
|
|
|
|
|
|
# old values that are still supported but now deprecated |
|
76
|
4730
|
|
|
|
|
9039
|
$_ = "bool_valid" if $_ eq 'bool'; |
|
77
|
4730
|
|
100
|
|
|
13710
|
$_ = "bool_valid+val" if $_ eq 'bool+val'; |
|
78
|
|
|
|
|
|
|
$_ = "str_errmsg" if $_ eq 'str'; |
|
79
|
4730
|
50
|
|
|
|
9112
|
$_ = "str_errmsg+val" if $_ eq 'str+val'; |
|
80
|
4730
|
50
|
|
|
|
8649
|
$_ = "hash_details" if $_ eq 'full'; |
|
81
|
4730
|
50
|
|
|
|
8966
|
} |
|
82
|
4730
|
50
|
|
|
|
8536
|
my $rt = $args->{return_type}; |
|
83
|
4730
|
50
|
|
|
|
10966
|
if ($rt !~ /\A(bool_valid\+val|bool_valid|str_errmsg\+val|str_errmsg|hash_details)\z/) { |
|
84
|
|
|
|
|
|
|
$self->_die({}, "Invalid value for return_type, ". |
|
85
|
4730
|
|
|
|
|
6926
|
"use bool_valid+val|bool_valid|str_errmsg+val|str_errmsg|hash_details"); |
|
86
|
4730
|
50
|
|
|
|
18451
|
} |
|
87
|
0
|
|
|
|
|
0
|
$args->{var_prefix} //= "_sahv_"; |
|
88
|
|
|
|
|
|
|
$args->{sub_prefix} //= "_sahs_"; |
|
89
|
|
|
|
|
|
|
$args->{data_term} //= $self->var_sigil . $args->{data_name}; |
|
90
|
4730
|
|
50
|
|
|
19004
|
$args->{data_term_is_lvalue} //= 1; |
|
91
|
4730
|
|
50
|
|
|
18448
|
$args->{tmp_data_name} //= "tmp_$args->{data_name}"; |
|
92
|
4730
|
|
33
|
|
|
20113
|
$args->{tmp_data_term} //= $self->var_sigil . $args->{tmp_data_name}; |
|
93
|
4730
|
|
50
|
|
|
39663
|
$args->{comment} //= 1; |
|
94
|
4730
|
|
33
|
|
|
19299
|
$args->{err_term} //= $self->var_sigil . "err_$args->{data_name}"; |
|
95
|
4730
|
|
33
|
|
|
14828
|
$args->{coerce} //= 1; |
|
96
|
4730
|
|
50
|
|
|
31064
|
} |
|
97
|
4730
|
|
33
|
|
|
17505
|
|
|
98
|
4730
|
|
50
|
|
|
36198
|
my ($self, $cd, @args) = @_; |
|
99
|
|
|
|
|
|
|
return '' unless $cd->{args}{comment}; |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
my $content = join("", @args); |
|
102
|
17105
|
|
|
17105
|
1
|
31965
|
$content =~ s/\n+/ /g; |
|
103
|
17105
|
50
|
|
|
|
33785
|
|
|
104
|
|
|
|
|
|
|
my $style = $self->comment_style; |
|
105
|
17105
|
|
|
|
|
29608
|
if ($style eq 'shell') { |
|
106
|
17105
|
|
|
|
|
30171
|
return join("", "# ", $content, "\n"); |
|
107
|
|
|
|
|
|
|
} elsif ($style eq 'shell2') { |
|
108
|
17105
|
|
|
|
|
37807
|
return join("", "## ", $content, "\n"); |
|
109
|
17105
|
50
|
|
|
|
74418
|
} elsif ($style eq 'cpp') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
110
|
17105
|
|
|
|
|
55481
|
return join("", "// ", $content, "\n"); |
|
111
|
|
|
|
|
|
|
} elsif ($style eq 'c') { |
|
112
|
0
|
|
|
|
|
0
|
return join("", "/* ", $content, '*/'); |
|
113
|
|
|
|
|
|
|
} elsif ($style eq 'ini') { |
|
114
|
0
|
|
|
|
|
0
|
return join("", "; ", $content, "\n"); |
|
115
|
|
|
|
|
|
|
} else { |
|
116
|
0
|
|
|
|
|
0
|
$self->_die($cd, "BUG: Unknown comment style: $style"); |
|
117
|
|
|
|
|
|
|
} |
|
118
|
0
|
|
|
|
|
0
|
} |
|
119
|
|
|
|
|
|
|
|
|
120
|
0
|
|
|
|
|
0
|
# enclose expression with parentheses, unless it already is |
|
121
|
|
|
|
|
|
|
my ($self, $expr, $force) = @_; |
|
122
|
|
|
|
|
|
|
if ($expr =~ /\A(\s*)(\(.+\)\s*)\z/os) { |
|
123
|
|
|
|
|
|
|
return $expr if !$force; |
|
124
|
|
|
|
|
|
|
return "$1($2)"; |
|
125
|
|
|
|
|
|
|
} else { |
|
126
|
55497
|
|
|
55497
|
0
|
83684
|
$expr =~ /\A(\s*)(.*)/os; |
|
127
|
55497
|
100
|
|
|
|
163233
|
return "$1($2)"; |
|
128
|
30047
|
100
|
|
|
|
90564
|
} |
|
129
|
6605
|
|
|
|
|
24202
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
25450
|
|
|
|
|
54842
|
my ($self, $cd, $name, $value) = @_; |
|
132
|
25450
|
|
|
|
|
110750
|
|
|
133
|
|
|
|
|
|
|
return if exists $cd->{vars}{$name}; |
|
134
|
|
|
|
|
|
|
#$log->tracef("TMP: add_var %s", $name); |
|
135
|
|
|
|
|
|
|
$cd->{vars}{$name} = $value; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
13479
|
|
|
13479
|
0
|
22912
|
|
|
138
|
|
|
|
|
|
|
# naming convention: expr_NOUN(), stmt_VERB(_NOUN)?() |
|
139
|
13479
|
100
|
|
|
|
29749
|
|
|
140
|
|
|
|
|
|
|
# XXX requires: expr_list |
|
141
|
5042
|
|
|
|
|
12088
|
|
|
142
|
|
|
|
|
|
|
# XXX requires: expr_defined |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# XXX requires: expr_array |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# XXX requires: expr_array_subscript |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# XXX requires: expr_last_elem |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# XXX requires: expr_push |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# XXX requires: expr_pop |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# XXX requires: expr_push_and_pop_dpath_between_expr |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# XXX requires: expr_prefix_dpath |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# XXX requires: expr_set |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
# XXX requires: expr_setif |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# XXX requires: expr_set_err_str |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# XXX requires: expr_set_err_full |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# XXX requires: expr_reset_err_str |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# XXX requires: expr_reset_err_full |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# XXX requires: expr_ternary |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# XXX requires: expr_log |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# XXX requires: expr_block |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# XXX requires: expr_anon_sub |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# XXX requires: expr_eval |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# XXX requires: expr_refer_or_call_sub |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# TODO XXX requires: expr_declare_lexical_var |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# XXX requires: stmt_declare_local_var |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# XXX requires: stmt_require_module |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# XXX requires: stmt_require_log_module |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# XXX requires: stmt_assign_hash_value |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# XXX requires: stmt_sub |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
# XXX requires: stmt_return |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# XXX requires: sub_defined |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# XXX requires: gen_cached_validator |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
my ($self, $cd, $text) = @_; |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
my $hc = $cd->{_hc}; |
|
203
|
|
|
|
|
|
|
my $hcd = $cd->{_hcd}; |
|
204
|
|
|
|
|
|
|
#$log->tracef("(Prog) Translating text %s ...", $text); |
|
205
|
|
|
|
|
|
|
$hc->_xlt($hcd, $text); |
|
206
|
|
|
|
|
|
|
} |
|
207
|
19465
|
|
|
19465
|
|
31608
|
|
|
208
|
|
|
|
|
|
|
# concatenate strings |
|
209
|
19465
|
|
|
|
|
26005
|
my ($self, @t) = @_; |
|
210
|
19465
|
|
|
|
|
27560
|
join(" " . $self->concat_op . " ", @t); |
|
211
|
|
|
|
|
|
|
} |
|
212
|
19465
|
|
|
|
|
45946
|
|
|
213
|
|
|
|
|
|
|
# variable |
|
214
|
|
|
|
|
|
|
my ($self, $v) = @_; |
|
215
|
|
|
|
|
|
|
$self->var_sigil. $v; |
|
216
|
|
|
|
|
|
|
} |
|
217
|
0
|
|
|
0
|
0
|
0
|
|
|
218
|
0
|
|
|
|
|
0
|
my ($self, $t) = @_; |
|
219
|
|
|
|
|
|
|
"++$t"; |
|
220
|
|
|
|
|
|
|
} |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
my ($self, $v) = @_; |
|
223
|
607
|
|
|
607
|
0
|
1271
|
"++" . $self->var_sigil. $v; |
|
224
|
607
|
|
|
|
|
1523
|
} |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# expr_postinc |
|
227
|
|
|
|
|
|
|
# expr_predec |
|
228
|
0
|
|
|
0
|
0
|
0
|
# expr_postdec |
|
229
|
0
|
|
|
|
|
0
|
|
|
230
|
|
|
|
|
|
|
# args: log_result, var_term, err_term. the rest is the same/supplied to |
|
231
|
|
|
|
|
|
|
# compile(). |
|
232
|
|
|
|
|
|
|
my ($self, %args) = @_; |
|
233
|
2428
|
|
|
2428
|
0
|
3880
|
|
|
234
|
2428
|
|
|
|
|
4640
|
my $cache = $args{cache}; |
|
235
|
|
|
|
|
|
|
my $log_result = $args{log_result}; |
|
236
|
|
|
|
|
|
|
my $dt = $args{data_term}; |
|
237
|
|
|
|
|
|
|
my $vt = delete($args{var_term}) // $dt; |
|
238
|
|
|
|
|
|
|
my $do_log = $args{debug_log} // $args{debug}; |
|
239
|
|
|
|
|
|
|
my $rt = $args{return_type} // 'bool_valid'; |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
$args{indent_level} = 1; |
|
242
|
|
|
|
|
|
|
if ($cache) { |
|
243
|
|
|
|
|
|
|
# ... |
|
244
|
4724
|
|
|
4724
|
0
|
31284
|
} |
|
245
|
|
|
|
|
|
|
my $cd = $args{cd} // $self->compile(%args); |
|
246
|
4724
|
|
|
|
|
8769
|
my $et = $cd->{args}{err_term}; |
|
247
|
4724
|
|
|
|
|
8764
|
|
|
248
|
4724
|
|
|
|
|
6704
|
if ($rt !~ /\Abool/) { |
|
249
|
4724
|
|
33
|
|
|
15309
|
my ($ev) = $et =~ /(\w+)/; # to remove sigil |
|
250
|
4724
|
|
33
|
|
|
15646
|
$self->add_var($cd, $ev, $rt =~ /\Astr/ ? undef : {}); |
|
251
|
4724
|
|
50
|
|
|
10375
|
} |
|
252
|
|
|
|
|
|
|
my $resv = '_sahv_res'; |
|
253
|
4724
|
|
|
|
|
7122
|
my $rest = $self->var_sigil . $resv; |
|
254
|
4724
|
50
|
|
|
|
8644
|
|
|
255
|
|
|
|
|
|
|
my $needs_expr_block = (grep {$_->{phase} eq 'runtime'} @{ $cd->{modules} }) |
|
256
|
|
|
|
|
|
|
|| $do_log; |
|
257
|
4724
|
|
33
|
|
|
31309
|
|
|
258
|
4691
|
|
|
|
|
20776
|
my $code_sub_body = join( |
|
259
|
|
|
|
|
|
|
"", |
|
260
|
4691
|
100
|
|
|
|
15347
|
(map {$self->stmt_declare_local_var( |
|
261
|
2943
|
|
|
|
|
12726
|
$_, $self->literal($cd->{vars}{$_}))."\n"} |
|
262
|
2943
|
100
|
|
|
|
13342
|
sort keys %{ $cd->{vars} }), |
|
263
|
|
|
|
|
|
|
#$log->tracef('-> (validator)(%s) ...', $dt);\n"; |
|
264
|
4691
|
|
|
|
|
7245
|
$self->stmt_declare_local_var($resv, "\n\n" . $cd->{result})."\n\n", |
|
265
|
4691
|
|
|
|
|
12061
|
|
|
266
|
|
|
|
|
|
|
# when rt=bool_valid, return true/false result |
|
267
|
4691
|
|
66
|
|
|
20532
|
#(";\n\n\$log->tracef('<- validator() = %s', \$res)") |
|
268
|
|
|
|
|
|
|
# x !!($do_log && $rt eq 'bool_valid'), |
|
269
|
|
|
|
|
|
|
($self->stmt_return($rest)."\n") |
|
270
|
|
|
|
|
|
|
x !!($rt eq 'bool_valid'), |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# when rt=str_errmsg, return string error message |
|
273
|
5038
|
|
|
|
|
14009
|
#($log->tracef('<- validator() = %s', ". |
|
274
|
4691
|
|
|
|
|
21576
|
# "\$err_data);\n\n"; |
|
275
|
|
|
|
|
|
|
# x !!($do_log && $rt eq 'str_errmsg'), |
|
276
|
4691
|
|
|
|
|
8042
|
($self->expr_set_err_str($et, $self->literal('')).";", |
|
277
|
|
|
|
|
|
|
"\n\n".$self->stmt_return($et)."\n") |
|
278
|
|
|
|
|
|
|
x !!($rt eq 'str_errmsg'), |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# when rt=bool_valid+val, return true/false result as well as |
|
281
|
|
|
|
|
|
|
# final input value |
|
282
|
|
|
|
|
|
|
($self->stmt_return($self->expr_array($rest, $dt))."\n") |
|
283
|
|
|
|
|
|
|
x !!($rt eq 'bool_valid+val'), |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# when rt=str_errmsg+val, return string error message as well as |
|
286
|
|
|
|
|
|
|
# final input value |
|
287
|
|
|
|
|
|
|
($self->expr_set_err_str($et, $self->literal('')).";", |
|
288
|
|
|
|
|
|
|
"\n\n".$self->stmt_return($self->expr_array($et, $dt))."\n") |
|
289
|
|
|
|
|
|
|
x !!($rt eq 'str_errmsg+val'), |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# when rt=hash_details, return error hash |
|
292
|
|
|
|
|
|
|
($self->stmt_assign_hash_value($et, $self->literal('value'), $dt), |
|
293
|
|
|
|
|
|
|
"\n".$self->stmt_return($et)."\n") |
|
294
|
|
|
|
|
|
|
x !!($rt eq 'hash_details'), |
|
295
|
|
|
|
|
|
|
); |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
my $code = join( |
|
298
|
|
|
|
|
|
|
"", |
|
299
|
|
|
|
|
|
|
($self->stmt_require_log_module."\n") x !!$do_log, |
|
300
|
|
|
|
|
|
|
(map { $self->stmt_require_module($_)."\n" } |
|
301
|
|
|
|
|
|
|
grep { $_->{phase} eq 'runtime' } @{ $cd->{modules} }), |
|
302
|
|
|
|
|
|
|
$self->expr_anon_sub([$vt], $code_sub_body), |
|
303
|
|
|
|
|
|
|
); |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
if ($needs_expr_block) { |
|
306
|
|
|
|
|
|
|
$code = $self->expr_block($code); |
|
307
|
|
|
|
|
|
|
} |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
if ($log_result && log_is_trace()) { |
|
310
|
|
|
|
|
|
|
log_trace("validator code:\n%s", |
|
311
|
|
|
|
|
|
|
($ENV{LINENUM} // 1) ? |
|
312
|
7185
|
|
|
|
|
15107
|
Data::Sah::Compiler::__linenum($code) : |
|
313
|
4691
|
|
|
|
|
20142
|
$code); |
|
|
13526
|
|
|
|
|
25793
|
|
|
|
4691
|
|
|
|
|
9137
|
|
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
$code; |
|
317
|
4691
|
100
|
|
|
|
17804
|
} |
|
318
|
4651
|
|
|
|
|
14113
|
|
|
319
|
|
|
|
|
|
|
# add compiled clause to ccls, along with extra information useful for joining |
|
320
|
|
|
|
|
|
|
# later (like error level, code for adding error message, etc). available |
|
321
|
4691
|
50
|
33
|
|
|
13799
|
# options: |
|
322
|
|
|
|
|
|
|
# |
|
323
|
0
|
0
|
0
|
|
|
0
|
# - err_level (str, the default will be taken from current clause's .err_level |
|
324
|
|
|
|
|
|
|
# if not specified), |
|
325
|
|
|
|
|
|
|
# |
|
326
|
|
|
|
|
|
|
# - err_expr (str, a string expression in the target language that evaluates to |
|
327
|
|
|
|
|
|
|
# an error message, the more general and dynamic alternative to err_msg. |
|
328
|
4691
|
|
|
|
|
142386
|
# |
|
329
|
|
|
|
|
|
|
# - err_msg (str, the default will be produced by human compiler if not |
|
330
|
|
|
|
|
|
|
# supplied, or taken from current clause's .err_msg), |
|
331
|
|
|
|
|
|
|
# |
|
332
|
|
|
|
|
|
|
# - subdata (bool, default false, if set to true then this means we are |
|
333
|
|
|
|
|
|
|
# delving into subdata, e.g. array elements or hash pair values, and appropriate |
|
334
|
|
|
|
|
|
|
# things must be done to adjust for this [e.g. push_dpath/pop_dpath at the end |
|
335
|
|
|
|
|
|
|
# so that error message can show the proper data path]. |
|
336
|
|
|
|
|
|
|
# |
|
337
|
|
|
|
|
|
|
# - assert (bool, default false, if set to true means this ccl is an assert ccl, |
|
338
|
|
|
|
|
|
|
# meaning it always returns true and is not translated from an actual clause. it |
|
339
|
|
|
|
|
|
|
# will not affect number of errors nor produce error messages.) |
|
340
|
|
|
|
|
|
|
my ($self, $cd, $ccl, $opts) = @_; |
|
341
|
|
|
|
|
|
|
$opts //= {}; |
|
342
|
|
|
|
|
|
|
my $clause = $cd->{clause} // ""; |
|
343
|
|
|
|
|
|
|
my $op = $cd->{cl_op} // ""; |
|
344
|
|
|
|
|
|
|
#$log->errorf("TMP: adding ccl %s, current ccls=%s", $ccl, $cd->{ccls}); |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
my $el = $opts->{err_level} // $cd->{clset}{"$clause.err_level"} // "error"; |
|
347
|
|
|
|
|
|
|
my $err_expr = $opts->{err_expr}; |
|
348
|
|
|
|
|
|
|
my $err_msg = $opts->{err_msg}; |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
if (defined $err_expr) { |
|
351
|
|
|
|
|
|
|
$self->add_var($cd, '_sahv_dpath', []) if $cd->{use_dpath}; |
|
352
|
|
|
|
|
|
|
$err_expr = $self->expr_prefix_dpath($err_expr) if $cd->{use_dpath}; |
|
353
|
18651
|
|
|
18651
|
0
|
58019
|
} else { |
|
354
|
18651
|
|
100
|
|
|
45340
|
unless (defined $err_msg) { $err_msg = $cd->{clset}{"$clause.err_msg"} } |
|
355
|
18651
|
|
100
|
|
|
49924
|
unless (defined $err_msg) { |
|
356
|
18651
|
|
100
|
|
|
45073
|
# XXX how to invert on op='none' or op='not'? |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
my @msgpath = @{$cd->{spath}}; |
|
359
|
18651
|
|
100
|
|
|
69252
|
my $msgpath; |
|
|
|
|
100
|
|
|
|
|
|
360
|
18651
|
|
|
|
|
25001
|
my $hc = $cd->{_hc}; |
|
361
|
18651
|
|
|
|
|
24279
|
my $hcd = $cd->{_hcd}; |
|
362
|
|
|
|
|
|
|
while (1) { |
|
363
|
18651
|
100
|
|
|
|
29678
|
# search error message, use more general one if the more |
|
364
|
133
|
100
|
|
|
|
412
|
# specific one is not available |
|
365
|
133
|
100
|
|
|
|
383
|
last unless @msgpath; |
|
366
|
|
|
|
|
|
|
$msgpath = join("/", @msgpath); |
|
367
|
18518
|
100
|
|
|
|
34536
|
my $ccls = $hcd->{result}{$msgpath}; |
|
|
6037
|
|
|
|
|
12388
|
|
|
368
|
18518
|
100
|
|
|
|
32555
|
pop @msgpath; |
|
369
|
|
|
|
|
|
|
if ($ccls) { |
|
370
|
|
|
|
|
|
|
local $hcd->{args}{format} = 'inline_err_text'; |
|
371
|
6037
|
|
|
|
|
8126
|
$err_msg = $hc->format_ccls($hcd, $ccls); |
|
|
6037
|
|
|
|
|
15905
|
|
|
372
|
6037
|
|
|
|
|
8268
|
# show path when debugging |
|
373
|
6037
|
|
|
|
|
8307
|
$err_msg = "(msgpath=$msgpath) $err_msg" |
|
374
|
6037
|
|
|
|
|
9004
|
if $cd->{args}{debug}; |
|
375
|
6037
|
|
|
|
|
7347
|
last; |
|
376
|
|
|
|
|
|
|
} |
|
377
|
|
|
|
|
|
|
} |
|
378
|
8518
|
100
|
|
|
|
16249
|
if (!$err_msg) { |
|
379
|
8236
|
|
|
|
|
16459
|
$err_msg = "ERR (clause=".($cd->{clause} // "").")"; |
|
380
|
8236
|
|
|
|
|
14928
|
} else { |
|
381
|
8236
|
|
|
|
|
9968
|
$err_msg = ucfirst($err_msg); |
|
382
|
8236
|
100
|
|
|
|
16312
|
} |
|
383
|
5755
|
|
|
|
|
13087
|
} |
|
384
|
5755
|
|
|
|
|
17891
|
if ($err_msg) { |
|
385
|
|
|
|
|
|
|
$self->add_var($cd, '_sahv_dpath', []) if $cd->{use_dpath}; |
|
386
|
|
|
|
|
|
|
$err_expr = $self->literal($err_msg); |
|
387
|
5755
|
50
|
|
|
|
13816
|
$err_expr = $self->expr_prefix_dpath($err_expr) if $cd->{use_dpath}; |
|
388
|
5755
|
|
|
|
|
10730
|
} |
|
389
|
|
|
|
|
|
|
} |
|
390
|
|
|
|
|
|
|
|
|
391
|
6037
|
100
|
|
|
|
11324
|
my $rt = $cd->{args}{return_type}; |
|
392
|
282
|
|
100
|
|
|
1161
|
my $et = $cd->{args}{err_term}; |
|
393
|
|
|
|
|
|
|
my $err_code; |
|
394
|
5755
|
|
|
|
|
15521
|
if ($rt eq 'hash_details') { |
|
395
|
|
|
|
|
|
|
$self->add_var($cd, '_sahv_dpath', []) if $cd->{use_dpath}; |
|
396
|
|
|
|
|
|
|
my $k = $el eq 'warn' ? 'warnings' : 'errors'; |
|
397
|
18518
|
100
|
|
|
|
31198
|
$err_code = $self->expr_set_err_full($et, $k, $err_expr) if $err_expr; |
|
398
|
11591
|
100
|
|
|
|
28674
|
} elsif ($rt =~ /\Astr/) { |
|
399
|
11591
|
|
|
|
|
30285
|
if ($el ne 'warn') { |
|
400
|
11591
|
100
|
|
|
|
377850
|
$err_code = $self->expr_set_err_str($et, $err_expr) if $err_expr; |
|
401
|
|
|
|
|
|
|
} |
|
402
|
|
|
|
|
|
|
} |
|
403
|
|
|
|
|
|
|
|
|
404
|
18651
|
|
|
|
|
33602
|
my $res = { |
|
405
|
18651
|
|
|
|
|
30088
|
ccl => $ccl, |
|
406
|
18651
|
|
|
|
|
22053
|
err_level => $el, |
|
407
|
18651
|
100
|
|
|
|
52793
|
err_code => $err_code, |
|
|
|
100
|
|
|
|
|
|
|
408
|
5844
|
50
|
|
|
|
20823
|
(_debug_ccl_note => $cd->{_debug_ccl_note}) x !!$cd->{_debug_ccl_note}, |
|
409
|
5844
|
100
|
|
|
|
12076
|
subdata => $opts->{subdata}, |
|
410
|
5844
|
100
|
|
|
|
14846
|
}; |
|
411
|
|
|
|
|
|
|
push @{ $cd->{ccls} }, $res; |
|
412
|
5869
|
100
|
|
|
|
13269
|
delete $cd->{uclset}{"$clause.err_level"}; |
|
413
|
5851
|
100
|
|
|
|
15476
|
delete $cd->{uclset}{"$clause.err_msg"}; |
|
414
|
|
|
|
|
|
|
} |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
# join ccls to handle .op and insert error messages. opts = op |
|
417
|
|
|
|
|
|
|
my ($self, $cd, $ccls, $opts) = @_; |
|
418
|
|
|
|
|
|
|
$opts //= {}; |
|
419
|
|
|
|
|
|
|
my $op = $opts->{op} // "and"; |
|
420
|
|
|
|
|
|
|
#$log->errorf("TMP: joining ccl %s", $ccls); |
|
421
|
|
|
|
|
|
|
#warn "join_ccls"; #TMP |
|
422
|
|
|
|
|
|
|
|
|
423
|
18651
|
|
|
|
|
76865
|
my ($min_ok, $max_ok, $min_nok, $max_nok); |
|
424
|
18651
|
|
|
|
|
26982
|
if ($op eq 'and') { |
|
|
18651
|
|
|
|
|
35998
|
|
|
425
|
18651
|
|
|
|
|
35415
|
$max_nok = 0; |
|
426
|
18651
|
|
|
|
|
75254
|
} elsif ($op eq 'or') { |
|
427
|
|
|
|
|
|
|
$min_ok = 1; |
|
428
|
|
|
|
|
|
|
} elsif ($op eq 'none') { |
|
429
|
|
|
|
|
|
|
$max_ok = 0; |
|
430
|
|
|
|
|
|
|
} elsif ($op eq 'not') { |
|
431
|
13822
|
|
|
13822
|
0
|
25137
|
|
|
432
|
13822
|
|
100
|
|
|
39474
|
} |
|
433
|
13822
|
|
100
|
|
|
39005
|
my $dmin_ok = defined($min_ok); |
|
434
|
|
|
|
|
|
|
my $dmax_ok = defined($max_ok); |
|
435
|
|
|
|
|
|
|
my $dmin_nok = defined($min_nok); |
|
436
|
|
|
|
|
|
|
my $dmax_nok = defined($max_nok); |
|
437
|
13822
|
|
|
|
|
19203
|
|
|
438
|
13822
|
100
|
|
|
|
25958
|
return "" unless @$ccls; |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
439
|
12623
|
|
|
|
|
20166
|
|
|
440
|
|
|
|
|
|
|
my $rt = $cd->{args}{return_type}; |
|
441
|
607
|
|
|
|
|
1125
|
my $vp = $cd->{args}{var_prefix}; |
|
442
|
|
|
|
|
|
|
|
|
443
|
288
|
|
|
|
|
505
|
my $aop = $self->logical_and_op; |
|
444
|
|
|
|
|
|
|
my $nop = $self->logical_not_op; |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
my $true = $self->true; |
|
447
|
13822
|
|
|
|
|
20376
|
|
|
448
|
13822
|
|
|
|
|
16704
|
# insert comment, error message, and $ok/$nok counting. $which is 0 by |
|
449
|
13822
|
|
|
|
|
16717
|
# default (normal), or 1 (reverse logic, for 'not' or 'none'), or 2 (for |
|
450
|
13822
|
|
|
|
|
18634
|
# $ok/$nok counting), or 3 (like 2, but for the last clause). |
|
451
|
|
|
|
|
|
|
my $_ice = sub { |
|
452
|
13822
|
100
|
|
|
|
23359
|
my ($ccl, $which) = @_; |
|
453
|
|
|
|
|
|
|
|
|
454
|
13768
|
|
|
|
|
19896
|
return $self->enclose_paren($ccl->{ccl}) if $ccl->{assert}; |
|
455
|
13768
|
|
|
|
|
19626
|
|
|
456
|
|
|
|
|
|
|
my $res = ""; |
|
457
|
13768
|
|
|
|
|
38399
|
|
|
458
|
13768
|
|
|
|
|
73442
|
if ($ccl->{_debug_ccl_note}) { |
|
459
|
|
|
|
|
|
|
if ($cd->{args}{debug_log} // $cd->{args}{debug}) { |
|
460
|
13768
|
|
|
|
|
62553
|
$res .= $self->expr_log( |
|
461
|
|
|
|
|
|
|
$cd, $self->literal($ccl->{_debug_ccl_note})) . " $aop\n"; |
|
462
|
|
|
|
|
|
|
} else { |
|
463
|
|
|
|
|
|
|
$res .= $self->comment($cd, $ccl->{_debug_ccl_note}); |
|
464
|
|
|
|
|
|
|
} |
|
465
|
|
|
|
|
|
|
} |
|
466
|
22751
|
|
|
22751
|
|
33438
|
|
|
467
|
|
|
|
|
|
|
$which //= 0; |
|
468
|
22751
|
50
|
|
|
|
46006
|
# clause code |
|
469
|
|
|
|
|
|
|
my $cc = ($which == 1 ? $nop:"") . $self->enclose_paren($ccl->{ccl}); |
|
470
|
22751
|
|
|
|
|
33673
|
my ($ec, $oec); |
|
471
|
|
|
|
|
|
|
my ($ret, $oret); |
|
472
|
22751
|
100
|
|
|
|
36626
|
if ($which >= 2) { |
|
473
|
17105
|
50
|
33
|
|
|
55864
|
my @chk; |
|
474
|
|
|
|
|
|
|
if ($ccl->{err_level} eq 'warn') { |
|
475
|
0
|
|
|
|
|
0
|
$oret = 1; |
|
476
|
|
|
|
|
|
|
$ret = 1; |
|
477
|
17105
|
|
|
|
|
34338
|
} elsif ($ccl->{err_level} eq 'fatal') { |
|
478
|
|
|
|
|
|
|
$oret = 1; |
|
479
|
|
|
|
|
|
|
$ret = 0; |
|
480
|
|
|
|
|
|
|
} else { |
|
481
|
22751
|
|
100
|
|
|
70941
|
$oret = $self->expr_preinc_var("${vp}ok"); |
|
482
|
|
|
|
|
|
|
$ret = $self->expr_preinc_var("${vp}nok"); |
|
483
|
22751
|
100
|
|
|
|
54091
|
push @chk, $self->expr_var("${vp}ok"). " <= $max_ok" |
|
484
|
22751
|
|
|
|
|
47550
|
if $dmax_ok; |
|
485
|
22751
|
|
|
|
|
0
|
push @chk, $self->expr_var("${vp}nok")." <= $max_nok" |
|
486
|
22751
|
100
|
|
|
|
34663
|
if $dmax_nok; |
|
487
|
1214
|
|
|
|
|
1628
|
if ($which == 3) { |
|
488
|
1214
|
50
|
|
|
|
3346
|
push @chk, $self->expr_var("${vp}ok"). " >= $min_ok" |
|
|
|
50
|
|
|
|
|
|
|
489
|
0
|
|
|
|
|
0
|
if $dmin_ok; |
|
490
|
0
|
|
|
|
|
0
|
push @chk, $self->expr_var("${vp}nok")." >= $min_nok" |
|
491
|
|
|
|
|
|
|
if $dmin_nok; |
|
492
|
0
|
|
|
|
|
0
|
|
|
493
|
0
|
|
|
|
|
0
|
# we need to clear the error message previously set |
|
494
|
|
|
|
|
|
|
if ($rt !~ /\Abool/) { |
|
495
|
1214
|
|
|
|
|
3193
|
my $et = $cd->{args}{err_term}; |
|
496
|
1214
|
|
|
|
|
6340
|
my $clerrc; |
|
497
|
1214
|
50
|
|
|
|
5672
|
if ($rt eq 'hash_details') { |
|
498
|
|
|
|
|
|
|
$clerrc = $self->expr_reset_err_full($et); |
|
499
|
1214
|
50
|
|
|
|
2654
|
} else { |
|
500
|
|
|
|
|
|
|
$clerrc = $self->expr_reset_err_str($et); |
|
501
|
1214
|
100
|
|
|
|
2353
|
} |
|
502
|
607
|
50
|
|
|
|
2782
|
push @chk, $clerrc; |
|
503
|
|
|
|
|
|
|
} |
|
504
|
607
|
50
|
|
|
|
3900
|
} |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
$res .= "($cc ? $oret : $ret)"; |
|
507
|
|
|
|
|
|
|
$res .= " $aop " . join(" $aop ", @chk) if @chk; |
|
508
|
607
|
100
|
|
|
|
1820
|
} else { |
|
509
|
404
|
|
|
|
|
956
|
$ec = $ccl->{err_code}; |
|
510
|
404
|
|
|
|
|
772
|
$ret = |
|
511
|
404
|
100
|
|
|
|
1097
|
$ccl->{err_level} eq 'fatal' ? 0 : |
|
512
|
202
|
|
|
|
|
920
|
# this must not be done because it messes up ok/nok counting |
|
513
|
|
|
|
|
|
|
#$rt eq 'hash_details' ? 1 : |
|
514
|
202
|
|
|
|
|
703
|
$ccl->{err_level} eq 'warn' ? 1 : 0; |
|
515
|
|
|
|
|
|
|
if ($rt =~ /\Abool/ && $ret) { |
|
516
|
404
|
|
|
|
|
983
|
$res .= $true; |
|
517
|
|
|
|
|
|
|
} elsif ($rt =~ /\Abool/ || !$ec) { |
|
518
|
|
|
|
|
|
|
$res .= $self->enclose_paren($cc); |
|
519
|
|
|
|
|
|
|
} else { |
|
520
|
1214
|
|
|
|
|
3490
|
$res .= $self->enclose_paren( |
|
521
|
1214
|
100
|
|
|
|
3892
|
$self->enclose_paren($cc). " ? $true : ($ec,$ret)", |
|
522
|
|
|
|
|
|
|
"force"); |
|
523
|
21537
|
|
|
|
|
32257
|
} |
|
524
|
|
|
|
|
|
|
} |
|
525
|
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
# insert dpath handling |
|
527
|
|
|
|
|
|
|
$res = $self->expr_push_and_pop_dpath_between_expr($res) |
|
528
|
21537
|
100
|
|
|
|
45699
|
if $cd->{use_dpath} && $ccl->{subdata}; |
|
|
|
100
|
|
|
|
|
|
|
529
|
21537
|
100
|
100
|
|
|
91254
|
$res; |
|
|
|
100
|
100
|
|
|
|
|
|
530
|
36
|
|
|
|
|
62
|
|
|
531
|
|
|
|
|
|
|
}; |
|
532
|
14896
|
|
|
|
|
28359
|
|
|
533
|
|
|
|
|
|
|
my $j = "\n\n$aop\n\n"; |
|
534
|
6605
|
|
|
|
|
13905
|
if ($op eq 'not') { |
|
535
|
|
|
|
|
|
|
return $_ice->($ccls->[0], 1); |
|
536
|
|
|
|
|
|
|
} elsif ($op eq 'and') { |
|
537
|
|
|
|
|
|
|
return join $j, map { $_ice->($_) } @$ccls; |
|
538
|
|
|
|
|
|
|
} elsif ($op eq 'none') { |
|
539
|
|
|
|
|
|
|
return join $j, map { $_ice->($_, 1) } @$ccls; |
|
540
|
|
|
|
|
|
|
} else { |
|
541
|
|
|
|
|
|
|
my $jccl = join $j, map {$_ice->($ccls->[$_], $_ == @$ccls-1 ? 3:2)} |
|
542
|
22751
|
100
|
100
|
|
|
57230
|
0..@$ccls-1; |
|
543
|
22751
|
|
|
|
|
262574
|
{ |
|
544
|
|
|
|
|
|
|
local $cd->{ccls} = []; |
|
545
|
13768
|
|
|
|
|
84668
|
local $cd->{_debug_ccl_note} = "op=$op"; |
|
546
|
|
|
|
|
|
|
$self->add_ccl( |
|
547
|
13768
|
|
|
|
|
28453
|
$cd, |
|
548
|
13768
|
100
|
|
|
|
35856
|
$self->expr_block( |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
549
|
304
|
|
|
|
|
826
|
join( |
|
550
|
|
|
|
|
|
|
"", |
|
551
|
12569
|
|
|
|
|
21081
|
$self->stmt_declare_local_var("${vp}ok" , "0"), "\n", |
|
|
20050
|
|
|
|
|
36131
|
|
|
552
|
|
|
|
|
|
|
$self->stmt_declare_local_var("${vp}nok", "0"), "\n", |
|
553
|
288
|
|
|
|
|
712
|
"\n", |
|
|
576
|
|
|
|
|
1198
|
|
|
554
|
|
|
|
|
|
|
$self->block_uses_sub ? |
|
555
|
607
|
100
|
|
|
|
1796
|
$self->stmt_return($jccl) : $jccl, |
|
|
1214
|
|
|
|
|
3433
|
|
|
556
|
|
|
|
|
|
|
) |
|
557
|
|
|
|
|
|
|
), |
|
558
|
607
|
|
|
|
|
1273
|
); |
|
|
607
|
|
|
|
|
1545
|
|
|
559
|
607
|
|
|
|
|
1520
|
$_ice->($cd->{ccls}[0]); |
|
560
|
607
|
50
|
|
|
|
2653
|
} |
|
561
|
|
|
|
|
|
|
} |
|
562
|
|
|
|
|
|
|
} |
|
563
|
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
my ($self, $cd) = @_; |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
if ($cd->{args}{data_term_is_lvalue}) { |
|
567
|
|
|
|
|
|
|
$cd->{data_term} = $cd->{args}{data_term}; |
|
568
|
|
|
|
|
|
|
} else { |
|
569
|
|
|
|
|
|
|
my $v = $cd->{args}{var_prefix} . $cd->{args}{data_name}; |
|
570
|
|
|
|
|
|
|
push @{ $cd->{vars} }, $v; # XXX unless already there |
|
571
|
|
|
|
|
|
|
$cd->{data_term} = $self->var_sigil . $v; |
|
572
|
|
|
|
|
|
|
die "BUG: support for non-perl compiler not yet added here" |
|
573
|
607
|
|
|
|
|
2057
|
unless $cd->{compiler_name} eq 'perl'; |
|
574
|
|
|
|
|
|
|
push @{ $cd->{ccls} }, ["(local($cd->{data_term} = $cd->{args}{data_term}), 1)"]; |
|
575
|
|
|
|
|
|
|
} |
|
576
|
|
|
|
|
|
|
} |
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
my ($self, $cd) = @_; |
|
579
|
5060
|
|
|
5060
|
1
|
9491
|
|
|
580
|
|
|
|
|
|
|
# do a human compilation first to collect all the error messages |
|
581
|
5060
|
50
|
|
|
|
12255
|
|
|
582
|
5060
|
|
|
|
|
13557
|
unless ($cd->{is_inner}) { |
|
583
|
|
|
|
|
|
|
my $hc = $cd->{_hc}; |
|
584
|
0
|
|
|
|
|
0
|
my %hargs = %{$cd->{args}}; |
|
585
|
0
|
|
|
|
|
0
|
$hargs{format} = 'msg_catalog'; |
|
|
0
|
|
|
|
|
0
|
|
|
586
|
0
|
|
|
|
|
0
|
$hargs{schema_is_normalized} = 1; |
|
587
|
|
|
|
|
|
|
$hargs{schema} = $cd->{nschema}; |
|
588
|
0
|
0
|
|
|
|
0
|
$hargs{on_unhandled_clause} = 'ignore'; |
|
589
|
0
|
|
|
|
|
0
|
$hargs{on_unhandled_attr} = 'ignore'; |
|
|
0
|
|
|
|
|
0
|
|
|
590
|
|
|
|
|
|
|
$hargs{hash_values} = $cd->{args}{human_hash_values}; |
|
591
|
|
|
|
|
|
|
$cd->{_hcd} = $hc->compile(%hargs); |
|
592
|
|
|
|
|
|
|
} |
|
593
|
|
|
|
|
|
|
} |
|
594
|
5059
|
|
|
5059
|
1
|
10805
|
|
|
595
|
|
|
|
|
|
|
my ($self, $cd) = @_; |
|
596
|
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
my $rt = $cd->{args}{return_type}; |
|
598
|
5059
|
100
|
|
|
|
11286
|
my $rt_is_hash = $rt =~ /\Ahash/; |
|
599
|
4729
|
|
|
|
|
8518
|
my $rt_is_str = $rt =~ /\Astr/; |
|
600
|
4729
|
|
|
|
|
6250
|
|
|
|
4729
|
|
|
|
|
58448
|
|
|
601
|
4729
|
|
|
|
|
13703
|
$cd->{use_dpath} //= ( |
|
602
|
4729
|
|
|
|
|
8284
|
$rt_is_hash || |
|
603
|
4729
|
|
|
|
|
10354
|
($rt_is_str && $cd->{has_subschema}) |
|
604
|
4729
|
|
|
|
|
7392
|
); |
|
605
|
4729
|
|
|
|
|
7476
|
|
|
606
|
4729
|
|
|
|
|
9493
|
# handle ok/default/coercion/prefilters/req/forbidden clauses and type check |
|
607
|
4729
|
|
|
|
|
25808
|
|
|
608
|
|
|
|
|
|
|
my $c = $cd->{compiler}; |
|
609
|
|
|
|
|
|
|
my $cname = $c->name; |
|
610
|
|
|
|
|
|
|
my $dt = $cd->{data_term}; |
|
611
|
|
|
|
|
|
|
my $et = $cd->{args}{err_term}; |
|
612
|
5056
|
|
|
5056
|
1
|
9053
|
my $clsets = $cd->{clsets}; |
|
613
|
|
|
|
|
|
|
|
|
614
|
5056
|
|
|
|
|
9500
|
# handle ok, this is very high priority because !ok=>1 should fail undef |
|
615
|
5056
|
|
|
|
|
12712
|
# too. we need to handle its .op=not here. |
|
616
|
5056
|
|
|
|
|
12610
|
for my $i (0..@$clsets-1) { |
|
617
|
|
|
|
|
|
|
my $clset = $clsets->[$i]; |
|
618
|
|
|
|
|
|
|
next unless exists $clset->{ok}; |
|
619
|
|
|
|
|
|
|
my $op = $clset->{"ok.op"} // ""; |
|
620
|
|
|
|
|
|
|
if ($op && $op ne 'not') { |
|
621
|
5056
|
|
100
|
|
|
33499
|
$self->_die($cd, "ok can only be combined with .op=not"); |
|
|
|
|
100
|
|
|
|
|
|
622
|
|
|
|
|
|
|
} |
|
623
|
|
|
|
|
|
|
if ($op eq 'not') { |
|
624
|
|
|
|
|
|
|
local $cd->{_debug_ccl_note} = "!ok #$i"; |
|
625
|
5056
|
|
|
|
|
7349
|
$self->add_ccl($cd, $self->false); |
|
626
|
5056
|
|
|
|
|
14781
|
} else { |
|
627
|
5056
|
|
|
|
|
10581
|
local $cd->{_debug_ccl_note} = "ok #$i"; |
|
628
|
5056
|
|
|
|
|
8068
|
$self->add_ccl($cd, $self->true); |
|
629
|
5056
|
|
|
|
|
7241
|
} |
|
630
|
|
|
|
|
|
|
delete $cd->{uclsets}[$i]{"ok"}; |
|
631
|
|
|
|
|
|
|
delete $cd->{uclsets}[$i]{"ok.is_expr"}; |
|
632
|
|
|
|
|
|
|
} |
|
633
|
5056
|
|
|
|
|
13430
|
|
|
634
|
4610
|
|
|
|
|
7353
|
# handle default |
|
635
|
4610
|
100
|
|
|
|
15161
|
HANDLE_DEFAULT: { |
|
636
|
54
|
|
100
|
|
|
212
|
|
|
637
|
54
|
50
|
66
|
|
|
179
|
my $default_value_expr; |
|
638
|
0
|
|
|
|
|
0
|
my $default_value_ccl_note; |
|
639
|
|
|
|
|
|
|
GEN_DEFAULT_VALUE_RULES: |
|
640
|
54
|
100
|
|
|
|
140
|
{ |
|
641
|
27
|
|
|
|
|
94
|
require Data::Sah::DefaultValueCommon; |
|
642
|
27
|
|
|
|
|
90
|
|
|
643
|
|
|
|
|
|
|
my @default_value_rules; |
|
644
|
27
|
|
|
|
|
84
|
for my $i (0..@$clsets-1) { |
|
645
|
27
|
|
|
|
|
85
|
my $clset = $clsets->[$i]; |
|
646
|
|
|
|
|
|
|
push @default_value_rules, |
|
647
|
54
|
|
|
|
|
118
|
@{ $clset->{"x.$cname.default_value_rules"} // [] }, |
|
648
|
54
|
|
|
|
|
120
|
@{ $clset->{'x.default_value_rules'} // [] }; |
|
649
|
|
|
|
|
|
|
} |
|
650
|
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
my $rules = Data::Sah::DefaultValueCommon::get_default_value_rules( |
|
652
|
|
|
|
|
|
|
compiler => $self->name, |
|
653
|
|
|
|
|
|
|
default_value_rules => \@default_value_rules, |
|
654
|
5056
|
|
|
|
|
6742
|
); |
|
|
5056
|
|
|
|
|
7732
|
|
|
655
|
|
|
|
|
|
|
last unless @$rules; |
|
656
|
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
for my $i (reverse 0..$#{$rules}) { |
|
658
|
5056
|
|
|
|
|
7592
|
my $rule = $rules->[$i]; |
|
|
5056
|
|
|
|
|
33965
|
|
|
659
|
|
|
|
|
|
|
|
|
660
|
5056
|
|
|
|
|
22009
|
$self->add_compile_module( |
|
661
|
5056
|
|
|
|
|
10801
|
$cd, "Data::Sah::Value::$cname\::$rule->{name}", |
|
662
|
4610
|
|
|
|
|
8590
|
{category => 'default_value'}, |
|
663
|
|
|
|
|
|
|
); |
|
664
|
4610
|
|
100
|
|
|
19785
|
|
|
665
|
4610
|
|
50
|
|
|
6138
|
if ($rule->{modules}) { |
|
|
4610
|
|
|
|
|
18629
|
|
|
666
|
|
|
|
|
|
|
for my $mod (keys %{ $rule->{modules} }) { |
|
667
|
|
|
|
|
|
|
my $modspec = $rule->{modules}{$mod}; |
|
668
|
5056
|
|
|
|
|
11662
|
$modspec = {version=>$modspec} unless ref $modspec eq 'HASH'; |
|
669
|
|
|
|
|
|
|
$self->add_runtime_module($cd, $mod, {category=>'default_value', %$modspec}); |
|
670
|
|
|
|
|
|
|
} |
|
671
|
|
|
|
|
|
|
} |
|
672
|
5056
|
100
|
|
|
|
94339
|
} |
|
673
|
|
|
|
|
|
|
|
|
674
|
1
|
|
|
|
|
2
|
$default_value_expr = join " // " , map { "($_->{expr_value})" } @$rules; |
|
|
1
|
|
|
|
|
4
|
|
|
675
|
1
|
|
|
|
|
1
|
$default_value_ccl_note = "default value rule(s): ". |
|
676
|
|
|
|
|
|
|
join(", ", map {$_->{name}} @$rules); |
|
677
|
1
|
|
|
|
|
7
|
} # GEN_DEFAULT_VALUE_RULES |
|
678
|
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
for my $i (0..@$clsets-1) { |
|
680
|
|
|
|
|
|
|
my $clset = $clsets->[$i]; |
|
681
|
|
|
|
|
|
|
my $def = $clset->{default}; |
|
682
|
1
|
50
|
|
|
|
5
|
my $defie = $clset->{"default.is_expr"}; |
|
683
|
0
|
|
|
|
|
0
|
if (defined $def) { |
|
|
0
|
|
|
|
|
0
|
|
|
684
|
0
|
|
|
|
|
0
|
local $cd->{_debug_ccl_note} = "default #$i"; |
|
685
|
0
|
0
|
|
|
|
0
|
my $ct = $defie ? |
|
686
|
0
|
|
|
|
|
0
|
$self->expr($cd, $def) : $self->literal($def); |
|
687
|
|
|
|
|
|
|
$self->add_ccl( |
|
688
|
|
|
|
|
|
|
$cd, |
|
689
|
|
|
|
|
|
|
$self->expr_list( |
|
690
|
|
|
|
|
|
|
$self->expr_setif($dt, $ct), |
|
691
|
1
|
|
|
|
|
3
|
$self->true, |
|
|
1
|
|
|
|
|
5
|
|
|
692
|
|
|
|
|
|
|
), |
|
693
|
1
|
|
|
|
|
3
|
{err_msg => ""}, |
|
|
1
|
|
|
|
|
5
|
|
|
694
|
|
|
|
|
|
|
); |
|
695
|
|
|
|
|
|
|
} |
|
696
|
5056
|
|
|
|
|
10844
|
delete $cd->{uclsets}[$i]{"default"}; |
|
697
|
4610
|
|
|
|
|
7445
|
delete $cd->{uclsets}[$i]{"default.is_expr"}; |
|
698
|
4610
|
|
|
|
|
9599
|
} |
|
699
|
4610
|
|
|
|
|
7709
|
|
|
700
|
4610
|
100
|
|
|
|
9589
|
if (defined $default_value_expr) { |
|
701
|
90
|
|
|
|
|
280
|
local $cd->{_debug_ccl_note} = $default_value_ccl_note; |
|
702
|
90
|
50
|
|
|
|
280
|
$self->add_ccl( |
|
703
|
|
|
|
|
|
|
$cd, |
|
704
|
90
|
|
|
|
|
3002
|
$self->expr_list( |
|
705
|
|
|
|
|
|
|
$self->expr_setif($dt, $default_value_expr), |
|
706
|
|
|
|
|
|
|
$self->true, |
|
707
|
|
|
|
|
|
|
), |
|
708
|
|
|
|
|
|
|
{err_msg => ""}, |
|
709
|
|
|
|
|
|
|
); |
|
710
|
|
|
|
|
|
|
} |
|
711
|
|
|
|
|
|
|
} # HANDLE_DEFAULT |
|
712
|
|
|
|
|
|
|
|
|
713
|
4610
|
|
|
|
|
8247
|
# handle req |
|
714
|
4610
|
|
|
|
|
9304
|
my $has_req; |
|
715
|
|
|
|
|
|
|
for my $i (0..@$clsets-1) { |
|
716
|
|
|
|
|
|
|
my $clset = $clsets->[$i]; |
|
717
|
5056
|
100
|
|
|
|
11383
|
my $req = $clset->{req}; |
|
718
|
1
|
|
|
|
|
2
|
my $reqie = $clset->{"req.is_expr"}; |
|
719
|
1
|
|
|
|
|
4
|
my $req_err_msg = $self->_xlt($cd, "Required but not specified"); |
|
720
|
|
|
|
|
|
|
local $cd->{_debug_ccl_note} = "req #$i"; |
|
721
|
|
|
|
|
|
|
if ($req && !$reqie) { |
|
722
|
|
|
|
|
|
|
$has_req++; |
|
723
|
|
|
|
|
|
|
$self->add_ccl( |
|
724
|
|
|
|
|
|
|
$cd, $self->expr_defined($dt), |
|
725
|
|
|
|
|
|
|
{ |
|
726
|
|
|
|
|
|
|
err_msg => $req_err_msg, |
|
727
|
|
|
|
|
|
|
err_level => 'fatal', |
|
728
|
|
|
|
|
|
|
}, |
|
729
|
|
|
|
|
|
|
); |
|
730
|
|
|
|
|
|
|
} elsif ($reqie) { |
|
731
|
5056
|
|
|
|
|
8149
|
$has_req++; |
|
732
|
5056
|
|
|
|
|
9627
|
my $ct = $self->expr($cd, $req); |
|
733
|
4610
|
|
|
|
|
7587
|
$self->add_ccl( |
|
734
|
4610
|
|
|
|
|
8521
|
$cd, "!($ct) || ".$self->expr_defined($dt), |
|
735
|
4610
|
|
|
|
|
8099
|
{ |
|
736
|
4610
|
|
|
|
|
13021
|
err_msg => $req_err_msg, |
|
737
|
4610
|
|
|
|
|
14798
|
err_level => 'fatal', |
|
738
|
4610
|
100
|
66
|
|
|
14278
|
}, |
|
|
|
50
|
|
|
|
|
|
|
739
|
471
|
|
|
|
|
889
|
); |
|
740
|
471
|
|
|
|
|
1357
|
} |
|
741
|
|
|
|
|
|
|
delete $cd->{uclsets}[$i]{"req"}; |
|
742
|
|
|
|
|
|
|
delete $cd->{uclsets}[$i]{"req.is_expr"}; |
|
743
|
|
|
|
|
|
|
} |
|
744
|
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
# handle forbidden |
|
746
|
|
|
|
|
|
|
my $has_fbd; |
|
747
|
|
|
|
|
|
|
for my $i (0..@$clsets-1) { |
|
748
|
0
|
|
|
|
|
0
|
my $clset = $clsets->[$i]; |
|
749
|
0
|
|
|
|
|
0
|
my $fbd = $clset->{forbidden}; |
|
750
|
0
|
|
|
|
|
0
|
my $fbdie = $clset->{"forbidden.is_expr"}; |
|
751
|
|
|
|
|
|
|
my $fbd_err_msg = $self->_xlt($cd, "Forbidden but specified"); |
|
752
|
|
|
|
|
|
|
local $cd->{_debug_ccl_note} = "forbidden #$i"; |
|
753
|
|
|
|
|
|
|
if ($fbd && !$fbdie) { |
|
754
|
|
|
|
|
|
|
$has_fbd++; |
|
755
|
|
|
|
|
|
|
$self->add_ccl( |
|
756
|
|
|
|
|
|
|
$cd, "!".$self->expr_defined($dt), |
|
757
|
|
|
|
|
|
|
{ |
|
758
|
4610
|
|
|
|
|
7255
|
err_msg => $fbd_err_msg, |
|
759
|
4610
|
|
|
|
|
11413
|
err_level => 'fatal', |
|
760
|
|
|
|
|
|
|
}, |
|
761
|
|
|
|
|
|
|
); |
|
762
|
|
|
|
|
|
|
} elsif ($fbdie) { |
|
763
|
5056
|
|
|
|
|
7352
|
$has_fbd++; |
|
764
|
5056
|
|
|
|
|
9530
|
my $ct = $self->expr($cd, $fbd); |
|
765
|
4610
|
|
|
|
|
7149
|
$self->add_ccl( |
|
766
|
4610
|
|
|
|
|
8308
|
$cd, "!($ct) || !".$self->expr_defined($dt), |
|
767
|
4610
|
|
|
|
|
6464
|
{ |
|
768
|
4610
|
|
|
|
|
9241
|
err_msg => $fbd_err_msg, |
|
769
|
4610
|
|
|
|
|
11638
|
err_level => 'fatal', |
|
770
|
4610
|
100
|
66
|
|
|
13380
|
}, |
|
|
|
50
|
|
|
|
|
|
|
771
|
27
|
|
|
|
|
50
|
); |
|
772
|
27
|
|
|
|
|
94
|
} |
|
773
|
|
|
|
|
|
|
delete $cd->{uclsets}[$i]{"forbidden"}; |
|
774
|
|
|
|
|
|
|
delete $cd->{uclsets}[$i]{"forbidden.is_expr"}; |
|
775
|
|
|
|
|
|
|
} |
|
776
|
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
if (!$has_req && !$has_fbd) { |
|
778
|
|
|
|
|
|
|
$cd->{_skip_undef} = 1; |
|
779
|
|
|
|
|
|
|
$cd->{_ccls_idx1} = @{$cd->{ccls}}; |
|
780
|
0
|
|
|
|
|
0
|
} |
|
781
|
0
|
|
|
|
|
0
|
|
|
782
|
0
|
|
|
|
|
0
|
my $coerce_expr; |
|
783
|
|
|
|
|
|
|
my $coerce_might_fail; |
|
784
|
|
|
|
|
|
|
my $coerce_ccl_note; |
|
785
|
|
|
|
|
|
|
GEN_COERCE_EXPR: |
|
786
|
|
|
|
|
|
|
{ |
|
787
|
|
|
|
|
|
|
last unless $cd->{args}{coerce}; |
|
788
|
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
require Data::Sah::CoerceCommon; |
|
790
|
4610
|
|
|
|
|
7135
|
|
|
791
|
4610
|
|
|
|
|
10000
|
my @coerce_rules; |
|
792
|
|
|
|
|
|
|
for my $i (0..@$clsets-1) { |
|
793
|
|
|
|
|
|
|
my $clset = $clsets->[$i]; |
|
794
|
5056
|
100
|
100
|
|
|
17306
|
push @coerce_rules, |
|
795
|
4558
|
|
|
|
|
7817
|
@{ $clset->{"x.$cname.coerce_rules"} // [] }, |
|
796
|
4558
|
|
|
|
|
6539
|
@{ $clset->{'x.coerce_rules'} // [] }; |
|
|
4558
|
|
|
|
|
12093
|
|
|
797
|
|
|
|
|
|
|
} |
|
798
|
|
|
|
|
|
|
|
|
799
|
5056
|
|
|
|
|
12537
|
my $rules = Data::Sah::CoerceCommon::get_coerce_rules( |
|
800
|
|
|
|
|
|
|
compiler => $self->name, |
|
801
|
5056
|
|
|
|
|
0
|
type => $cd->{type}, |
|
802
|
|
|
|
|
|
|
data_term => $dt, |
|
803
|
|
|
|
|
|
|
coerce_to => $cd->{coerce_to}, |
|
804
|
5056
|
50
|
|
|
|
6709
|
coerce_rules => \@coerce_rules, |
|
|
5056
|
|
|
|
|
11815
|
|
|
805
|
|
|
|
|
|
|
); |
|
806
|
5056
|
|
|
|
|
23806
|
last unless @$rules; |
|
807
|
|
|
|
|
|
|
|
|
808
|
5056
|
|
|
|
|
18556
|
$coerce_might_fail = 1 if grep { $_->{meta}{might_fail} } @$rules; |
|
809
|
5056
|
|
|
|
|
11101
|
|
|
810
|
4610
|
|
|
|
|
7793
|
my $prev_term; |
|
811
|
|
|
|
|
|
|
for my $i (reverse 0..$#{$rules}) { |
|
812
|
4610
|
|
100
|
|
|
17844
|
my $rule = $rules->[$i]; |
|
813
|
4610
|
|
50
|
|
|
6497
|
|
|
|
4610
|
|
|
|
|
18453
|
|
|
814
|
|
|
|
|
|
|
$self->add_compile_module( |
|
815
|
|
|
|
|
|
|
$cd, "Data::Sah::Coerce::$cname\::To_$cd->{type}::$rule->{name}", |
|
816
|
|
|
|
|
|
|
{category => 'coerce'}, |
|
817
|
|
|
|
|
|
|
); |
|
818
|
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
if ($rule->{modules}) { |
|
820
|
|
|
|
|
|
|
for my $mod (keys %{ $rule->{modules} }) { |
|
821
|
5056
|
|
|
|
|
12693
|
my $modspec = $rule->{modules}{$mod}; |
|
822
|
|
|
|
|
|
|
$modspec = {version=>$modspec} unless ref $modspec eq 'HASH'; |
|
823
|
5056
|
100
|
|
|
|
302653
|
$self->add_runtime_module($cd, $mod, {category=>'coerce', %$modspec}); |
|
824
|
|
|
|
|
|
|
} |
|
825
|
1220
|
100
|
|
|
|
2945
|
} |
|
|
1384
|
|
|
|
|
4844
|
|
|
826
|
|
|
|
|
|
|
|
|
827
|
1220
|
|
|
|
|
1886
|
if ($i == $#{$rules}) { |
|
828
|
1220
|
|
|
|
|
2122
|
if ($coerce_might_fail) { |
|
|
1220
|
|
|
|
|
2927
|
|
|
829
|
1384
|
|
|
|
|
2370
|
$prev_term = $self->expr_array($self->literal(undef), $dt); |
|
830
|
|
|
|
|
|
|
} else { |
|
831
|
1384
|
|
|
|
|
8778
|
$prev_term = $dt; |
|
832
|
|
|
|
|
|
|
} |
|
833
|
|
|
|
|
|
|
} else { |
|
834
|
|
|
|
|
|
|
$prev_term = "($coerce_expr)"; |
|
835
|
|
|
|
|
|
|
} |
|
836
|
1384
|
100
|
|
|
|
5539
|
|
|
837
|
156
|
|
|
|
|
207
|
my $ec; |
|
|
156
|
|
|
|
|
340
|
|
|
838
|
156
|
|
|
|
|
229
|
if ($coerce_might_fail && !$rule->{meta}{might_fail}) { |
|
839
|
156
|
50
|
|
|
|
382
|
$ec = $self->expr_array($self->literal(undef), $rule->{expr_coerce}); |
|
840
|
156
|
|
|
|
|
489
|
} else { |
|
841
|
|
|
|
|
|
|
$ec = "($rule->{expr_coerce})"; |
|
842
|
|
|
|
|
|
|
} |
|
843
|
|
|
|
|
|
|
|
|
844
|
1384
|
100
|
|
|
|
2344
|
$coerce_expr = $self->expr_ternary( |
|
|
1384
|
|
|
|
|
4158
|
|
|
845
|
1220
|
100
|
|
|
|
2391
|
"($rule->{expr_match})", |
|
846
|
60
|
|
|
|
|
163
|
$ec, |
|
847
|
|
|
|
|
|
|
$prev_term, |
|
848
|
1160
|
|
|
|
|
2045
|
); |
|
849
|
|
|
|
|
|
|
} |
|
850
|
|
|
|
|
|
|
$coerce_ccl_note = "coerce rule(s): ". |
|
851
|
164
|
|
|
|
|
349
|
join(", ", map {$_->{name}} @$rules) . |
|
852
|
|
|
|
|
|
|
($cd->{coerce_to} ? " # coerce to: $cd->{coerce_to}" : ""); |
|
853
|
|
|
|
|
|
|
} # GEN_COERCE_EXPR |
|
854
|
1384
|
|
|
|
|
2306
|
|
|
855
|
1384
|
100
|
100
|
|
|
3932
|
my $prefilters_expr; |
|
856
|
164
|
|
|
|
|
333
|
my $prefilters_ccl_note; |
|
857
|
|
|
|
|
|
|
GEN_PREFILTERS_EXPRS: |
|
858
|
1220
|
|
|
|
|
3049
|
{ |
|
859
|
|
|
|
|
|
|
my @filter_names; |
|
860
|
|
|
|
|
|
|
for my $i (0..@$clsets-1) { |
|
861
|
1384
|
|
|
|
|
5217
|
my $clset = $clsets->[$i]; |
|
862
|
|
|
|
|
|
|
push @filter_names, @{ $clset->{prefilters} } |
|
863
|
|
|
|
|
|
|
if defined $clset->{prefilters}; |
|
864
|
|
|
|
|
|
|
} |
|
865
|
|
|
|
|
|
|
last unless @filter_names; |
|
866
|
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
require Data::Sah::FilterCommon; |
|
868
|
1384
|
|
|
|
|
7233
|
my $rules = Data::Sah::FilterCommon::get_filter_rules( |
|
869
|
1220
|
100
|
|
|
|
2932
|
compiler => $cname, |
|
870
|
|
|
|
|
|
|
data_term => $dt, |
|
871
|
|
|
|
|
|
|
filter_names => \@filter_names, |
|
872
|
5056
|
|
|
|
|
8432
|
); |
|
873
|
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
my @exprs; |
|
875
|
|
|
|
|
|
|
for my $i (0..$#{$rules}) { |
|
876
|
5056
|
|
|
|
|
8122
|
my $rule = $rules->[$i]; |
|
|
5056
|
|
|
|
|
6626
|
|
|
877
|
5056
|
|
|
|
|
10773
|
|
|
878
|
4610
|
|
|
|
|
7389
|
$self->add_compile_module( |
|
879
|
6
|
|
|
|
|
15
|
$cd, "Data::Sah::Filter::$cname\::$rule->{name}", |
|
880
|
4610
|
100
|
|
|
|
13025
|
{category => 'filter'}, |
|
881
|
|
|
|
|
|
|
); |
|
882
|
5056
|
100
|
|
|
|
11108
|
if ($rule->{modules}) { |
|
883
|
|
|
|
|
|
|
for my $mod (keys %{ $rule->{modules} }) { |
|
884
|
6
|
|
|
|
|
879
|
my $modspec = $rule->{modules}{$mod}; |
|
885
|
6
|
|
|
|
|
1100
|
$modspec = {version=>$modspec} unless ref $modspec eq 'HASH'; |
|
886
|
|
|
|
|
|
|
$self->add_runtime_module($cd, $mod, {category=>'filter', %$modspec}); |
|
887
|
|
|
|
|
|
|
} |
|
888
|
|
|
|
|
|
|
} |
|
889
|
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
my $rule_might_fail = $rule->{meta}{might_fail}; |
|
891
|
6
|
|
|
|
|
4886
|
my $expr; |
|
892
|
6
|
|
|
|
|
11
|
if ($rule->{meta}{might_fail}) { |
|
|
6
|
|
|
|
|
19
|
|
|
893
|
7
|
|
|
|
|
16
|
my $expr_fail; |
|
894
|
|
|
|
|
|
|
# XXX rather hackish: like when coercion handling, to avoid |
|
895
|
7
|
|
|
|
|
38
|
# adding another temporary variable, we reuse data term to hold |
|
896
|
|
|
|
|
|
|
# filtering result (which contains error message string as well |
|
897
|
|
|
|
|
|
|
# filtered data) then set the data term to the filtered data |
|
898
|
|
|
|
|
|
|
# again. this might fail in languages or setting that is |
|
899
|
7
|
50
|
|
|
|
26
|
# stricter (e.g. data term must be of certain type). |
|
900
|
0
|
|
|
|
|
0
|
if ($rt_is_hash) { |
|
|
0
|
|
|
|
|
0
|
|
|
901
|
0
|
|
|
|
|
0
|
$expr_fail = $self->expr_list( |
|
902
|
0
|
0
|
|
|
|
0
|
$self->expr_set_err_full($et, 'errors', $self->expr_array_subscript($dt, 0)), |
|
903
|
0
|
|
|
|
|
0
|
$self->false, |
|
904
|
|
|
|
|
|
|
); |
|
905
|
|
|
|
|
|
|
} elsif ($rt_is_str) { |
|
906
|
|
|
|
|
|
|
$expr_fail = $self->expr_list( |
|
907
|
7
|
|
|
|
|
15
|
$self->expr_set_err_str($et, $self->expr_array_subscript($dt, 0)), |
|
908
|
7
|
|
|
|
|
10
|
$self->expr_set($dt, $self->expr_array_subscript($dt, 1)), |
|
909
|
7
|
100
|
|
|
|
18
|
$self->false, |
|
910
|
3
|
|
|
|
|
4
|
); |
|
911
|
|
|
|
|
|
|
} else { |
|
912
|
|
|
|
|
|
|
$expr_fail = $self->false; |
|
913
|
|
|
|
|
|
|
} |
|
914
|
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
$expr = $self->expr_list( |
|
916
|
|
|
|
|
|
|
$self->expr_set($dt, $rule->{expr_filter}), |
|
917
|
3
|
50
|
|
|
|
7
|
$self->expr_ternary( |
|
|
|
50
|
|
|
|
|
|
|
918
|
0
|
|
|
|
|
0
|
$self->expr_defined($self->expr_array_subscript($dt, 0)), |
|
919
|
|
|
|
|
|
|
$expr_fail, |
|
920
|
|
|
|
|
|
|
$self->expr_list( |
|
921
|
|
|
|
|
|
|
$self->expr_set($dt, $self->expr_array_subscript($dt, 1)), |
|
922
|
|
|
|
|
|
|
$self->true, |
|
923
|
0
|
|
|
|
|
0
|
) |
|
924
|
|
|
|
|
|
|
), |
|
925
|
|
|
|
|
|
|
); |
|
926
|
|
|
|
|
|
|
} else { |
|
927
|
|
|
|
|
|
|
$expr = $self->expr_list( |
|
928
|
|
|
|
|
|
|
$self->expr_set($dt, $rule->{expr_filter}), |
|
929
|
3
|
|
|
|
|
9
|
$self->true, |
|
930
|
|
|
|
|
|
|
); |
|
931
|
|
|
|
|
|
|
} |
|
932
|
|
|
|
|
|
|
push @exprs, $expr; |
|
933
|
3
|
|
|
|
|
9
|
} # for rules |
|
934
|
|
|
|
|
|
|
$prefilters_expr = join(" ".$self->logical_and_op." ", @exprs); |
|
935
|
|
|
|
|
|
|
$prefilters_ccl_note = "prefilters: ". |
|
936
|
|
|
|
|
|
|
join(", ", map {$_->{name}} @$rules); |
|
937
|
|
|
|
|
|
|
} # GEN_PREFILTERS_EXPR |
|
938
|
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
HANDLE_TYPE_CHECK_OR_BASE_SCHEMA_CHECK: |
|
940
|
|
|
|
|
|
|
{ |
|
941
|
|
|
|
|
|
|
if (defined $cd->{base_schema}) { |
|
942
|
|
|
|
|
|
|
$self->gen_cached_validator($cd, $cd->{base_schema}); |
|
943
|
|
|
|
|
|
|
} else { |
|
944
|
|
|
|
|
|
|
$self->_die($cd, "BUG: type handler did not produce _ccl_check_type") |
|
945
|
4
|
|
|
|
|
16
|
unless defined($cd->{_ccl_check_type}); |
|
946
|
|
|
|
|
|
|
} |
|
947
|
|
|
|
|
|
|
local $cd->{_debug_ccl_note}; |
|
948
|
|
|
|
|
|
|
|
|
949
|
7
|
|
|
|
|
19
|
# handle coercion |
|
950
|
|
|
|
|
|
|
if ($coerce_expr) { |
|
951
|
6
|
|
|
|
|
26
|
$cd->{_debug_ccl_note} = $coerce_ccl_note; |
|
952
|
|
|
|
|
|
|
if ($coerce_might_fail) { |
|
953
|
6
|
|
|
|
|
15
|
|
|
|
7
|
|
|
|
|
38
|
|
|
954
|
|
|
|
|
|
|
my $expr_fail; |
|
955
|
|
|
|
|
|
|
if ($rt_is_hash) { |
|
956
|
|
|
|
|
|
|
$expr_fail = $self->expr_list( |
|
957
|
|
|
|
|
|
|
$self->expr_set_err_full($et, 'errors', $self->expr_array_subscript($dt, 0)), |
|
958
|
5056
|
50
|
|
|
|
8011
|
$self->false, |
|
|
5056
|
|
|
|
|
9691
|
|
|
959
|
0
|
|
|
|
|
0
|
); |
|
960
|
|
|
|
|
|
|
} elsif ($rt_is_str) { |
|
961
|
|
|
|
|
|
|
$expr_fail = $self->expr_list( |
|
962
|
5056
|
50
|
|
|
|
11207
|
$self->expr_set_err_str($et, $self->expr_array_subscript($dt, 0)), |
|
963
|
|
|
|
|
|
|
$self->expr_set($dt, $self->expr_array_subscript($dt, 1)), |
|
964
|
5056
|
|
|
|
|
17435
|
$self->false, |
|
965
|
|
|
|
|
|
|
); |
|
966
|
|
|
|
|
|
|
} else { |
|
967
|
5056
|
100
|
|
|
|
12499
|
$expr_fail = $self->false; |
|
968
|
1220
|
|
|
|
|
2543
|
} |
|
969
|
1220
|
100
|
|
|
|
2591
|
|
|
970
|
|
|
|
|
|
|
$self->add_ccl( |
|
971
|
60
|
|
|
|
|
82
|
$cd, |
|
972
|
60
|
50
|
|
|
|
129
|
$self->expr_list( |
|
|
|
100
|
|
|
|
|
|
|
973
|
0
|
|
|
|
|
0
|
$self->expr_set($dt, $coerce_expr), |
|
974
|
|
|
|
|
|
|
$self->expr_ternary( |
|
975
|
|
|
|
|
|
|
$self->expr_defined($self->expr_array_subscript($dt, 0)), |
|
976
|
|
|
|
|
|
|
$expr_fail, |
|
977
|
|
|
|
|
|
|
$self->expr_list( |
|
978
|
1
|
|
|
|
|
4
|
$self->expr_set($dt, $self->expr_array_subscript($dt, 1)), |
|
979
|
|
|
|
|
|
|
$self->true, |
|
980
|
|
|
|
|
|
|
) |
|
981
|
|
|
|
|
|
|
), |
|
982
|
|
|
|
|
|
|
), |
|
983
|
|
|
|
|
|
|
{ |
|
984
|
59
|
|
|
|
|
148
|
err_msg => "", |
|
985
|
|
|
|
|
|
|
err_level => "fatal", |
|
986
|
|
|
|
|
|
|
}, |
|
987
|
60
|
|
|
|
|
175
|
); |
|
988
|
|
|
|
|
|
|
} else { |
|
989
|
|
|
|
|
|
|
$self->add_ccl( |
|
990
|
|
|
|
|
|
|
$cd, |
|
991
|
|
|
|
|
|
|
$self->expr_list( |
|
992
|
|
|
|
|
|
|
$self->expr_set($dt, $coerce_expr), |
|
993
|
|
|
|
|
|
|
$self->true, |
|
994
|
|
|
|
|
|
|
), |
|
995
|
|
|
|
|
|
|
{ |
|
996
|
|
|
|
|
|
|
err_msg => "", |
|
997
|
|
|
|
|
|
|
err_level => "fatal", |
|
998
|
|
|
|
|
|
|
}, |
|
999
|
|
|
|
|
|
|
); |
|
1000
|
|
|
|
|
|
|
} |
|
1001
|
|
|
|
|
|
|
} # handle coercion |
|
1002
|
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
# handle prefilters |
|
1004
|
|
|
|
|
|
|
if (defined $prefilters_expr) { |
|
1005
|
|
|
|
|
|
|
$cd->{_debug_ccl_note} = $prefilters_ccl_note; |
|
1006
|
1160
|
|
|
|
|
4607
|
$self->add_ccl( |
|
1007
|
|
|
|
|
|
|
$cd, |
|
1008
|
|
|
|
|
|
|
$prefilters_expr, |
|
1009
|
|
|
|
|
|
|
{ |
|
1010
|
|
|
|
|
|
|
err_msg => "", |
|
1011
|
|
|
|
|
|
|
err_level => "fatal", |
|
1012
|
|
|
|
|
|
|
}, |
|
1013
|
|
|
|
|
|
|
); |
|
1014
|
|
|
|
|
|
|
} # handle prefilters |
|
1015
|
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
# handle type check (if cache=0) or base schema check (if cache=1) |
|
1017
|
|
|
|
|
|
|
if (defined $cd->{base_schema}) { |
|
1018
|
|
|
|
|
|
|
$cd->{_debug_ccl_note} = "check base schema '$cd->{base_schema}'"; |
|
1019
|
|
|
|
|
|
|
$self->add_ccl( |
|
1020
|
|
|
|
|
|
|
$cd, $self->expr_call_cached_validator($cd, $cd->{base_schema}), |
|
1021
|
5056
|
100
|
|
|
|
12193
|
{ |
|
1022
|
6
|
|
|
|
|
13
|
err_msg => sprintf( |
|
1023
|
6
|
|
|
|
|
26
|
$self->_xlt($cd, "Not of schema %s"), |
|
1024
|
|
|
|
|
|
|
$self->_xlt( |
|
1025
|
|
|
|
|
|
|
$cd, |
|
1026
|
|
|
|
|
|
|
$cd->{base_schema}, |
|
1027
|
|
|
|
|
|
|
), |
|
1028
|
|
|
|
|
|
|
), |
|
1029
|
|
|
|
|
|
|
err_level => 'fatal', |
|
1030
|
|
|
|
|
|
|
}, |
|
1031
|
|
|
|
|
|
|
); |
|
1032
|
|
|
|
|
|
|
} else { |
|
1033
|
|
|
|
|
|
|
$cd->{_debug_ccl_note} = "check type '$cd->{type}'"; |
|
1034
|
5056
|
50
|
|
|
|
9970
|
$self->add_ccl( |
|
1035
|
0
|
|
|
|
|
0
|
$cd, $cd->{_ccl_check_type}, |
|
1036
|
|
|
|
|
|
|
{ |
|
1037
|
|
|
|
|
|
|
err_msg => sprintf( |
|
1038
|
|
|
|
|
|
|
$self->_xlt($cd, "Not of type %s"), |
|
1039
|
|
|
|
|
|
|
$self->_xlt( |
|
1040
|
|
|
|
|
|
|
$cd, |
|
1041
|
|
|
|
|
|
|
$cd->{_hc}->get_th(name=>$cd->{type})->name // |
|
1042
|
|
|
|
|
|
|
$cd->{type} |
|
1043
|
|
|
|
|
|
|
), |
|
1044
|
0
|
|
|
|
|
0
|
), |
|
1045
|
|
|
|
|
|
|
err_level => 'fatal', |
|
1046
|
|
|
|
|
|
|
}, |
|
1047
|
|
|
|
|
|
|
); |
|
1048
|
|
|
|
|
|
|
} |
|
1049
|
|
|
|
|
|
|
} # HANDLE_TYPE_CHECK_OR_BASE_SCHEMA_CHECK |
|
1050
|
5056
|
|
|
|
|
12128
|
} |
|
1051
|
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
my ($self, $cd) = @_; |
|
1053
|
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
$self->_die($cd, "Sorry, .op + .is_expr not yet supported ". |
|
1055
|
|
|
|
|
|
|
"(found in clause $cd->{clause})") |
|
1056
|
|
|
|
|
|
|
if $cd->{cl_is_expr} && $cd->{cl_op}; |
|
1057
|
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
if ($cd->{args}{debug}) { |
|
1059
|
|
|
|
|
|
|
state $json = do { |
|
1060
|
5056
|
|
66
|
|
|
14680
|
require JSON; |
|
1061
|
|
|
|
|
|
|
JSON->new->allow_nonref; |
|
1062
|
|
|
|
|
|
|
}; |
|
1063
|
|
|
|
|
|
|
my $clset = $cd->{clset}; |
|
1064
|
|
|
|
|
|
|
my $cl = $cd->{clause}; |
|
1065
|
|
|
|
|
|
|
my $res = $json->encode({ |
|
1066
|
|
|
|
|
|
|
map { $_ => $clset->{$_}} |
|
1067
|
|
|
|
|
|
|
grep {/\A\Q$cl\E(?:\.|\z)/} |
|
1068
|
|
|
|
|
|
|
keys %$clset }); |
|
1069
|
|
|
|
|
|
|
$res =~ s/\n+/ /g; |
|
1070
|
5306
|
|
|
5306
|
1
|
10241
|
# a one-line dump of the clause, suitable for putting in generated |
|
1071
|
|
|
|
|
|
|
# code's comment |
|
1072
|
|
|
|
|
|
|
$cd->{_debug_ccl_note} = "clause: $res"; |
|
1073
|
|
|
|
|
|
|
} else { |
|
1074
|
5306
|
50
|
66
|
|
|
14664
|
$cd->{_debug_ccl_note} = "clause: $cd->{clause}"; |
|
1075
|
|
|
|
|
|
|
} |
|
1076
|
5306
|
50
|
|
|
|
12745
|
|
|
1077
|
0
|
|
|
|
|
0
|
# we save ccls to save_ccls and empty ccls for each clause, to let clause |
|
1078
|
0
|
|
|
|
|
0
|
# join and do stuffs to ccls. at after_clause(), we push the clause's result |
|
1079
|
0
|
|
|
|
|
0
|
# as a single ccl to the original ccls. |
|
1080
|
|
|
|
|
|
|
|
|
1081
|
0
|
|
|
|
|
0
|
push @{ $cd->{_save_ccls} }, $cd->{ccls}; |
|
1082
|
0
|
|
|
|
|
0
|
$cd->{ccls} = []; |
|
1083
|
|
|
|
|
|
|
} |
|
1084
|
0
|
|
|
|
|
0
|
|
|
1085
|
0
|
|
|
|
|
0
|
my ($self, $cd) = @_; |
|
|
0
|
|
|
|
|
0
|
|
|
1086
|
|
|
|
|
|
|
|
|
1087
|
0
|
|
|
|
|
0
|
if ($cd->{args}{debug}) { |
|
1088
|
|
|
|
|
|
|
delete $cd->{_debug_ccl_note}; |
|
1089
|
|
|
|
|
|
|
} |
|
1090
|
0
|
|
|
|
|
0
|
|
|
1091
|
|
|
|
|
|
|
my $save = pop @{ $cd->{_save_ccls} }; |
|
1092
|
5306
|
|
|
|
|
13000
|
if (@{ $cd->{ccls} }) { |
|
1093
|
|
|
|
|
|
|
push @$save, { |
|
1094
|
|
|
|
|
|
|
ccl => $self->join_ccls($cd, $cd->{ccls}, {op=>$cd->{cl_op}}), |
|
1095
|
|
|
|
|
|
|
err_level => $cd->{clset}{"$cd->{clause}.err_level"} // "error", |
|
1096
|
|
|
|
|
|
|
} |
|
1097
|
|
|
|
|
|
|
} |
|
1098
|
|
|
|
|
|
|
$cd->{ccls} = $save; |
|
1099
|
5306
|
|
|
|
|
8716
|
} |
|
|
5306
|
|
|
|
|
13396
|
|
|
1100
|
5306
|
|
|
|
|
11604
|
|
|
1101
|
|
|
|
|
|
|
my ($self, $cd) = @_; |
|
1102
|
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
# simply join them together with && |
|
1104
|
5276
|
|
|
5276
|
1
|
9931
|
$cd->{result} = $self->indent( |
|
1105
|
|
|
|
|
|
|
$cd, |
|
1106
|
5276
|
50
|
|
|
|
14684
|
$self->join_ccls($cd, $cd->{ccls}, {err_msg => ''}), |
|
1107
|
0
|
|
|
|
|
0
|
); |
|
1108
|
|
|
|
|
|
|
} |
|
1109
|
|
|
|
|
|
|
|
|
1110
|
5276
|
|
|
|
|
6668
|
my ($self, $cd) = @_; |
|
|
5276
|
|
|
|
|
10874
|
|
|
1111
|
5276
|
100
|
|
|
|
6735
|
|
|
|
5276
|
|
|
|
|
11345
|
|
|
1112
|
|
|
|
|
|
|
# XXX also handle postfilters here |
|
1113
|
|
|
|
|
|
|
|
|
1114
|
3957
|
|
100
|
|
|
17367
|
if (delete $cd->{_skip_undef}) { |
|
1115
|
|
|
|
|
|
|
my $jccl = $self->join_ccls( |
|
1116
|
|
|
|
|
|
|
$cd, |
|
1117
|
5276
|
|
|
|
|
20610
|
[splice(@{ $cd->{ccls} }, $cd->{_ccls_idx1})], |
|
1118
|
|
|
|
|
|
|
); |
|
1119
|
|
|
|
|
|
|
local $cd->{_debug_ccl_note} = "skip if undef"; |
|
1120
|
|
|
|
|
|
|
$self->add_ccl( |
|
1121
|
174
|
|
|
174
|
0
|
368
|
$cd, |
|
1122
|
|
|
|
|
|
|
"!".$self->expr_defined($cd->{data_term})." ? ".$self->true." : \n\n". |
|
1123
|
|
|
|
|
|
|
$self->enclose_paren($jccl), |
|
1124
|
|
|
|
|
|
|
{err_msg => ''}, |
|
1125
|
|
|
|
|
|
|
); |
|
1126
|
174
|
|
|
|
|
681
|
} |
|
1127
|
|
|
|
|
|
|
|
|
1128
|
|
|
|
|
|
|
# simply join them together with && |
|
1129
|
|
|
|
|
|
|
$cd->{result} = $self->indent( |
|
1130
|
|
|
|
|
|
|
$cd, |
|
1131
|
5025
|
|
|
5025
|
1
|
9680
|
$self->join_ccls($cd, $cd->{ccls}, {err_msg => ''}), |
|
1132
|
|
|
|
|
|
|
); |
|
1133
|
|
|
|
|
|
|
} |
|
1134
|
|
|
|
|
|
|
|
|
1135
|
5025
|
100
|
|
|
|
13372
|
1; |
|
1136
|
|
|
|
|
|
|
# ABSTRACT: Base class for programming language compilers |
|
1137
|
|
|
|
|
|
|
|
|
1138
|
4554
|
|
|
|
|
7573
|
|
|
|
4554
|
|
|
|
|
18898
|
|
|
1139
|
|
|
|
|
|
|
=pod |
|
1140
|
4554
|
|
|
|
|
18414
|
|
|
1141
|
|
|
|
|
|
|
=encoding UTF-8 |
|
1142
|
|
|
|
|
|
|
|
|
1143
|
4554
|
|
|
|
|
15806
|
=head1 NAME |
|
1144
|
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
Data::Sah::Compiler::Prog - Base class for programming language compilers |
|
1146
|
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
=head1 VERSION |
|
1148
|
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
This document describes version 0.912 of Data::Sah::Compiler::Prog (from Perl distribution Data-Sah), released on 2022-08-20. |
|
1150
|
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
1152
|
5025
|
|
|
|
|
20431
|
|
|
1153
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
This class is derived from L<Data::Sah::Compiler>. It is used as base class for |
|
1156
|
|
|
|
|
|
|
compilers which compile schemas into code (validator) in several programming |
|
1157
|
|
|
|
|
|
|
languages, Perl (L<Data::Sah::Compiler::perl>) and JavaScript |
|
1158
|
|
|
|
|
|
|
(L<Data::Sah::Compiler::js>) being two of them. (Other similar programming |
|
1159
|
|
|
|
|
|
|
languages like PHP and Ruby might also be supported later on if needed). |
|
1160
|
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
Compilers using this base class are flexible in the kind of code they produce: |
|
1162
|
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
=over 4 |
|
1164
|
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
=item * configurable validator return type |
|
1166
|
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
Can generate validator that returns a simple bool result, str, or full data |
|
1168
|
|
|
|
|
|
|
structure (containing errors, warnings, and potentially other information). |
|
1169
|
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
=item * configurable data term |
|
1171
|
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
For flexibility in combining the validator code with other code, e.g. putting |
|
1173
|
|
|
|
|
|
|
inside subroutine wrapper (see L<Perinci::Sub::Wrapper>) or directly embedded to |
|
1174
|
|
|
|
|
|
|
your source code (see L<Dist::Zilla::Plugin::Rinci::Validate>). |
|
1175
|
|
|
|
|
|
|
|
|
1176
|
|
|
|
|
|
|
=back |
|
1177
|
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
=for Pod::Coverage ^(after_.+|before_.+|add_var|add_ccl|join_ccls|check_compile_args|enclose_paren|init_cd|expr|expr_.+|stmt_.+)$ |
|
1179
|
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
=head1 HOW IT WORKS |
|
1181
|
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
The compiler generates code in the following form: |
|
1183
|
|
|
|
|
|
|
|
|
1184
|
|
|
|
|
|
|
EXPR && EXPR2 && ... |
|
1185
|
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
where C<EXPR> can be a single expression or multiple expressions joined by the |
|
1187
|
|
|
|
|
|
|
list operator (which Perl and JavaScript support). Each C<EXPR> is typically |
|
1188
|
|
|
|
|
|
|
generated out of a single schema clause. Some pseudo-example of generated |
|
1189
|
|
|
|
|
|
|
JavaScript code: |
|
1190
|
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
(data >= 0) # from clause: min => 0 |
|
1192
|
|
|
|
|
|
|
&& |
|
1193
|
|
|
|
|
|
|
(data <= 10) # from clause: max => 10 |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
Another example, a fuller translation of schema C<< [int => {min=>0, max=>10}] |
|
1196
|
|
|
|
|
|
|
>> to Perl, returning string result (error message) instead of boolean: |
|
1197
|
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
# from clause: req => 0 |
|
1199
|
|
|
|
|
|
|
!defined($data) ? 1 : ( |
|
1200
|
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
# type check |
|
1202
|
|
|
|
|
|
|
($data =~ /^[+-]?\d+$/ ? 1 : ($err //= "Data is not an integer", 0)) |
|
1203
|
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
&& |
|
1205
|
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
# from clause: min => 0 |
|
1207
|
|
|
|
|
|
|
($data >= 0 ? 1 : ($err //= "Must be at least 0", 0)) |
|
1208
|
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
&& |
|
1210
|
|
|
|
|
|
|
|
|
1211
|
|
|
|
|
|
|
# from clause: max => 10 |
|
1212
|
|
|
|
|
|
|
($data <= 10 ? 1 : ($err //= "Must be at most 10", 0)) |
|
1213
|
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
) |
|
1215
|
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
The final validator code will add enclosing subroutine and variable declaration, |
|
1217
|
|
|
|
|
|
|
loading of modules, etc. |
|
1218
|
|
|
|
|
|
|
|
|
1219
|
|
|
|
|
|
|
Note: Current assumptions/hard-coded things for the supported languages: ternary |
|
1220
|
|
|
|
|
|
|
operator (C<? :>), semicolon as statement separator. |
|
1221
|
|
|
|
|
|
|
|
|
1222
|
|
|
|
|
|
|
=head1 COMPILATION DATA KEYS |
|
1223
|
|
|
|
|
|
|
|
|
1224
|
|
|
|
|
|
|
=over |
|
1225
|
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
=item * use_dpath => bool |
|
1227
|
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
Convenience. This is set when code needs to track data path, which is when |
|
1229
|
|
|
|
|
|
|
C<return_type> argument is set to something other than C<bool> or C<bool+val>, |
|
1230
|
|
|
|
|
|
|
and when schema has subschemas. Data path is used when generating error message |
|
1231
|
|
|
|
|
|
|
string, to help point to the item in the data structure (an array element, a |
|
1232
|
|
|
|
|
|
|
hash value) which fails the validation. This is not needed when we want the |
|
1233
|
|
|
|
|
|
|
validator to only return true/false, and also not needed when we do not recurse |
|
1234
|
|
|
|
|
|
|
into subschemas. |
|
1235
|
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
=item * data_term => ARRAY |
|
1237
|
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
Input data term. Set to C<< $cd->{args}{data_term} >> or a temporary variable |
|
1239
|
|
|
|
|
|
|
(if C<< $cd->{args}{data_term_is_lvalue} >> is false). Hooks should use this |
|
1240
|
|
|
|
|
|
|
instead of C<< $cd->{args}{data_term} >> directly, because aside from the |
|
1241
|
|
|
|
|
|
|
aforementioned temporary variable, data term can also change, for example if |
|
1242
|
|
|
|
|
|
|
C<default.temp> or C<prefilters.temp> attribute is set, where generated code |
|
1243
|
|
|
|
|
|
|
will operate on another temporary variable to avoid modifying the original data. |
|
1244
|
|
|
|
|
|
|
Or when C<.input> attribute is set, where generated code will operate on |
|
1245
|
|
|
|
|
|
|
variable other than data. |
|
1246
|
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
=item * subs => ARRAY |
|
1248
|
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
Contains pairs of subroutine names and definition code string, e.g. C<< [ |
|
1250
|
|
|
|
|
|
|
[_sahs_zero => 'sub _sahs_zero { $_[0] == 0 }'], [_sahs_nonzero => 'sub |
|
1251
|
|
|
|
|
|
|
_sah_s_nonzero { $_[0] != 0 }'] ] >>. For flexibility, you'll need to do this |
|
1252
|
|
|
|
|
|
|
bit of arranging yourself to get the final usable code you can compile in your |
|
1253
|
|
|
|
|
|
|
chosen programming language. |
|
1254
|
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
=item * vars => HASH |
|
1256
|
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
=item * coerce_to => str |
|
1258
|
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
Retrieved from the schema's C<x.$COMPILER.coerce_to> attribute. Each type |
|
1260
|
|
|
|
|
|
|
handler might have its own default value. |
|
1261
|
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
=back |
|
1263
|
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
=head1 INTERNAL VARIABLES IN THE GENERATED CODE |
|
1265
|
|
|
|
|
|
|
|
|
1266
|
|
|
|
|
|
|
The generated code maintains the following variables. C<_sahv_> prefix stands |
|
1267
|
|
|
|
|
|
|
for "Sah validator", it is used to minimize clash with data_term. |
|
1268
|
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
=over |
|
1270
|
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
=item * _sahv_dpath => ARRAY |
|
1272
|
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
Analogous to C<spath> in compilation data, this variable stands for "data path" |
|
1274
|
|
|
|
|
|
|
and is used to track location within data. If a clause is checking each element |
|
1275
|
|
|
|
|
|
|
of an array (like the 'each_elem' or 'elems' array clause), this variable will |
|
1276
|
|
|
|
|
|
|
be adjusted accordingly. Error messages thus can be more informative by pointing |
|
1277
|
|
|
|
|
|
|
more exactly where in the data the problem lies. |
|
1278
|
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
=item * tmp_data_term => ANY |
|
1280
|
|
|
|
|
|
|
|
|
1281
|
|
|
|
|
|
|
As explained in the C<compile()> method, this is used to store temporary value |
|
1282
|
|
|
|
|
|
|
when checking against clauses. |
|
1283
|
|
|
|
|
|
|
|
|
1284
|
|
|
|
|
|
|
=item * _sahv_stack => ARRAY |
|
1285
|
|
|
|
|
|
|
|
|
1286
|
|
|
|
|
|
|
This variable is used to store validation result of subdata. It is only used if |
|
1287
|
|
|
|
|
|
|
the validator is returning a string or full structure, not a single boolean |
|
1288
|
|
|
|
|
|
|
value. See C<Data::Sah::Compiler::js::TH::hash> for an example. |
|
1289
|
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
=item * _sahv_x |
|
1291
|
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
Usually used as temporary variable in short, anonymous functions. |
|
1293
|
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
=back |
|
1295
|
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
|
1297
|
|
|
|
|
|
|
|
|
1298
|
|
|
|
|
|
|
These usually need not be set/changed by users. |
|
1299
|
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
=head2 hc => OBJ |
|
1301
|
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
Instance of L<Data::Sah::Compiler::human>, to generate error messages. |
|
1303
|
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
=head2 comment_style => STR |
|
1305
|
|
|
|
|
|
|
|
|
1306
|
|
|
|
|
|
|
Specify how comments are written in the target language. Either 'cpp' (C<// |
|
1307
|
|
|
|
|
|
|
comment>), 'shell' (C<# comment>), 'c' (C</* comment */>), or 'ini' (C<; |
|
1308
|
|
|
|
|
|
|
comment>). Each programming language subclass will set this, for example, the |
|
1309
|
|
|
|
|
|
|
perl compiler sets this to 'shell' while js sets this to 'cpp'. |
|
1310
|
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
=head2 var_sigil => STR |
|
1312
|
|
|
|
|
|
|
|
|
1313
|
|
|
|
|
|
|
=head2 concat_op => STR |
|
1314
|
|
|
|
|
|
|
|
|
1315
|
|
|
|
|
|
|
=head2 logical_and_op => STR |
|
1316
|
|
|
|
|
|
|
|
|
1317
|
|
|
|
|
|
|
=head2 logical_not_op => STR |
|
1318
|
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
=head1 METHODS |
|
1320
|
|
|
|
|
|
|
|
|
1321
|
|
|
|
|
|
|
=head2 new() => OBJ |
|
1322
|
|
|
|
|
|
|
|
|
1323
|
|
|
|
|
|
|
=head2 $c->compile(%args) => RESULT |
|
1324
|
|
|
|
|
|
|
|
|
1325
|
|
|
|
|
|
|
Generate a validator (function) for the given schema. |
|
1326
|
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
Aside from base class' arguments, this class supports these arguments (suffix |
|
1328
|
|
|
|
|
|
|
C<*> denotes required argument): |
|
1329
|
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
=over |
|
1331
|
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
=item * cache |
|
1333
|
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
Bool, default false. If set to true, will generate validators for base schemas |
|
1335
|
|
|
|
|
|
|
when possible, compile them into functions in the |
|
1336
|
|
|
|
|
|
|
C<Data::Sah::_GeneratedValidators::*>, then have the generated validator code |
|
1337
|
|
|
|
|
|
|
calls these functions. This will result in smaller validator code and shorter |
|
1338
|
|
|
|
|
|
|
compilation time especially for large/complex schema that is composed from |
|
1339
|
|
|
|
|
|
|
subschemas. But this will also create a (usually insignificant) additional |
|
1340
|
|
|
|
|
|
|
overhead of multiple function calls when doing validation using the generated |
|
1341
|
|
|
|
|
|
|
validator code. |
|
1342
|
|
|
|
|
|
|
|
|
1343
|
|
|
|
|
|
|
Only relevant when L</name> argument is set. When a certain named |
|
1344
|
|
|
|
|
|
|
function is already defined, avoid generating the function declaration again and |
|
1345
|
|
|
|
|
|
|
instead call the defined function. |
|
1346
|
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
=item * data_term |
|
1348
|
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
Str. A variable name or an expression in the target language that contains the |
|
1350
|
|
|
|
|
|
|
data, defaults to I<var_sigil> + C<name> if not specified. |
|
1351
|
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
=item * data_term_is_lvalue |
|
1353
|
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
Bool, default true. Whether C<data_term> can be assigned to. |
|
1355
|
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
=item * tmp_data_name |
|
1357
|
|
|
|
|
|
|
|
|
1358
|
|
|
|
|
|
|
Str. Normally need not be set manually, as it will be set to "tmp_" . data_name. |
|
1359
|
|
|
|
|
|
|
Used to store temporary data during clause evaluation. |
|
1360
|
|
|
|
|
|
|
|
|
1361
|
|
|
|
|
|
|
=item * tmp_data_term |
|
1362
|
|
|
|
|
|
|
|
|
1363
|
|
|
|
|
|
|
Str. Normally need not be set manually, as it will be set to var_sigil . |
|
1364
|
|
|
|
|
|
|
tmp_data_name. Used to store temporary data during clause evaluation. For |
|
1365
|
|
|
|
|
|
|
example, in JavaScript, the 'int' and 'float' type pass strings in the type |
|
1366
|
|
|
|
|
|
|
check. But for further checking with the clauses (like 'min', 'max', |
|
1367
|
|
|
|
|
|
|
'divisible_by') the string data needs to be converted to number first. Likewise |
|
1368
|
|
|
|
|
|
|
with prefiltering. This variable holds the temporary value. The clauses compare |
|
1369
|
|
|
|
|
|
|
against this value. At the end of clauses, the original data_term is restored. |
|
1370
|
|
|
|
|
|
|
So the output validator code for schema C<< [int => min => 1] >> will look |
|
1371
|
|
|
|
|
|
|
something like: |
|
1372
|
|
|
|
|
|
|
|
|
1373
|
|
|
|
|
|
|
// type check 'int' |
|
1374
|
|
|
|
|
|
|
type(data)=='number' && Math.round(data)==data || parseInt(data)==data) |
|
1375
|
|
|
|
|
|
|
|
|
1376
|
|
|
|
|
|
|
&& |
|
1377
|
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
// convert to number |
|
1379
|
|
|
|
|
|
|
(tmp_data = type(data)=='number' ? data : parseFloat(data), true) |
|
1380
|
|
|
|
|
|
|
|
|
1381
|
|
|
|
|
|
|
&& |
|
1382
|
|
|
|
|
|
|
|
|
1383
|
|
|
|
|
|
|
// check clause 'min' |
|
1384
|
|
|
|
|
|
|
(tmp_data >= 1) |
|
1385
|
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
=item * err_term |
|
1387
|
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
Str. A variable name or lvalue expression to store error message(s), defaults to |
|
1389
|
|
|
|
|
|
|
I<var_sigil> + C<err_NAME> (e.g. C<$err_data> in the Perl compiler). |
|
1390
|
|
|
|
|
|
|
|
|
1391
|
|
|
|
|
|
|
=item * var_prefix |
|
1392
|
|
|
|
|
|
|
|
|
1393
|
|
|
|
|
|
|
Str, default "_sahv_". Prefix for variables declared by generated code. |
|
1394
|
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
=item * sub_prefix |
|
1396
|
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
Str, default "_sahs_". Prefix for subroutines declared by generated code. |
|
1398
|
|
|
|
|
|
|
|
|
1399
|
|
|
|
|
|
|
=item * code_type |
|
1400
|
|
|
|
|
|
|
|
|
1401
|
|
|
|
|
|
|
Str, default "validator". The kind of code to generate. For now the only valid |
|
1402
|
|
|
|
|
|
|
(and default) value is 'validator'. Compiler can perhaps generate other kinds of |
|
1403
|
|
|
|
|
|
|
code in the future. |
|
1404
|
|
|
|
|
|
|
|
|
1405
|
|
|
|
|
|
|
=item * return_type |
|
1406
|
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
Str, default "bool". Specify what kind of return value the generated code should |
|
1408
|
|
|
|
|
|
|
produce. Either C<bool_valid>, C<bool_valid+val>, C<str_errmsg>, |
|
1409
|
|
|
|
|
|
|
C<str_errmsg+val>, or C<hash_details>. |
|
1410
|
|
|
|
|
|
|
|
|
1411
|
|
|
|
|
|
|
C<bool_valid> means generated validator code should just return true/false |
|
1412
|
|
|
|
|
|
|
depending on whether validation succeeds/fails. |
|
1413
|
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
C<bool_valid+val> is like C<bool_valid>, but instead of just C<bool_valid> the |
|
1415
|
|
|
|
|
|
|
validator code will return a two-element arrayref C<< [bool_valid, val] >> where |
|
1416
|
|
|
|
|
|
|
C<val> is the final value of data (after setting of default, coercion, etc.) |
|
1417
|
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
C<str_errmsg> means validation should return an error message string (the first |
|
1419
|
|
|
|
|
|
|
one encountered) if validation fails and an empty string/undef if validation |
|
1420
|
|
|
|
|
|
|
succeeds. |
|
1421
|
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
C<str_errmsg+val> is like C<str_errmsg>, but instead of just C<str_errmsg> the |
|
1423
|
|
|
|
|
|
|
validator code will return a two-element arrayref C<< [str_errmsg, val] >> where |
|
1424
|
|
|
|
|
|
|
C<val> is the final value of data (after setting of default, coercion, etc.) |
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
C<hash_details> means validation should return a full hash data structure. From |
|
1427
|
|
|
|
|
|
|
this structure you can check whether validation succeeds, retrieve all the |
|
1428
|
|
|
|
|
|
|
collected errors/warnings, etc. |
|
1429
|
|
|
|
|
|
|
|
|
1430
|
|
|
|
|
|
|
=item * coerce |
|
1431
|
|
|
|
|
|
|
|
|
1432
|
|
|
|
|
|
|
Bool, default true. If set to false, will not include coercion code. |
|
1433
|
|
|
|
|
|
|
|
|
1434
|
|
|
|
|
|
|
=item * debug |
|
1435
|
|
|
|
|
|
|
|
|
1436
|
|
|
|
|
|
|
Bool, default false. This is a general debugging option which should turn on all |
|
1437
|
|
|
|
|
|
|
debugging-related options, e.g. produce more comments in the generated code, |
|
1438
|
|
|
|
|
|
|
etc. Each compiler might have more specific debugging options. |
|
1439
|
|
|
|
|
|
|
|
|
1440
|
|
|
|
|
|
|
If turned on, specific debugging options can be explicitly turned off |
|
1441
|
|
|
|
|
|
|
afterwards, e.g. C<< debug=>1, debug_log=>0 >> will turn on all debugging |
|
1442
|
|
|
|
|
|
|
options but turn off the C<debug_log> setting. |
|
1443
|
|
|
|
|
|
|
|
|
1444
|
|
|
|
|
|
|
Currently turning on C<debug> means: |
|
1445
|
|
|
|
|
|
|
|
|
1446
|
|
|
|
|
|
|
=over |
|
1447
|
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
=item - Turning on the other debug_* options, like debug_log |
|
1449
|
|
|
|
|
|
|
|
|
1450
|
|
|
|
|
|
|
=item - Prefixing error message with msgpath |
|
1451
|
|
|
|
|
|
|
|
|
1452
|
|
|
|
|
|
|
=back |
|
1453
|
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
=item * debug_log |
|
1455
|
|
|
|
|
|
|
|
|
1456
|
|
|
|
|
|
|
Bool, default false. Whether to add logging to generated code. This aids in |
|
1457
|
|
|
|
|
|
|
debugging generated code specially for more complex validation. |
|
1458
|
|
|
|
|
|
|
|
|
1459
|
|
|
|
|
|
|
=item * comment |
|
1460
|
|
|
|
|
|
|
|
|
1461
|
|
|
|
|
|
|
Bool, default true. If set to false, generated code will be devoid of comments. |
|
1462
|
|
|
|
|
|
|
|
|
1463
|
|
|
|
|
|
|
=item * human_hash_values |
|
1464
|
|
|
|
|
|
|
|
|
1465
|
|
|
|
|
|
|
Hash. Optional. Will be passed to C<hash_values> argument during C<compile()> by |
|
1466
|
|
|
|
|
|
|
human compiler. |
|
1467
|
|
|
|
|
|
|
|
|
1468
|
|
|
|
|
|
|
=back |
|
1469
|
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
=head2 $c->comment($cd, @args) => STR |
|
1471
|
|
|
|
|
|
|
|
|
1472
|
|
|
|
|
|
|
Generate a comment. For example, in perl compiler: |
|
1473
|
|
|
|
|
|
|
|
|
1474
|
|
|
|
|
|
|
$c->comment($cd, "123"); # -> "# 123\n" |
|
1475
|
|
|
|
|
|
|
|
|
1476
|
|
|
|
|
|
|
Will return an empty string if compile argument C<comment> is set to false. |
|
1477
|
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
=head1 HOMEPAGE |
|
1479
|
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>. |
|
1481
|
|
|
|
|
|
|
|
|
1482
|
|
|
|
|
|
|
=head1 SOURCE |
|
1483
|
|
|
|
|
|
|
|
|
1484
|
|
|
|
|
|
|
Source repository is at L<https://github.com/perlancar/perl-Data-Sah>. |
|
1485
|
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
=head1 AUTHOR |
|
1487
|
|
|
|
|
|
|
|
|
1488
|
|
|
|
|
|
|
perlancar <perlancar@cpan.org> |
|
1489
|
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
=head1 CONTRIBUTING |
|
1491
|
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
|
|
1493
|
|
|
|
|
|
|
To contribute, you can send patches by email/via RT, or send pull requests on |
|
1494
|
|
|
|
|
|
|
GitHub. |
|
1495
|
|
|
|
|
|
|
|
|
1496
|
|
|
|
|
|
|
Most of the time, you don't need to build the distribution yourself. You can |
|
1497
|
|
|
|
|
|
|
simply modify the code, then test via: |
|
1498
|
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
% prove -l |
|
1500
|
|
|
|
|
|
|
|
|
1501
|
|
|
|
|
|
|
If you want to build the distribution (e.g. to try to install it locally on your |
|
1502
|
|
|
|
|
|
|
system), you can install L<Dist::Zilla>, |
|
1503
|
|
|
|
|
|
|
L<Dist::Zilla::PluginBundle::Author::PERLANCAR>, |
|
1504
|
|
|
|
|
|
|
L<Pod::Weaver::PluginBundle::Author::PERLANCAR>, and sometimes one or two other |
|
1505
|
|
|
|
|
|
|
Dist::Zilla- and/or Pod::Weaver plugins. Any additional steps required beyond |
|
1506
|
|
|
|
|
|
|
that are considered a bug and can be reported to me. |
|
1507
|
|
|
|
|
|
|
|
|
1508
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
1509
|
|
|
|
|
|
|
|
|
1510
|
|
|
|
|
|
|
This software is copyright (c) 2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012 by perlancar <perlancar@cpan.org>. |
|
1511
|
|
|
|
|
|
|
|
|
1512
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
|
1513
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
|
1514
|
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
=head1 BUGS |
|
1516
|
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah> |
|
1518
|
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
When submitting a bug or request, please include a test-file or a |
|
1520
|
|
|
|
|
|
|
patch to an existing test-file that illustrates the bug or desired |
|
1521
|
|
|
|
|
|
|
feature. |
|
1522
|
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
=cut |