| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* You may distribute under the terms of either the GNU General Public License |
|
2
|
|
|
|
|
|
|
* or the Artistic License (the same terms as Perl itself) |
|
3
|
|
|
|
|
|
|
* |
|
4
|
|
|
|
|
|
|
* (C) Paul Evans, 2024-2025 -- leonerd@leonerd.org.uk |
|
5
|
|
|
|
|
|
|
*/ |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#include "EXTERN.h" |
|
8
|
|
|
|
|
|
|
#include "perl.h" |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#include "constraints.h" |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
#include "perl-backcompat.c.inc" |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
#include "make_argcheck_ops.c.inc" |
|
15
|
|
|
|
|
|
|
#include "newOP_CUSTOM.c.inc" |
|
16
|
|
|
|
|
|
|
#include "optree-additions.c.inc" |
|
17
|
|
|
|
|
|
|
#include "sv_regexp_match.c.inc" |
|
18
|
|
|
|
|
|
|
#include "sv_streq.c.inc" |
|
19
|
|
|
|
|
|
|
#include "sv_numcmp.c.inc" |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
#include "ckcall_constfold.c.inc" |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
#if HAVE_PERL_VERSION(5, 28, 0) |
|
24
|
|
|
|
|
|
|
/* perl 5.28.0 onward can do gv_fetchmeth superclass lookups without caching |
|
25
|
|
|
|
|
|
|
*/ |
|
26
|
|
|
|
|
|
|
# define HAVE_FETCHMETH_SUPER_NOCACHE |
|
27
|
|
|
|
|
|
|
#endif |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
#define newSVsv_num(osv) S_newSVsv_num(aTHX_ osv) |
|
30
|
90
|
|
|
|
|
|
static SV *S_newSVsv_num(pTHX_ SV *osv) |
|
31
|
|
|
|
|
|
|
{ |
|
32
|
90
|
50
|
|
|
|
|
if(SvNOK(osv)) |
|
33
|
0
|
|
|
|
|
|
return newSVnv(SvNV(osv)); |
|
34
|
90
|
50
|
|
|
|
|
if(SvIOK(osv) && SvIsUV(osv)) |
|
|
|
50
|
|
|
|
|
|
|
35
|
0
|
|
|
|
|
|
return newSVuv(SvUV(osv)); |
|
36
|
|
|
|
|
|
|
|
|
37
|
90
|
|
|
|
|
|
return newSViv(SvIV(osv)); |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
#define newSVsv_str(osv) S_newSVsv_str(aTHX_ osv) |
|
41
|
22
|
|
|
|
|
|
static SV *S_newSVsv_str(pTHX_ SV *osv) |
|
42
|
|
|
|
|
|
|
{ |
|
43
|
22
|
|
|
|
|
|
SV *nsv = newSV(0); |
|
44
|
22
|
|
|
|
|
|
sv_copypv(nsv, osv); |
|
45
|
22
|
|
|
|
|
|
return nsv; |
|
46
|
|
|
|
|
|
|
} |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
#if !HAVE_PERL_VERSION(5, 32, 0) |
|
49
|
|
|
|
|
|
|
# define sv_isa_sv(sv, namesv) S_sv_isa_sv(aTHX_ sv, namesv) |
|
50
|
|
|
|
|
|
|
static bool S_sv_isa_sv(pTHX_ SV *sv, SV *namesv) |
|
51
|
|
|
|
|
|
|
{ |
|
52
|
|
|
|
|
|
|
if(!SvROK(sv) || !SvOBJECT(SvRV(sv))) |
|
53
|
|
|
|
|
|
|
return FALSE; |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
/* TODO: ->isa invocation */ |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
return sv_derived_from_sv(sv, namesv, 0); |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
#endif |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
#ifndef op_force_list |
|
62
|
|
|
|
|
|
|
# define op_force_list(o) S_op_force_list(aTHX_ o) |
|
63
|
|
|
|
|
|
|
static OP *S_op_force_list(pTHX_ OP *o) |
|
64
|
|
|
|
|
|
|
/* Sufficiently good enough for our purposes */ |
|
65
|
|
|
|
|
|
|
{ |
|
66
|
|
|
|
|
|
|
op_null(o); |
|
67
|
|
|
|
|
|
|
return o; |
|
68
|
|
|
|
|
|
|
} |
|
69
|
|
|
|
|
|
|
#endif |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
#define alloc_constraint(svp, constraintp, func, n) S_alloc_constraint(aTHX_ svp, constraintp, func, n) |
|
72
|
196
|
|
|
|
|
|
static void S_alloc_constraint(pTHX_ SV **svp, struct Constraint **constraintp, ConstraintFunc *func, size_t n) |
|
73
|
|
|
|
|
|
|
{ |
|
74
|
196
|
|
|
|
|
|
HV *constraint_stash = gv_stashpvs("Data::Checks::Constraint", GV_ADD); |
|
75
|
|
|
|
|
|
|
|
|
76
|
196
|
|
|
|
|
|
SV *sv = newSV(sizeof(struct Constraint) + n*sizeof(SV *)); |
|
77
|
196
|
|
|
|
|
|
SvPOK_on(sv); |
|
78
|
196
|
|
|
|
|
|
struct Constraint *constraint = (struct Constraint *)SvPVX(sv); |
|
79
|
196
|
|
|
|
|
|
*constraint = (struct Constraint){ |
|
80
|
|
|
|
|
|
|
.func = func, |
|
81
|
|
|
|
|
|
|
.n = n, |
|
82
|
|
|
|
|
|
|
}; |
|
83
|
|
|
|
|
|
|
|
|
84
|
353
|
100
|
|
|
|
|
for(int i = 0; i < n; i++) |
|
85
|
157
|
|
|
|
|
|
constraint->args[i] = NULL; |
|
86
|
|
|
|
|
|
|
|
|
87
|
196
|
|
|
|
|
|
*svp = sv_bless(newRV_noinc(sv), constraint_stash); |
|
88
|
196
|
|
|
|
|
|
*constraintp = constraint; |
|
89
|
196
|
|
|
|
|
|
} |
|
90
|
|
|
|
|
|
|
|
|
91
|
102
|
|
|
|
|
|
SV *DataChecks_extract_constraint(pTHX_ SV *sv) |
|
92
|
|
|
|
|
|
|
{ |
|
93
|
102
|
50
|
|
|
|
|
if(!sv_isa(sv, "Data::Checks::Constraint")) |
|
94
|
0
|
|
|
|
|
|
croak("Expected a Constraint instance as argument"); |
|
95
|
|
|
|
|
|
|
|
|
96
|
102
|
|
|
|
|
|
return SvRV(sv); |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
#define sv_has_overload(sv, method) S_sv_has_overload(aTHX_ sv, method) |
|
100
|
16
|
|
|
|
|
|
static bool S_sv_has_overload(pTHX_ SV *sv, int method) |
|
101
|
|
|
|
|
|
|
{ |
|
102
|
|
|
|
|
|
|
assert(SvROK(sv)); |
|
103
|
|
|
|
|
|
|
|
|
104
|
16
|
|
|
|
|
|
HV *stash = SvSTASH(SvRV(sv)); |
|
105
|
16
|
50
|
|
|
|
|
if(!stash || !Gv_AMG(stash)) |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
106
|
9
|
|
|
|
|
|
return false; |
|
107
|
|
|
|
|
|
|
|
|
108
|
7
|
|
|
|
|
|
MAGIC *mg = mg_find((const SV *)stash, PERL_MAGIC_overload_table); |
|
109
|
7
|
50
|
|
|
|
|
if(!mg) |
|
110
|
|
|
|
|
|
|
return false; |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
CV **cvp = NULL; |
|
113
|
7
|
50
|
|
|
|
|
if(AMT_AMAGIC((AMT *)mg->mg_ptr)) |
|
114
|
7
|
|
|
|
|
|
cvp = ((AMT *)mg->mg_ptr)->table; |
|
115
|
|
|
|
|
|
|
if(!cvp) |
|
116
|
|
|
|
|
|
|
return false; |
|
117
|
|
|
|
|
|
|
|
|
118
|
7
|
|
|
|
|
|
CV *cv = cvp[method]; |
|
119
|
7
|
100
|
|
|
|
|
if(!cv) |
|
120
|
|
|
|
|
|
|
return false; |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
return true; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
|
|
125
|
200013
|
|
|
|
|
|
static bool constraint_Defined(pTHX_ struct Constraint *c, SV *value) |
|
126
|
|
|
|
|
|
|
{ |
|
127
|
200013
|
|
|
|
|
|
return SvOK(value); |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
|
|
130
|
12
|
|
|
|
|
|
static bool constraint_Object(pTHX_ struct Constraint *c, SV *value) |
|
131
|
|
|
|
|
|
|
{ |
|
132
|
12
|
100
|
|
|
|
|
return SvROK(value) && SvOBJECT(SvRV(value)); |
|
|
|
100
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
|
|
135
|
39
|
|
|
|
|
|
static bool constraint_Str(pTHX_ struct Constraint *c, SV *value) |
|
136
|
|
|
|
|
|
|
{ |
|
137
|
39
|
100
|
|
|
|
|
if(!SvOK(value)) |
|
138
|
|
|
|
|
|
|
return false; |
|
139
|
|
|
|
|
|
|
|
|
140
|
35
|
100
|
|
|
|
|
if(SvROK(value)) { |
|
141
|
18
|
|
|
|
|
|
SV *rv = SvRV(value); |
|
142
|
18
|
100
|
|
|
|
|
if(!SvOBJECT(rv)) |
|
143
|
|
|
|
|
|
|
return false; |
|
144
|
|
|
|
|
|
|
|
|
145
|
6
|
100
|
|
|
|
|
if(sv_has_overload(value, string_amg)) |
|
146
|
|
|
|
|
|
|
return true; |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
return false; |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
else { |
|
151
|
|
|
|
|
|
|
return true; |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
7
|
|
|
|
|
|
static bool constraint_StrEq(pTHX_ struct Constraint *c, SV *value) |
|
156
|
|
|
|
|
|
|
{ |
|
157
|
7
|
100
|
|
|
|
|
if(!constraint_Str(aTHX_ c, value)) |
|
158
|
|
|
|
|
|
|
return false; |
|
159
|
|
|
|
|
|
|
|
|
160
|
6
|
|
|
|
|
|
SV *strs = c->args[0]; |
|
161
|
6
|
100
|
|
|
|
|
if(SvTYPE(strs) != SVt_PVAV) |
|
162
|
3
|
|
|
|
|
|
return sv_streq(value, strs); |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
/* TODO: If we were to sort the values initially we could binary-search |
|
165
|
|
|
|
|
|
|
* these much faster |
|
166
|
|
|
|
|
|
|
*/ |
|
167
|
3
|
|
|
|
|
|
size_t n = av_count((AV *)strs); |
|
168
|
3
|
|
|
|
|
|
SV **svp = AvARRAY(strs); |
|
169
|
8
|
100
|
|
|
|
|
for(size_t i = 0; i < n; i++) |
|
170
|
7
|
100
|
|
|
|
|
if(sv_streq(value, svp[i])) |
|
171
|
|
|
|
|
|
|
return true; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
return false; |
|
174
|
|
|
|
|
|
|
} |
|
175
|
|
|
|
|
|
|
|
|
176
|
9
|
|
|
|
|
|
static SV *mk_constraint_StrEq(pTHX_ size_t nargs, SV **args) |
|
177
|
|
|
|
|
|
|
{ |
|
178
|
|
|
|
|
|
|
SV *ret; |
|
179
|
|
|
|
|
|
|
struct Constraint *c; |
|
180
|
9
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_StrEq, 1); |
|
181
|
9
|
|
|
|
|
|
sv_2mortal(ret); |
|
182
|
|
|
|
|
|
|
|
|
183
|
9
|
50
|
|
|
|
|
if(!nargs) |
|
184
|
0
|
|
|
|
|
|
croak("Require at least one string for StrEq()"); |
|
185
|
|
|
|
|
|
|
|
|
186
|
9
|
100
|
|
|
|
|
if(nargs == 1) |
|
187
|
|
|
|
|
|
|
/* We can just store a single string directly */ |
|
188
|
5
|
|
|
|
|
|
c->args[0] = newSVsv_str(args[0]); |
|
189
|
|
|
|
|
|
|
else { |
|
190
|
4
|
|
|
|
|
|
AV *strs = newAV_alloc_x(nargs); |
|
191
|
15
|
100
|
|
|
|
|
for(size_t i = 0; i < nargs; i++) |
|
192
|
11
|
|
|
|
|
|
av_store(strs, i, newSVsv_str(args[i])); |
|
193
|
|
|
|
|
|
|
|
|
194
|
4
|
|
|
|
|
|
c->args[0] = (SV *)strs; |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
|
|
197
|
9
|
|
|
|
|
|
return ret; |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
|
|
200
|
9
|
|
|
|
|
|
static bool constraint_StrMatch(pTHX_ struct Constraint *c, SV *value) |
|
201
|
|
|
|
|
|
|
{ |
|
202
|
9
|
100
|
|
|
|
|
if(!constraint_Str(aTHX_ c, value)) |
|
203
|
|
|
|
|
|
|
return false; |
|
204
|
|
|
|
|
|
|
|
|
205
|
4
|
|
|
|
|
|
return sv_regexp_match(value, (REGEXP *)c->args[0]); |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
|
|
208
|
2
|
|
|
|
|
|
static SV *mk_constraint_StrMatch(pTHX_ SV *arg0) |
|
209
|
|
|
|
|
|
|
{ |
|
210
|
|
|
|
|
|
|
SV *ret; |
|
211
|
|
|
|
|
|
|
struct Constraint *c; |
|
212
|
2
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_StrMatch, 1); |
|
213
|
2
|
|
|
|
|
|
sv_2mortal(ret); |
|
214
|
|
|
|
|
|
|
|
|
215
|
2
|
50
|
|
|
|
|
if(!SvROK(arg0) || !SvRXOK(SvRV(arg0))) |
|
|
|
50
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
croak("Require a pre-compiled regexp pattern for StrMatch()"); |
|
217
|
|
|
|
|
|
|
|
|
218
|
2
|
50
|
|
|
|
|
c->args[0] = SvREFCNT_inc(SvRV(arg0)); |
|
219
|
|
|
|
|
|
|
|
|
220
|
2
|
|
|
|
|
|
return ret; |
|
221
|
|
|
|
|
|
|
} |
|
222
|
|
|
|
|
|
|
|
|
223
|
48
|
|
|
|
|
|
static bool constraint_Num(pTHX_ struct Constraint *c, SV *value) |
|
224
|
|
|
|
|
|
|
{ |
|
225
|
48
|
100
|
|
|
|
|
if(!SvOK(value)) |
|
226
|
|
|
|
|
|
|
return false; |
|
227
|
|
|
|
|
|
|
|
|
228
|
45
|
100
|
|
|
|
|
if(SvROK(value)) { |
|
229
|
10
|
|
|
|
|
|
SV *rv = SvRV(value); |
|
230
|
10
|
100
|
|
|
|
|
if(!SvOBJECT(rv)) |
|
231
|
|
|
|
|
|
|
return false; |
|
232
|
|
|
|
|
|
|
|
|
233
|
4
|
100
|
|
|
|
|
if(sv_has_overload(value, numer_amg)) |
|
234
|
|
|
|
|
|
|
return true; |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
return false; |
|
237
|
|
|
|
|
|
|
} |
|
238
|
35
|
100
|
|
|
|
|
else if(SvPOK(value)) { |
|
239
|
5
|
100
|
|
|
|
|
if(!looks_like_number(value)) |
|
240
|
|
|
|
|
|
|
return false; |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
// reject NaN |
|
243
|
3
|
100
|
|
|
|
|
if(SvPVX(value)[0] == 'N' || SvPVX(value)[0] == 'n') |
|
244
|
|
|
|
|
|
|
return false; |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
return true; |
|
247
|
|
|
|
|
|
|
} |
|
248
|
|
|
|
|
|
|
else { |
|
249
|
|
|
|
|
|
|
// reject NaN |
|
250
|
30
|
100
|
|
|
|
|
if(SvNOK(value) && Perl_isnan(SvNV(value))) |
|
|
|
100
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
return false; |
|
252
|
|
|
|
|
|
|
|
|
253
|
29
|
|
|
|
|
|
return true; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
enum { |
|
258
|
|
|
|
|
|
|
NUMBOUND_LOWER_INCLUSIVE = (1<<0), |
|
259
|
|
|
|
|
|
|
NUMBOUND_UPPER_INCLUSIVE = (1<<1), |
|
260
|
|
|
|
|
|
|
}; |
|
261
|
|
|
|
|
|
|
|
|
262
|
27
|
|
|
|
|
|
static bool constraint_NumBound(pTHX_ struct Constraint *c, SV *value) |
|
263
|
|
|
|
|
|
|
{ |
|
264
|
|
|
|
|
|
|
/* First off it must be a Num */ |
|
265
|
27
|
100
|
|
|
|
|
if(!constraint_Num(aTHX_ c, value)) |
|
266
|
|
|
|
|
|
|
return false; |
|
267
|
|
|
|
|
|
|
|
|
268
|
21
|
100
|
|
|
|
|
if(c->args[0]) { |
|
269
|
15
|
|
|
|
|
|
int cmp = sv_numcmp(c->args[0], value); |
|
270
|
15
|
100
|
|
|
|
|
if(cmp > 0 || (cmp == 0 && !(c->flags & NUMBOUND_LOWER_INCLUSIVE))) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
return false; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
|
|
274
|
17
|
100
|
|
|
|
|
if(c->args[1]) { |
|
275
|
14
|
|
|
|
|
|
int cmp = sv_numcmp(value, c->args[1]); |
|
276
|
14
|
100
|
|
|
|
|
if(cmp > 0 || (cmp == 0 && !(c->flags & NUMBOUND_UPPER_INCLUSIVE))) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
return false; |
|
278
|
|
|
|
|
|
|
} |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
return true; |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
|
|
283
|
8
|
|
|
|
|
|
static SV *mk_constraint_NumGT(pTHX_ SV *arg0) |
|
284
|
|
|
|
|
|
|
{ |
|
285
|
|
|
|
|
|
|
SV *ret; |
|
286
|
|
|
|
|
|
|
struct Constraint *c; |
|
287
|
8
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_NumBound, 2); |
|
288
|
8
|
|
|
|
|
|
sv_2mortal(ret); |
|
289
|
|
|
|
|
|
|
|
|
290
|
8
|
|
|
|
|
|
c->args[0] = newSVsv_num(arg0); |
|
291
|
8
|
|
|
|
|
|
c->args[1] = NULL; |
|
292
|
|
|
|
|
|
|
|
|
293
|
8
|
|
|
|
|
|
return ret; |
|
294
|
|
|
|
|
|
|
} |
|
295
|
|
|
|
|
|
|
|
|
296
|
10
|
|
|
|
|
|
static SV *mk_constraint_NumGE(pTHX_ SV *arg0) |
|
297
|
|
|
|
|
|
|
{ |
|
298
|
|
|
|
|
|
|
SV *ret; |
|
299
|
|
|
|
|
|
|
struct Constraint *c; |
|
300
|
10
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_NumBound, 2); |
|
301
|
10
|
|
|
|
|
|
sv_2mortal(ret); |
|
302
|
|
|
|
|
|
|
|
|
303
|
10
|
|
|
|
|
|
c->flags = NUMBOUND_LOWER_INCLUSIVE; |
|
304
|
10
|
|
|
|
|
|
c->args[0] = newSVsv_num(arg0); |
|
305
|
10
|
|
|
|
|
|
c->args[1] = NULL; |
|
306
|
|
|
|
|
|
|
|
|
307
|
10
|
|
|
|
|
|
return ret; |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
|
|
310
|
9
|
|
|
|
|
|
static SV *mk_constraint_NumLE(pTHX_ SV *arg0) |
|
311
|
|
|
|
|
|
|
{ |
|
312
|
|
|
|
|
|
|
SV *ret; |
|
313
|
|
|
|
|
|
|
struct Constraint *c; |
|
314
|
9
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_NumBound, 2); |
|
315
|
9
|
|
|
|
|
|
sv_2mortal(ret); |
|
316
|
|
|
|
|
|
|
|
|
317
|
9
|
|
|
|
|
|
c->flags = NUMBOUND_UPPER_INCLUSIVE; |
|
318
|
9
|
|
|
|
|
|
c->args[0] = NULL; |
|
319
|
9
|
|
|
|
|
|
c->args[1] = newSVsv_num(arg0); |
|
320
|
|
|
|
|
|
|
|
|
321
|
9
|
|
|
|
|
|
return ret; |
|
322
|
|
|
|
|
|
|
} |
|
323
|
|
|
|
|
|
|
|
|
324
|
9
|
|
|
|
|
|
static SV *mk_constraint_NumLT(pTHX_ SV *arg0) |
|
325
|
|
|
|
|
|
|
{ |
|
326
|
|
|
|
|
|
|
SV *ret; |
|
327
|
|
|
|
|
|
|
struct Constraint *c; |
|
328
|
9
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_NumBound, 2); |
|
329
|
9
|
|
|
|
|
|
sv_2mortal(ret); |
|
330
|
|
|
|
|
|
|
|
|
331
|
9
|
|
|
|
|
|
c->args[0] = NULL; |
|
332
|
9
|
|
|
|
|
|
c->args[1] = newSVsv_num(arg0); |
|
333
|
|
|
|
|
|
|
|
|
334
|
9
|
|
|
|
|
|
return ret; |
|
335
|
|
|
|
|
|
|
} |
|
336
|
|
|
|
|
|
|
|
|
337
|
7
|
|
|
|
|
|
static SV *mk_constraint_NumRange(pTHX_ SV *arg0, SV *arg1) |
|
338
|
|
|
|
|
|
|
{ |
|
339
|
|
|
|
|
|
|
SV *ret; |
|
340
|
|
|
|
|
|
|
struct Constraint *c; |
|
341
|
7
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_NumBound, 2); |
|
342
|
7
|
|
|
|
|
|
sv_2mortal(ret); |
|
343
|
|
|
|
|
|
|
|
|
344
|
7
|
|
|
|
|
|
c->flags = NUMBOUND_LOWER_INCLUSIVE; |
|
345
|
7
|
|
|
|
|
|
c->args[0] = newSVsv_num(arg0); |
|
346
|
7
|
|
|
|
|
|
c->args[1] = newSVsv_num(arg1); |
|
347
|
|
|
|
|
|
|
|
|
348
|
7
|
|
|
|
|
|
return ret; |
|
349
|
|
|
|
|
|
|
} |
|
350
|
|
|
|
|
|
|
|
|
351
|
7
|
|
|
|
|
|
static bool constraint_NumEq(pTHX_ struct Constraint *c, SV *value) |
|
352
|
|
|
|
|
|
|
{ |
|
353
|
7
|
100
|
|
|
|
|
if(!constraint_Num(aTHX_ c, value)) |
|
354
|
|
|
|
|
|
|
return false; |
|
355
|
|
|
|
|
|
|
|
|
356
|
6
|
|
|
|
|
|
SV *nums = c->args[0]; |
|
357
|
6
|
100
|
|
|
|
|
if(SvTYPE(nums) != SVt_PVAV) |
|
358
|
3
|
|
|
|
|
|
return sv_numcmp(value, nums) == 0; |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
/* TODO: If we were to sort the values initially we could binary-search |
|
361
|
|
|
|
|
|
|
* these much faster |
|
362
|
|
|
|
|
|
|
*/ |
|
363
|
3
|
|
|
|
|
|
size_t n = av_count((AV *)nums); |
|
364
|
3
|
|
|
|
|
|
SV **svp = AvARRAY(nums); |
|
365
|
8
|
100
|
|
|
|
|
for(size_t i = 0; i < n; i++) |
|
366
|
7
|
100
|
|
|
|
|
if(sv_numcmp(value, svp[i]) == 0) |
|
367
|
|
|
|
|
|
|
return true; |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
return false; |
|
370
|
|
|
|
|
|
|
} |
|
371
|
|
|
|
|
|
|
|
|
372
|
5
|
|
|
|
|
|
static SV *mk_constraint_NumEq(pTHX_ size_t nargs, SV **args) |
|
373
|
|
|
|
|
|
|
{ |
|
374
|
|
|
|
|
|
|
SV *ret; |
|
375
|
|
|
|
|
|
|
struct Constraint *c; |
|
376
|
5
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_NumEq, 1); |
|
377
|
5
|
|
|
|
|
|
sv_2mortal(ret); |
|
378
|
|
|
|
|
|
|
|
|
379
|
5
|
50
|
|
|
|
|
if(!nargs) |
|
380
|
0
|
|
|
|
|
|
croak("Require at least one number for NumEq()"); |
|
381
|
|
|
|
|
|
|
|
|
382
|
5
|
100
|
|
|
|
|
if(nargs == 1) |
|
383
|
|
|
|
|
|
|
/* We can just store a single number directly */ |
|
384
|
3
|
|
|
|
|
|
c->args[0] = newSVsv_num(args[0]); |
|
385
|
|
|
|
|
|
|
else { |
|
386
|
2
|
|
|
|
|
|
AV *nums = newAV_alloc_x(nargs); |
|
387
|
7
|
100
|
|
|
|
|
for(size_t i = 0; i < nargs; i++) |
|
388
|
5
|
|
|
|
|
|
av_store(nums, i, newSVsv_num(args[i])); |
|
389
|
|
|
|
|
|
|
|
|
390
|
2
|
|
|
|
|
|
c->args[0] = (SV *)nums; |
|
391
|
|
|
|
|
|
|
} |
|
392
|
|
|
|
|
|
|
|
|
393
|
5
|
|
|
|
|
|
return ret; |
|
394
|
|
|
|
|
|
|
} |
|
395
|
|
|
|
|
|
|
|
|
396
|
10
|
|
|
|
|
|
static bool constraint_Isa(pTHX_ struct Constraint *c, SV *value) |
|
397
|
|
|
|
|
|
|
{ |
|
398
|
10
|
|
|
|
|
|
return sv_isa_sv(value, c->args[0]); |
|
399
|
|
|
|
|
|
|
} |
|
400
|
|
|
|
|
|
|
|
|
401
|
4
|
|
|
|
|
|
static SV *mk_constraint_Isa(pTHX_ SV *arg0) |
|
402
|
|
|
|
|
|
|
{ |
|
403
|
|
|
|
|
|
|
SV *ret; |
|
404
|
|
|
|
|
|
|
struct Constraint *c; |
|
405
|
4
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_Isa, 1); |
|
406
|
|
|
|
|
|
|
|
|
407
|
4
|
|
|
|
|
|
c->args[0] = newSVsv(arg0); |
|
408
|
|
|
|
|
|
|
|
|
409
|
4
|
|
|
|
|
|
return sv_2mortal(ret); |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
|
|
412
|
19
|
|
|
|
|
|
static bool constraint_Can(pTHX_ struct Constraint *c, SV *value) |
|
413
|
|
|
|
|
|
|
{ |
|
414
|
|
|
|
|
|
|
HV *stash; |
|
415
|
19
|
100
|
|
|
|
|
if(SvROK(value) && SvOBJECT(SvRV(value))) |
|
|
|
100
|
|
|
|
|
|
|
416
|
5
|
|
|
|
|
|
stash = SvSTASH(SvRV(value)); |
|
417
|
14
|
100
|
|
|
|
|
else if(SvOK(value)) { |
|
418
|
12
|
|
|
|
|
|
stash = gv_stashsv(value, GV_NOADD_NOINIT); |
|
419
|
12
|
100
|
|
|
|
|
if(!stash) |
|
420
|
|
|
|
|
|
|
return false; |
|
421
|
|
|
|
|
|
|
} |
|
422
|
|
|
|
|
|
|
else |
|
423
|
|
|
|
|
|
|
return false; |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
/* TODO: we could cache which classes do or don't satisfy the constraints |
|
426
|
|
|
|
|
|
|
* and store it somewhere, maybe in an HV in ->args[1] or somesuch */ |
|
427
|
|
|
|
|
|
|
|
|
428
|
7
|
|
|
|
|
|
SV *methods = c->args[0]; |
|
429
|
7
|
100
|
|
|
|
|
size_t nmethods = SvTYPE(methods) == SVt_PVAV ? av_count((AV *)methods) : 1; |
|
430
|
19
|
100
|
|
|
|
|
for(size_t idx = 0; idx < nmethods; idx++) { |
|
431
|
13
|
100
|
|
|
|
|
SV *method = SvTYPE(methods) == SVt_PVAV ? AvARRAY((AV *)methods)[idx] : methods; |
|
432
|
13
|
100
|
|
|
|
|
if(!gv_fetchmeth_sv(stash, method, |
|
433
|
|
|
|
|
|
|
#ifdef HAVE_FETCHMETH_SUPER_NOCACHE |
|
434
|
|
|
|
|
|
|
-1, |
|
435
|
|
|
|
|
|
|
#else |
|
436
|
|
|
|
|
|
|
0, |
|
437
|
|
|
|
|
|
|
#endif |
|
438
|
|
|
|
|
|
|
0)) |
|
439
|
|
|
|
|
|
|
return false; |
|
440
|
|
|
|
|
|
|
} |
|
441
|
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
return true; |
|
443
|
|
|
|
|
|
|
} |
|
444
|
|
|
|
|
|
|
|
|
445
|
3
|
|
|
|
|
|
static SV *mk_constraint_Can(pTHX_ size_t nargs, SV **args) |
|
446
|
|
|
|
|
|
|
{ |
|
447
|
|
|
|
|
|
|
SV *ret; |
|
448
|
|
|
|
|
|
|
struct Constraint *c; |
|
449
|
3
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_Can, 1); |
|
450
|
3
|
|
|
|
|
|
sv_2mortal(ret); |
|
451
|
|
|
|
|
|
|
|
|
452
|
3
|
50
|
|
|
|
|
if(!nargs) |
|
453
|
0
|
|
|
|
|
|
croak("Require at least one method name for Can()"); |
|
454
|
|
|
|
|
|
|
|
|
455
|
3
|
100
|
|
|
|
|
if(nargs == 1) |
|
456
|
|
|
|
|
|
|
/* We can just store a single string directly */ |
|
457
|
1
|
|
|
|
|
|
c->args[0] = newSVsv_str(args[0]); |
|
458
|
|
|
|
|
|
|
else { |
|
459
|
2
|
|
|
|
|
|
AV *strs = newAV_alloc_x(nargs); |
|
460
|
7
|
100
|
|
|
|
|
for(size_t i = 0; i < nargs; i++) |
|
461
|
5
|
|
|
|
|
|
av_store(strs, i, newSVsv_str(args[i])); |
|
462
|
|
|
|
|
|
|
|
|
463
|
2
|
|
|
|
|
|
c->args[0] = (SV *)strs; |
|
464
|
|
|
|
|
|
|
} |
|
465
|
|
|
|
|
|
|
|
|
466
|
3
|
|
|
|
|
|
return ret; |
|
467
|
|
|
|
|
|
|
} |
|
468
|
|
|
|
|
|
|
|
|
469
|
8
|
|
|
|
|
|
static bool constraint_ArrayRef(pTHX_ struct Constraint *c, SV *value) |
|
470
|
|
|
|
|
|
|
{ |
|
471
|
8
|
100
|
|
|
|
|
if(!SvOK(value) || !SvROK(value)) |
|
|
|
100
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
return false; |
|
473
|
|
|
|
|
|
|
|
|
474
|
5
|
|
|
|
|
|
SV *rv = SvRV(value); |
|
475
|
|
|
|
|
|
|
|
|
476
|
5
|
100
|
|
|
|
|
if(!SvOBJECT(rv)) |
|
477
|
|
|
|
|
|
|
/* plain ref */ |
|
478
|
3
|
|
|
|
|
|
return SvTYPE(rv) == SVt_PVAV; |
|
479
|
|
|
|
|
|
|
else |
|
480
|
2
|
|
|
|
|
|
return sv_has_overload(value, to_av_amg); |
|
481
|
|
|
|
|
|
|
} |
|
482
|
|
|
|
|
|
|
|
|
483
|
8
|
|
|
|
|
|
static bool constraint_HashRef(pTHX_ struct Constraint *c, SV *value) |
|
484
|
|
|
|
|
|
|
{ |
|
485
|
8
|
100
|
|
|
|
|
if(!SvOK(value) || !SvROK(value)) |
|
|
|
100
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
return false; |
|
487
|
|
|
|
|
|
|
|
|
488
|
5
|
|
|
|
|
|
SV *rv = SvRV(value); |
|
489
|
|
|
|
|
|
|
|
|
490
|
5
|
100
|
|
|
|
|
if(!SvOBJECT(rv)) |
|
491
|
|
|
|
|
|
|
/* plain ref */ |
|
492
|
3
|
|
|
|
|
|
return SvTYPE(rv) == SVt_PVHV; |
|
493
|
|
|
|
|
|
|
else |
|
494
|
2
|
|
|
|
|
|
return sv_has_overload(value, to_hv_amg); |
|
495
|
|
|
|
|
|
|
} |
|
496
|
|
|
|
|
|
|
|
|
497
|
9
|
|
|
|
|
|
static bool constraint_Callable(pTHX_ struct Constraint *c, SV *value) |
|
498
|
|
|
|
|
|
|
{ |
|
499
|
9
|
100
|
|
|
|
|
if(!SvOK(value) || !SvROK(value)) |
|
|
|
100
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
return false; |
|
501
|
|
|
|
|
|
|
|
|
502
|
6
|
|
|
|
|
|
SV *rv = SvRV(value); |
|
503
|
|
|
|
|
|
|
|
|
504
|
6
|
100
|
|
|
|
|
if(!SvOBJECT(rv)) |
|
505
|
|
|
|
|
|
|
/* plain ref */ |
|
506
|
4
|
|
|
|
|
|
return SvTYPE(rv) == SVt_PVCV; |
|
507
|
|
|
|
|
|
|
else |
|
508
|
2
|
|
|
|
|
|
return sv_has_overload(value, to_cv_amg); |
|
509
|
|
|
|
|
|
|
} |
|
510
|
|
|
|
|
|
|
|
|
511
|
7
|
|
|
|
|
|
static bool constraint_Maybe(pTHX_ struct Constraint *c, SV *value) |
|
512
|
|
|
|
|
|
|
{ |
|
513
|
7
|
100
|
|
|
|
|
if(!SvOK(value)) |
|
514
|
|
|
|
|
|
|
return true; |
|
515
|
|
|
|
|
|
|
|
|
516
|
6
|
|
|
|
|
|
struct Constraint *inner = (struct Constraint *)SvPVX(c->args[0]); |
|
517
|
6
|
|
|
|
|
|
return (*inner->func)(aTHX_ inner, value); |
|
518
|
|
|
|
|
|
|
} |
|
519
|
|
|
|
|
|
|
|
|
520
|
3
|
|
|
|
|
|
static SV *mk_constraint_Maybe(pTHX_ SV *arg0) |
|
521
|
|
|
|
|
|
|
{ |
|
522
|
3
|
|
|
|
|
|
SV *inner = extract_constraint(arg0); |
|
523
|
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
SV *ret; |
|
525
|
|
|
|
|
|
|
struct Constraint *c; |
|
526
|
3
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_Maybe, 1); |
|
527
|
3
|
|
|
|
|
|
sv_2mortal(ret); |
|
528
|
|
|
|
|
|
|
|
|
529
|
3
|
50
|
|
|
|
|
c->args[0] = SvREFCNT_inc(inner); |
|
530
|
|
|
|
|
|
|
|
|
531
|
3
|
|
|
|
|
|
return ret; |
|
532
|
|
|
|
|
|
|
} |
|
533
|
|
|
|
|
|
|
|
|
534
|
7
|
|
|
|
|
|
static bool constraint_Any(pTHX_ struct Constraint *c, SV *value) |
|
535
|
|
|
|
|
|
|
{ |
|
536
|
7
|
|
|
|
|
|
AV *inners = (AV *)c->args[0]; |
|
537
|
7
|
|
|
|
|
|
SV **innersvs = AvARRAY(inners); |
|
538
|
7
|
|
|
|
|
|
size_t n = av_count(inners); |
|
539
|
|
|
|
|
|
|
|
|
540
|
16
|
100
|
|
|
|
|
for(size_t i = 0; i < n; i++) { |
|
541
|
12
|
|
|
|
|
|
struct Constraint *inner = (struct Constraint *)SvPVX(innersvs[i]); |
|
542
|
12
|
100
|
|
|
|
|
if((*inner->func)(aTHX_ inner, value)) |
|
543
|
|
|
|
|
|
|
return true; |
|
544
|
|
|
|
|
|
|
} |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
return false; |
|
547
|
|
|
|
|
|
|
} |
|
548
|
|
|
|
|
|
|
|
|
549
|
8
|
|
|
|
|
|
static SV *mk_constraint_Any(pTHX_ size_t nargs, SV **args) |
|
550
|
|
|
|
|
|
|
{ |
|
551
|
8
|
50
|
|
|
|
|
if(!nargs) |
|
552
|
0
|
|
|
|
|
|
croak("Any() requires at least one inner constraint"); |
|
553
|
8
|
100
|
|
|
|
|
if(nargs == 1) |
|
554
|
1
|
|
|
|
|
|
return args[0]; |
|
555
|
|
|
|
|
|
|
|
|
556
|
7
|
|
|
|
|
|
AV *inners = newAV(); |
|
557
|
7
|
|
|
|
|
|
sv_2mortal((SV *)inners); // in case of croak during construction |
|
558
|
|
|
|
|
|
|
|
|
559
|
21
|
100
|
|
|
|
|
for(size_t i = 0; i < nargs; i++) { |
|
560
|
14
|
|
|
|
|
|
SV *innersv = extract_constraint(args[i]); |
|
561
|
14
|
|
|
|
|
|
struct Constraint *inner = (struct Constraint *)SvPVX(innersv); |
|
562
|
|
|
|
|
|
|
|
|
563
|
14
|
100
|
|
|
|
|
if(inner->func == &constraint_Any) { |
|
564
|
2
|
|
|
|
|
|
AV *kidav = (AV *)inner->args[0]; |
|
565
|
2
|
|
|
|
|
|
size_t nkids = av_count(kidav); |
|
566
|
6
|
100
|
|
|
|
|
for(size_t kidi = 0; kidi < nkids; kidi++) { |
|
567
|
8
|
50
|
|
|
|
|
av_push(inners, SvREFCNT_inc(AvARRAY(kidav)[kidi])); |
|
568
|
|
|
|
|
|
|
} |
|
569
|
|
|
|
|
|
|
} |
|
570
|
|
|
|
|
|
|
else |
|
571
|
12
|
|
|
|
|
|
av_push(inners, SvREFCNT_inc(innersv)); |
|
572
|
|
|
|
|
|
|
} |
|
573
|
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
SV *ret; |
|
575
|
|
|
|
|
|
|
struct Constraint *c; |
|
576
|
7
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_Any, 1); |
|
577
|
7
|
|
|
|
|
|
sv_2mortal(ret); |
|
578
|
|
|
|
|
|
|
|
|
579
|
7
|
50
|
|
|
|
|
c->args[0] = SvREFCNT_inc(inners); |
|
580
|
|
|
|
|
|
|
|
|
581
|
7
|
|
|
|
|
|
return ret; |
|
582
|
|
|
|
|
|
|
} |
|
583
|
|
|
|
|
|
|
|
|
584
|
7
|
|
|
|
|
|
static bool constraint_All(pTHX_ struct Constraint *c, SV *value) |
|
585
|
|
|
|
|
|
|
{ |
|
586
|
7
|
|
|
|
|
|
AV *inners = (AV *)c->args[0]; |
|
587
|
7
|
50
|
|
|
|
|
if(!inners) |
|
588
|
|
|
|
|
|
|
return true; |
|
589
|
|
|
|
|
|
|
|
|
590
|
0
|
|
|
|
|
|
SV **innersvs = AvARRAY(inners); |
|
591
|
0
|
|
|
|
|
|
size_t n = av_count(inners); |
|
592
|
|
|
|
|
|
|
|
|
593
|
0
|
0
|
|
|
|
|
for(size_t i = 0; i < n; i++) { |
|
594
|
0
|
|
|
|
|
|
struct Constraint *inner = (struct Constraint *)SvPVX(innersvs[i]); |
|
595
|
0
|
0
|
|
|
|
|
if(!(*inner->func)(aTHX_ inner, value)) |
|
596
|
|
|
|
|
|
|
return false; |
|
597
|
|
|
|
|
|
|
} |
|
598
|
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
return true; |
|
600
|
|
|
|
|
|
|
} |
|
601
|
|
|
|
|
|
|
|
|
602
|
22
|
|
|
|
|
|
static SV *mk_constraint_All(pTHX_ size_t nargs, SV **args) |
|
603
|
|
|
|
|
|
|
{ |
|
604
|
|
|
|
|
|
|
/* nargs == 0 is valid */ |
|
605
|
22
|
100
|
|
|
|
|
if(nargs == 1) |
|
606
|
1
|
|
|
|
|
|
return args[0]; |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
AV *inners = NULL; |
|
609
|
21
|
100
|
|
|
|
|
if(nargs) { |
|
610
|
19
|
|
|
|
|
|
inners = newAV(); |
|
611
|
19
|
|
|
|
|
|
sv_2mortal((SV *)inners); // in case of croak during construction |
|
612
|
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
/* However many NumBound constraints are in 'inners' it's always possible to |
|
614
|
|
|
|
|
|
|
* optimise them down into just one |
|
615
|
|
|
|
|
|
|
*/ |
|
616
|
19
|
|
|
|
|
|
struct Constraint *all_nums = NULL; |
|
617
|
|
|
|
|
|
|
SV *all_nums_sv; |
|
618
|
|
|
|
|
|
|
|
|
619
|
58
|
100
|
|
|
|
|
for(size_t i = 0; i < nargs; i++) { |
|
620
|
39
|
|
|
|
|
|
SV *innersv = extract_constraint(args[i]); |
|
621
|
39
|
|
|
|
|
|
struct Constraint *inner = (struct Constraint *)SvPVX(innersv); |
|
622
|
|
|
|
|
|
|
|
|
623
|
39
|
100
|
|
|
|
|
if(inner->func == &constraint_All) { |
|
624
|
1
|
|
|
|
|
|
AV *kidav = (AV *)inner->args[0]; |
|
625
|
1
|
|
|
|
|
|
size_t nkids = av_count(kidav); |
|
626
|
3
|
100
|
|
|
|
|
for(size_t kidi = 0; kidi < nkids; kidi++) { |
|
627
|
4
|
50
|
|
|
|
|
av_push(inners, SvREFCNT_inc(AvARRAY(kidav)[kidi])); |
|
628
|
|
|
|
|
|
|
} |
|
629
|
|
|
|
|
|
|
} |
|
630
|
38
|
100
|
|
|
|
|
else if(inner->func == &constraint_NumBound) { |
|
631
|
32
|
100
|
|
|
|
|
if(!all_nums) { |
|
632
|
16
|
|
|
|
|
|
alloc_constraint(&all_nums_sv, &all_nums, &constraint_NumBound, 2); |
|
633
|
16
|
|
|
|
|
|
av_push(inners, SvRV(all_nums_sv)); /* no SvREFCNT_inc() */ |
|
634
|
|
|
|
|
|
|
} |
|
635
|
32
|
|
|
|
|
|
SV *innerL = inner->args[0], |
|
636
|
32
|
|
|
|
|
|
*innerU = inner->args[1]; |
|
637
|
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
int cmp; |
|
639
|
|
|
|
|
|
|
|
|
640
|
32
|
100
|
|
|
|
|
if(innerL) { |
|
641
|
18
|
100
|
|
|
|
|
if(!all_nums->args[0] || (cmp = sv_numcmp(all_nums->args[0], innerL)) < 0) { |
|
|
|
100
|
|
|
|
|
|
|
642
|
17
|
|
|
|
|
|
SvREFCNT_dec(all_nums->args[0]); |
|
643
|
17
|
|
|
|
|
|
all_nums->args[0] = newSVsv_num(innerL); |
|
644
|
17
|
|
|
|
|
|
all_nums->flags = (all_nums->flags & ~NUMBOUND_LOWER_INCLUSIVE) |
|
645
|
17
|
|
|
|
|
|
| (inner->flags & NUMBOUND_LOWER_INCLUSIVE); |
|
646
|
|
|
|
|
|
|
} |
|
647
|
1
|
50
|
|
|
|
|
else if(cmp == 0 && !(inner->flags & NUMBOUND_LOWER_INCLUSIVE)) |
|
|
|
50
|
|
|
|
|
|
|
648
|
1
|
|
|
|
|
|
all_nums->flags &= ~NUMBOUND_LOWER_INCLUSIVE; |
|
649
|
|
|
|
|
|
|
} |
|
650
|
32
|
100
|
|
|
|
|
if(innerU) { |
|
651
|
18
|
100
|
|
|
|
|
if(!all_nums->args[1] || (cmp = sv_numcmp(all_nums->args[1], innerU)) > 0) { |
|
|
|
100
|
|
|
|
|
|
|
652
|
15
|
|
|
|
|
|
SvREFCNT_dec(all_nums->args[1]); |
|
653
|
15
|
|
|
|
|
|
all_nums->args[1] = newSVsv_num(innerU); |
|
654
|
15
|
|
|
|
|
|
all_nums->flags = (all_nums->flags & ~NUMBOUND_UPPER_INCLUSIVE) |
|
655
|
15
|
|
|
|
|
|
| (inner->flags & NUMBOUND_UPPER_INCLUSIVE); |
|
656
|
|
|
|
|
|
|
} |
|
657
|
3
|
100
|
|
|
|
|
else if(cmp == 0 && !(inner->flags & NUMBOUND_UPPER_INCLUSIVE)) |
|
|
|
50
|
|
|
|
|
|
|
658
|
1
|
|
|
|
|
|
all_nums->flags &= ~NUMBOUND_UPPER_INCLUSIVE; |
|
659
|
|
|
|
|
|
|
} |
|
660
|
|
|
|
|
|
|
} |
|
661
|
|
|
|
|
|
|
else |
|
662
|
6
|
|
|
|
|
|
av_push(inners, SvREFCNT_inc(innersv)); |
|
663
|
|
|
|
|
|
|
} |
|
664
|
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
/* it's possible we've now squashed all the Num* bounds into a single one |
|
666
|
|
|
|
|
|
|
* and nothing else is left */ |
|
667
|
19
|
100
|
|
|
|
|
if(all_nums_sv && av_count(inners) == 1) |
|
|
|
100
|
|
|
|
|
|
|
668
|
15
|
|
|
|
|
|
return all_nums_sv; |
|
669
|
|
|
|
|
|
|
} |
|
670
|
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
SV *ret; |
|
672
|
|
|
|
|
|
|
struct Constraint *c; |
|
673
|
6
|
|
|
|
|
|
alloc_constraint(&ret, &c, &constraint_All, 1); |
|
674
|
6
|
|
|
|
|
|
sv_2mortal(ret); |
|
675
|
|
|
|
|
|
|
|
|
676
|
6
|
100
|
|
|
|
|
c->args[0] = SvREFCNT_inc(inners); |
|
677
|
|
|
|
|
|
|
|
|
678
|
6
|
|
|
|
|
|
return ret; |
|
679
|
|
|
|
|
|
|
} |
|
680
|
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
#define MAKE_0ARG_CONSTRAINT(name) S_make_0arg_constraint(aTHX_ #name, &constraint_##name) |
|
682
|
98
|
|
|
|
|
|
static void S_make_0arg_constraint(pTHX_ const char *name, ConstraintFunc *func) |
|
683
|
|
|
|
|
|
|
{ |
|
684
|
98
|
|
|
|
|
|
HV *stash = gv_stashpvs("Data::Checks", GV_ADD); |
|
685
|
98
|
|
|
|
|
|
AV *exportok = get_av("Data::Checks::EXPORT_OK", GV_ADD); |
|
686
|
|
|
|
|
|
|
|
|
687
|
98
|
|
|
|
|
|
SV *namesv = newSVpvf("Data::Checks::%s", name); |
|
688
|
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
/* Before perl 5.38, XSUBs cannot be exported lexically. newCONSTSUB() makes |
|
690
|
|
|
|
|
|
|
* XSUBs. We'll have to build our own constant-value sub instead |
|
691
|
|
|
|
|
|
|
*/ |
|
692
|
|
|
|
|
|
|
|
|
693
|
98
|
|
|
|
|
|
I32 floor_ix = start_subparse(FALSE, 0); |
|
694
|
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
SV *sv; |
|
696
|
|
|
|
|
|
|
struct Constraint *constraint; |
|
697
|
98
|
|
|
|
|
|
alloc_constraint(&sv, &constraint, func, 0); |
|
698
|
|
|
|
|
|
|
|
|
699
|
98
|
|
|
|
|
|
OP *body = make_argcheck_ops(0, 0, 0, namesv); |
|
700
|
98
|
|
|
|
|
|
body = op_append_elem(OP_LINESEQ, |
|
701
|
|
|
|
|
|
|
body, |
|
702
|
|
|
|
|
|
|
newSTATEOP(0, NULL, |
|
703
|
|
|
|
|
|
|
newSVOP(OP_CONST, 0, sv))); |
|
704
|
|
|
|
|
|
|
|
|
705
|
98
|
|
|
|
|
|
CV *cv = newATTRSUB(floor_ix, newSVOP(OP_CONST, 0, namesv), NULL, NULL, body); |
|
706
|
98
|
|
|
|
|
|
cv_set_call_checker(cv, &ckcall_constfold, &PL_sv_undef); |
|
707
|
|
|
|
|
|
|
|
|
708
|
98
|
|
|
|
|
|
av_push(exportok, newSVpv(name, 0)); |
|
709
|
98
|
|
|
|
|
|
} |
|
710
|
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
static XOP xop_make_constraint; |
|
712
|
99
|
|
|
|
|
|
static OP *pp_make_constraint(pTHX) |
|
713
|
|
|
|
|
|
|
{ |
|
714
|
99
|
|
|
|
|
|
dSP; |
|
715
|
99
|
|
|
|
|
|
int nargs = PL_op->op_private; |
|
716
|
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
SV *ret; |
|
718
|
99
|
|
|
|
|
|
switch(nargs) { |
|
719
|
45
|
|
|
|
|
|
case 1: |
|
720
|
|
|
|
|
|
|
{ |
|
721
|
45
|
|
|
|
|
|
SV *(*mk_constraint)(pTHX_ SV *arg0) = |
|
722
|
45
|
|
|
|
|
|
(SV * (*)(pTHX_ SV *))cUNOP_AUX->op_aux; |
|
723
|
|
|
|
|
|
|
|
|
724
|
45
|
|
|
|
|
|
SV *arg0 = POPs; |
|
725
|
|
|
|
|
|
|
|
|
726
|
45
|
|
|
|
|
|
ret = (*mk_constraint)(aTHX_ arg0); |
|
727
|
45
|
|
|
|
|
|
break; |
|
728
|
|
|
|
|
|
|
} |
|
729
|
|
|
|
|
|
|
|
|
730
|
7
|
|
|
|
|
|
case 2: |
|
731
|
|
|
|
|
|
|
{ |
|
732
|
7
|
|
|
|
|
|
SV *(*mk_constraint)(pTHX_ SV *arg0, SV *arg1) = |
|
733
|
7
|
|
|
|
|
|
(SV * (*)(pTHX_ SV *, SV *))cUNOP_AUX->op_aux; |
|
734
|
|
|
|
|
|
|
|
|
735
|
7
|
|
|
|
|
|
SV *arg1 = POPs; |
|
736
|
7
|
|
|
|
|
|
SV *arg0 = POPs; |
|
737
|
|
|
|
|
|
|
|
|
738
|
7
|
|
|
|
|
|
ret = (*mk_constraint)(aTHX_ arg0, arg1); |
|
739
|
7
|
|
|
|
|
|
break; |
|
740
|
|
|
|
|
|
|
} |
|
741
|
|
|
|
|
|
|
|
|
742
|
47
|
|
|
|
|
|
case (U8)-1: |
|
743
|
|
|
|
|
|
|
{ |
|
744
|
47
|
|
|
|
|
|
SV *(*mk_constraint)(pTHX_ size_t nargs, SV **args) = |
|
745
|
47
|
|
|
|
|
|
(SV * (*)(pTHX_ size_t, SV **))cUNOP_AUX->op_aux; |
|
746
|
|
|
|
|
|
|
|
|
747
|
47
|
100
|
|
|
|
|
SV **svp = PL_stack_base + POPMARK + 1; |
|
748
|
47
|
|
|
|
|
|
size_t nargs = SP - svp + 1; |
|
749
|
47
|
|
|
|
|
|
SP -= nargs; |
|
750
|
|
|
|
|
|
|
|
|
751
|
47
|
100
|
|
|
|
|
if(!nargs) |
|
752
|
2
|
50
|
|
|
|
|
EXTEND(SP, 1); |
|
753
|
|
|
|
|
|
|
|
|
754
|
47
|
|
|
|
|
|
ret = (*mk_constraint)(aTHX_ nargs, svp); |
|
755
|
47
|
|
|
|
|
|
break; |
|
756
|
|
|
|
|
|
|
} |
|
757
|
|
|
|
|
|
|
|
|
758
|
0
|
|
|
|
|
|
default: |
|
759
|
0
|
|
|
|
|
|
croak("ARGH unreachable nargs=%d", nargs); |
|
760
|
|
|
|
|
|
|
} |
|
761
|
|
|
|
|
|
|
|
|
762
|
99
|
|
|
|
|
|
PUSHs(ret); |
|
763
|
|
|
|
|
|
|
|
|
764
|
99
|
|
|
|
|
|
RETURN; |
|
765
|
|
|
|
|
|
|
} |
|
766
|
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
#define MAKE_1ARG_CONSTRAINT(name) S_make_1arg_constraint(aTHX_ #name, &mk_constraint_##name) |
|
768
|
98
|
|
|
|
|
|
static void S_make_1arg_constraint(pTHX_ const char *name, SV *(*mk_constraint)(pTHX_ SV *arg0)) |
|
769
|
|
|
|
|
|
|
{ |
|
770
|
98
|
|
|
|
|
|
HV *stash = gv_stashpvs("Data::Checks", GV_ADD); |
|
771
|
98
|
|
|
|
|
|
HV *constraint_stash = gv_stashpvs("Data::Checks::Constraint", GV_ADD); |
|
772
|
98
|
|
|
|
|
|
AV *exportok = get_av("Data::Checks::EXPORT_OK", GV_ADD); |
|
773
|
|
|
|
|
|
|
|
|
774
|
98
|
|
|
|
|
|
SV *namesv = newSVpvf("Data::Checks::%s", name); |
|
775
|
|
|
|
|
|
|
|
|
776
|
98
|
|
|
|
|
|
I32 floor_ix = start_subparse(FALSE, 0); |
|
777
|
|
|
|
|
|
|
|
|
778
|
98
|
|
|
|
|
|
OP *mkop = newUNOP_AUX_CUSTOM(&pp_make_constraint, 0, |
|
779
|
|
|
|
|
|
|
newSLUGOP(0), |
|
780
|
|
|
|
|
|
|
(UNOP_AUX_item *)mk_constraint); |
|
781
|
98
|
|
|
|
|
|
mkop->op_private = 1; |
|
782
|
|
|
|
|
|
|
|
|
783
|
98
|
|
|
|
|
|
OP *body = make_argcheck_ops(1, 0, 0, namesv); |
|
784
|
98
|
|
|
|
|
|
body = op_append_elem(OP_LINESEQ, |
|
785
|
|
|
|
|
|
|
body, |
|
786
|
|
|
|
|
|
|
newSTATEOP(0, NULL, mkop)); |
|
787
|
|
|
|
|
|
|
|
|
788
|
98
|
|
|
|
|
|
CV *cv = newATTRSUB(floor_ix, newSVOP(OP_CONST, 0, namesv), NULL, NULL, body); |
|
789
|
98
|
|
|
|
|
|
cv_set_call_checker(cv, &ckcall_constfold, &PL_sv_undef); |
|
790
|
|
|
|
|
|
|
|
|
791
|
98
|
|
|
|
|
|
av_push(exportok, newSVpv(name, 0)); |
|
792
|
98
|
|
|
|
|
|
} |
|
793
|
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
#define MAKE_2ARG_CONSTRAINT(name) S_make_2arg_constraint(aTHX_ #name, &mk_constraint_##name) |
|
795
|
14
|
|
|
|
|
|
static void S_make_2arg_constraint(pTHX_ const char *name, SV *(*mk_constraint)(pTHX_ SV *arg0, SV *arg1)) |
|
796
|
|
|
|
|
|
|
{ |
|
797
|
14
|
|
|
|
|
|
HV *stash = gv_stashpvs("Data::Checks", GV_ADD); |
|
798
|
14
|
|
|
|
|
|
HV *constraint_stash = gv_stashpvs("Data::Checks::Constraint", GV_ADD); |
|
799
|
14
|
|
|
|
|
|
AV *exportok = get_av("Data::Checks::EXPORT_OK", GV_ADD); |
|
800
|
|
|
|
|
|
|
|
|
801
|
14
|
|
|
|
|
|
SV *namesv = newSVpvf("Data::Checks::%s", name); |
|
802
|
|
|
|
|
|
|
|
|
803
|
14
|
|
|
|
|
|
I32 floor_ix = start_subparse(FALSE, 0); |
|
804
|
|
|
|
|
|
|
|
|
805
|
14
|
|
|
|
|
|
OP *mkop = newUNOP_AUX_CUSTOM(&pp_make_constraint, 0, |
|
806
|
|
|
|
|
|
|
newLISTOPn(OP_LIST, OPf_WANT_LIST, newSLUGOP(0), newSLUGOP(1), NULL), |
|
807
|
|
|
|
|
|
|
(UNOP_AUX_item *)mk_constraint); |
|
808
|
14
|
|
|
|
|
|
mkop->op_private = 2; |
|
809
|
|
|
|
|
|
|
|
|
810
|
14
|
|
|
|
|
|
OP *body = make_argcheck_ops(2, 0, 0, namesv); |
|
811
|
14
|
|
|
|
|
|
body = op_append_elem(OP_LINESEQ, |
|
812
|
|
|
|
|
|
|
body, |
|
813
|
|
|
|
|
|
|
newSTATEOP(0, NULL, mkop)); |
|
814
|
|
|
|
|
|
|
|
|
815
|
14
|
|
|
|
|
|
CV *cv = newATTRSUB(floor_ix, newSVOP(OP_CONST, 0, namesv), NULL, NULL, body); |
|
816
|
14
|
|
|
|
|
|
cv_set_call_checker(cv, &ckcall_constfold, &PL_sv_undef); |
|
817
|
|
|
|
|
|
|
|
|
818
|
14
|
|
|
|
|
|
av_push(exportok, newSVpv(name, 0)); |
|
819
|
14
|
|
|
|
|
|
} |
|
820
|
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
#define MAKE_nARG_CONSTRAINT(name) S_make_narg_constraint(aTHX_ #name, &mk_constraint_##name) |
|
822
|
70
|
|
|
|
|
|
static void S_make_narg_constraint(pTHX_ const char *name, SV *(*mk_constraint)(pTHX_ size_t nargs, SV **args)) |
|
823
|
|
|
|
|
|
|
{ |
|
824
|
70
|
|
|
|
|
|
HV *stash = gv_stashpvs("Data::Checks", GV_ADD); |
|
825
|
70
|
|
|
|
|
|
HV *constraint_stash = gv_stashpvs("Data::Checks::Constraint", GV_ADD); |
|
826
|
70
|
|
|
|
|
|
AV *exportok = get_av("Data::Checks::EXPORT_OK", GV_ADD); |
|
827
|
|
|
|
|
|
|
|
|
828
|
70
|
|
|
|
|
|
SV *namesv = newSVpvf("Data::Checks::%s", name); |
|
829
|
|
|
|
|
|
|
|
|
830
|
70
|
|
|
|
|
|
I32 floor_ix = start_subparse(FALSE, 0); |
|
831
|
|
|
|
|
|
|
|
|
832
|
70
|
|
|
|
|
|
OP *mkop = newUNOP_AUX_CUSTOM(&pp_make_constraint, 0, |
|
833
|
|
|
|
|
|
|
op_force_list(newLISTOPn(OP_LIST, OPf_WANT_LIST, |
|
834
|
|
|
|
|
|
|
newUNOP(OP_RV2AV, OPf_WANT_LIST, newGVOP(OP_GV, 0, PL_defgv)), |
|
835
|
|
|
|
|
|
|
NULL)), |
|
836
|
|
|
|
|
|
|
(UNOP_AUX_item *)mk_constraint); |
|
837
|
70
|
|
|
|
|
|
mkop->op_private = -1; |
|
838
|
|
|
|
|
|
|
|
|
839
|
70
|
|
|
|
|
|
OP *body = make_argcheck_ops(0, 0, '@', namesv); |
|
840
|
70
|
|
|
|
|
|
body = op_append_elem(OP_LINESEQ, |
|
841
|
|
|
|
|
|
|
body, |
|
842
|
|
|
|
|
|
|
newSTATEOP(0, NULL, mkop)); |
|
843
|
|
|
|
|
|
|
|
|
844
|
70
|
|
|
|
|
|
CV *cv = newATTRSUB(floor_ix, newSVOP(OP_CONST, 0, namesv), NULL, NULL, body); |
|
845
|
70
|
|
|
|
|
|
cv_set_call_checker(cv, &ckcall_constfold, &PL_sv_undef); |
|
846
|
|
|
|
|
|
|
|
|
847
|
70
|
|
|
|
|
|
av_push(exportok, newSVpv(name, 0)); |
|
848
|
70
|
|
|
|
|
|
} |
|
849
|
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
/* This does NOT use SVf_quoted as that is intended for C's quoting |
|
851
|
|
|
|
|
|
|
* rules; we want qq()-style perlish ones. This means that $ and @ need to be |
|
852
|
|
|
|
|
|
|
* escaped as well. |
|
853
|
|
|
|
|
|
|
*/ |
|
854
|
|
|
|
|
|
|
#define sv_catsv_quoted(buf, sv, quote) S_sv_catsv_quoted(aTHX_ buf, sv, quote) |
|
855
|
21
|
|
|
|
|
|
static void S_sv_catsv_quoted(pTHX_ SV *buf, SV *sv, char quote) |
|
856
|
|
|
|
|
|
|
{ |
|
857
|
|
|
|
|
|
|
STRLEN len; |
|
858
|
21
|
|
|
|
|
|
const char *s = SvPV_const(sv, len); |
|
859
|
21
|
|
|
|
|
|
sv_catpvn(buf, "e, 1); |
|
860
|
131
|
100
|
|
|
|
|
for(STRLEN i = 0; i < len; i++) { |
|
861
|
110
|
50
|
|
|
|
|
if(len == 256) { |
|
862
|
0
|
|
|
|
|
|
sv_catpvs(buf, "..."); |
|
863
|
0
|
|
|
|
|
|
break; |
|
864
|
|
|
|
|
|
|
} |
|
865
|
110
|
|
|
|
|
|
char c = s[i]; |
|
866
|
110
|
50
|
|
|
|
|
if(c == '\\' || c == quote || (quote != '\'' && (c == '$' || c == '@'))) |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
867
|
3
|
|
|
|
|
|
sv_catpvs(buf, "\\"); |
|
868
|
|
|
|
|
|
|
/* TODO: UTF-8 */ |
|
869
|
110
|
|
|
|
|
|
sv_catpvn(buf, &c, 1); |
|
870
|
|
|
|
|
|
|
} |
|
871
|
21
|
|
|
|
|
|
sv_catpvn(buf, "e, 1); |
|
872
|
21
|
|
|
|
|
|
} |
|
873
|
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
#define sv_catsv_quoted_list(buf, av, quote, sep) S_sv_catsv_quoted_list(aTHX_ buf, av, quote, sep) |
|
875
|
4
|
|
|
|
|
|
static void S_sv_catsv_quoted_list(pTHX_ SV *buf, AV *av, char quote, char sep) |
|
876
|
|
|
|
|
|
|
{ |
|
877
|
4
|
|
|
|
|
|
U32 n = av_count(av); |
|
878
|
4
|
|
|
|
|
|
SV **vals = AvARRAY(av); |
|
879
|
14
|
100
|
|
|
|
|
for(U32 i = 0; i < n; i++) { |
|
880
|
10
|
100
|
|
|
|
|
if(i > 0) |
|
881
|
6
|
|
|
|
|
|
sv_catpvn(buf, &sep, 1), sv_catpvs(buf, " "); |
|
882
|
10
|
|
|
|
|
|
sv_catsv_quoted(buf, vals[i], quote); |
|
883
|
|
|
|
|
|
|
} |
|
884
|
4
|
|
|
|
|
|
} |
|
885
|
|
|
|
|
|
|
|
|
886
|
96
|
|
|
|
|
|
SV *DataChecks_stringify_constraint(pTHX_ struct Constraint *c) |
|
887
|
|
|
|
|
|
|
{ |
|
888
|
|
|
|
|
|
|
const char *name = NULL; |
|
889
|
96
|
|
|
|
|
|
SV *args = sv_2mortal(newSVpvn("", 0)); |
|
890
|
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
/* such a shame C doesn't let us use function addresses as case labels */ |
|
892
|
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
// 0arg |
|
894
|
96
|
100
|
|
|
|
|
if (c->func == &constraint_Defined) |
|
895
|
|
|
|
|
|
|
name = "Defined"; |
|
896
|
91
|
100
|
|
|
|
|
else if(c->func == &constraint_Object) |
|
897
|
|
|
|
|
|
|
name = "Object"; |
|
898
|
85
|
100
|
|
|
|
|
else if(c->func == &constraint_ArrayRef) |
|
899
|
|
|
|
|
|
|
name = "ArrayRef"; |
|
900
|
83
|
100
|
|
|
|
|
else if(c->func == &constraint_HashRef) |
|
901
|
|
|
|
|
|
|
name = "HashRef"; |
|
902
|
81
|
100
|
|
|
|
|
else if(c->func == &constraint_Callable) |
|
903
|
|
|
|
|
|
|
name = "Callable"; |
|
904
|
79
|
100
|
|
|
|
|
else if(c->func == &constraint_Num) |
|
905
|
|
|
|
|
|
|
name = "Num"; |
|
906
|
77
|
100
|
|
|
|
|
else if(c->func == &constraint_Str) |
|
907
|
|
|
|
|
|
|
name = "Str"; |
|
908
|
|
|
|
|
|
|
// 1arg |
|
909
|
58
|
100
|
|
|
|
|
else if(c->func == &constraint_Isa) { |
|
910
|
|
|
|
|
|
|
name = "Isa"; |
|
911
|
3
|
|
|
|
|
|
sv_catsv_quoted(args, c->args[0], '"'); |
|
912
|
|
|
|
|
|
|
} |
|
913
|
55
|
100
|
|
|
|
|
else if(c->func == &constraint_StrMatch) { |
|
914
|
|
|
|
|
|
|
name = "StrMatch"; |
|
915
|
2
|
|
|
|
|
|
sv_catpvs(args, "qr"); |
|
916
|
2
|
|
|
|
|
|
sv_catsv_quoted(args, c->args[0], '/'); |
|
917
|
|
|
|
|
|
|
} |
|
918
|
53
|
100
|
|
|
|
|
else if(c->func == &constraint_Maybe) { |
|
919
|
|
|
|
|
|
|
name = "Maybe"; |
|
920
|
2
|
|
|
|
|
|
args = stringify_constraint_sv(c->args[0]); |
|
921
|
|
|
|
|
|
|
} |
|
922
|
|
|
|
|
|
|
// 2arg |
|
923
|
51
|
100
|
|
|
|
|
else if(c->func == &constraint_NumBound) { |
|
924
|
26
|
100
|
|
|
|
|
if(!c->args[0]) |
|
925
|
7
|
100
|
|
|
|
|
name = (c->flags & NUMBOUND_UPPER_INCLUSIVE ) ? "NumLE" : "NumLT"; |
|
926
|
19
|
100
|
|
|
|
|
else if(!c->args[1]) |
|
927
|
7
|
100
|
|
|
|
|
name = (c->flags & NUMBOUND_LOWER_INCLUSIVE ) ? "NumGE" : "NumGT"; |
|
928
|
12
|
100
|
|
|
|
|
else if(c->flags == NUMBOUND_LOWER_INCLUSIVE) |
|
929
|
|
|
|
|
|
|
name = "NumRange"; |
|
930
|
|
|
|
|
|
|
else { |
|
931
|
|
|
|
|
|
|
/* This was optimised from an All() call on at least two different ones; |
|
932
|
|
|
|
|
|
|
* we'll have to just stringify it as best we can |
|
933
|
|
|
|
|
|
|
*/ |
|
934
|
|
|
|
|
|
|
name = "All"; |
|
935
|
11
|
100
|
|
|
|
|
sv_catpvf(args, "NumG%c(%" SVf "), NumL%c(%" SVf ")", |
|
|
|
100
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
(c->flags & NUMBOUND_LOWER_INCLUSIVE) ? 'E' : 'T', SVfARG(c->args[0]), |
|
937
|
|
|
|
|
|
|
(c->flags & NUMBOUND_UPPER_INCLUSIVE) ? 'E' : 'T', SVfARG(c->args[1])); |
|
938
|
|
|
|
|
|
|
} |
|
939
|
|
|
|
|
|
|
|
|
940
|
26
|
100
|
|
|
|
|
if(!SvCUR(args)) { |
|
941
|
20
|
100
|
|
|
|
|
if(c->args[0]) |
|
942
|
13
|
|
|
|
|
|
sv_catsv(args, c->args[0]); |
|
943
|
20
|
100
|
|
|
|
|
if(c->args[0] && c->args[1]) |
|
|
|
100
|
|
|
|
|
|
|
944
|
6
|
|
|
|
|
|
sv_catpvs(args, ", "); |
|
945
|
20
|
100
|
|
|
|
|
if(c->args[1]) |
|
946
|
13
|
|
|
|
|
|
sv_catsv(args, c->args[1]); |
|
947
|
|
|
|
|
|
|
} |
|
948
|
|
|
|
|
|
|
} |
|
949
|
|
|
|
|
|
|
// narg |
|
950
|
25
|
100
|
|
|
|
|
else if(c->func == &constraint_NumEq) { |
|
951
|
|
|
|
|
|
|
name = "NumEq"; |
|
952
|
5
|
100
|
|
|
|
|
if(SvTYPE(c->args[0]) != SVt_PVAV) |
|
953
|
3
|
|
|
|
|
|
sv_catsv(args, c->args[0]); |
|
954
|
|
|
|
|
|
|
else { |
|
955
|
2
|
|
|
|
|
|
U32 n = av_count((AV *)c->args[0]); |
|
956
|
2
|
|
|
|
|
|
SV **vals = AvARRAY(c->args[0]); |
|
957
|
7
|
100
|
|
|
|
|
for(U32 i = 0; i < n; i++) { |
|
958
|
5
|
100
|
|
|
|
|
if(i > 0) |
|
959
|
3
|
|
|
|
|
|
sv_catpvs(args, ", "); |
|
960
|
5
|
|
|
|
|
|
sv_catsv(args, vals[i]); |
|
961
|
|
|
|
|
|
|
} |
|
962
|
|
|
|
|
|
|
} |
|
963
|
|
|
|
|
|
|
} |
|
964
|
20
|
100
|
|
|
|
|
else if(c->func == &constraint_StrEq) { |
|
965
|
|
|
|
|
|
|
name = "StrEq"; |
|
966
|
7
|
100
|
|
|
|
|
if(SvTYPE(c->args[0]) == SVt_PVAV) |
|
967
|
2
|
|
|
|
|
|
sv_catsv_quoted_list(args, (AV *)c->args[0], '"', ','); |
|
968
|
|
|
|
|
|
|
else |
|
969
|
5
|
|
|
|
|
|
sv_catsv_quoted(args, c->args[0], '"'); |
|
970
|
|
|
|
|
|
|
} |
|
971
|
13
|
100
|
|
|
|
|
else if(c->func == &constraint_Can) { |
|
972
|
|
|
|
|
|
|
name = "Can"; |
|
973
|
3
|
100
|
|
|
|
|
if(SvTYPE(c->args[0]) == SVt_PVAV) |
|
974
|
2
|
|
|
|
|
|
sv_catsv_quoted_list(args, (AV *)c->args[0], '"', ','); |
|
975
|
|
|
|
|
|
|
else |
|
976
|
1
|
|
|
|
|
|
sv_catsv_quoted(args, c->args[0], '"'); |
|
977
|
|
|
|
|
|
|
} |
|
978
|
10
|
100
|
|
|
|
|
else if(c->func == &constraint_Any || c->func == &constraint_All) { |
|
|
|
50
|
|
|
|
|
|
|
979
|
10
|
100
|
|
|
|
|
name = (c->func == &constraint_Any) ? "Any" : "All"; |
|
980
|
10
|
100
|
|
|
|
|
if(c->args[0]) { |
|
981
|
8
|
|
|
|
|
|
U32 n = av_count((AV *)c->args[0]); |
|
982
|
8
|
|
|
|
|
|
SV **inners = AvARRAY(c->args[0]); |
|
983
|
27
|
100
|
|
|
|
|
for(U32 i = 0; i < n; i++) { |
|
984
|
19
|
100
|
|
|
|
|
if(i > 0) |
|
985
|
11
|
|
|
|
|
|
sv_catpvs(args, ", "); |
|
986
|
19
|
|
|
|
|
|
sv_catsv(args, stringify_constraint_sv(inners[i])); |
|
987
|
|
|
|
|
|
|
} |
|
988
|
|
|
|
|
|
|
} |
|
989
|
|
|
|
|
|
|
} |
|
990
|
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
else |
|
992
|
0
|
|
|
|
|
|
return newSVpvs_flags("TODO: debug inspect constraint", SVs_TEMP); |
|
993
|
|
|
|
|
|
|
|
|
994
|
96
|
|
|
|
|
|
SV *ret = newSVpvf("%s", name); |
|
995
|
96
|
100
|
|
|
|
|
if(SvCUR(args)) |
|
996
|
56
|
|
|
|
|
|
sv_catpvf(ret, "(%" SVf ")", SVfARG(args)); |
|
997
|
|
|
|
|
|
|
|
|
998
|
96
|
|
|
|
|
|
return sv_2mortal(ret); |
|
999
|
|
|
|
|
|
|
} |
|
1000
|
|
|
|
|
|
|
|
|
1001
|
14
|
|
|
|
|
|
void boot_Data_Checks__constraints(pTHX) |
|
1002
|
|
|
|
|
|
|
{ |
|
1003
|
14
|
|
|
|
|
|
MAKE_0ARG_CONSTRAINT(Defined); |
|
1004
|
14
|
|
|
|
|
|
MAKE_0ARG_CONSTRAINT(Object); |
|
1005
|
14
|
|
|
|
|
|
MAKE_0ARG_CONSTRAINT(Str); |
|
1006
|
14
|
|
|
|
|
|
MAKE_0ARG_CONSTRAINT(Num); |
|
1007
|
|
|
|
|
|
|
|
|
1008
|
14
|
|
|
|
|
|
MAKE_nARG_CONSTRAINT(StrEq); |
|
1009
|
14
|
|
|
|
|
|
MAKE_1ARG_CONSTRAINT(StrMatch); |
|
1010
|
|
|
|
|
|
|
|
|
1011
|
14
|
|
|
|
|
|
MAKE_1ARG_CONSTRAINT(NumGT); |
|
1012
|
14
|
|
|
|
|
|
MAKE_1ARG_CONSTRAINT(NumGE); |
|
1013
|
14
|
|
|
|
|
|
MAKE_1ARG_CONSTRAINT(NumLE); |
|
1014
|
14
|
|
|
|
|
|
MAKE_1ARG_CONSTRAINT(NumLT); |
|
1015
|
14
|
|
|
|
|
|
MAKE_2ARG_CONSTRAINT(NumRange); |
|
1016
|
14
|
|
|
|
|
|
MAKE_nARG_CONSTRAINT(NumEq); |
|
1017
|
|
|
|
|
|
|
|
|
1018
|
14
|
|
|
|
|
|
MAKE_1ARG_CONSTRAINT(Isa); |
|
1019
|
14
|
|
|
|
|
|
MAKE_nARG_CONSTRAINT(Can); |
|
1020
|
14
|
|
|
|
|
|
MAKE_0ARG_CONSTRAINT(ArrayRef); |
|
1021
|
14
|
|
|
|
|
|
MAKE_0ARG_CONSTRAINT(HashRef); |
|
1022
|
14
|
|
|
|
|
|
MAKE_0ARG_CONSTRAINT(Callable); |
|
1023
|
14
|
|
|
|
|
|
MAKE_1ARG_CONSTRAINT(Maybe); |
|
1024
|
14
|
|
|
|
|
|
MAKE_nARG_CONSTRAINT(Any); |
|
1025
|
14
|
|
|
|
|
|
MAKE_nARG_CONSTRAINT(All); |
|
1026
|
|
|
|
|
|
|
|
|
1027
|
14
|
|
|
|
|
|
XopENTRY_set(&xop_make_constraint, xop_name, "make_constraint"); |
|
1028
|
14
|
|
|
|
|
|
XopENTRY_set(&xop_make_constraint, xop_desc, "make constraint"); |
|
1029
|
14
|
|
|
|
|
|
XopENTRY_set(&xop_make_constraint, xop_class, OA_UNOP_AUX); |
|
1030
|
14
|
|
|
|
|
|
Perl_custom_op_register(aTHX_ &pp_make_constraint, &xop_make_constraint); |
|
1031
|
14
|
|
|
|
|
|
} |