File Coverage

Parameters.xs
Criterion Covered Total %
statement 1040 1170 88.8
branch 624 954 65.4
condition n/a
subroutine n/a
pod n/a
total 1664 2124 78.3


line stmt bran cond sub pod time code
1             /*
2             Copyright 2012, 2014, 2023 Lukas Mai.
3              
4             This program is free software; you can redistribute it and/or modify it
5             under the terms of either: the GNU General Public License as published
6             by the Free Software Foundation; or the Artistic License.
7              
8             See http://dev.perl.org/licenses/ for more information.
9             */
10              
11             #ifdef __GNUC__
12             #if __GNUC__ >= 5
13             #define IF_HAVE_GCC_5(X) X
14             #endif
15              
16             #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ >= 5
17             #define PRAGMA_GCC_(X) _Pragma(#X)
18             #define PRAGMA_GCC(X) PRAGMA_GCC_(GCC X)
19             #endif
20             #endif
21              
22             #ifndef IF_HAVE_GCC_5
23             #define IF_HAVE_GCC_5(X)
24             #endif
25              
26             #ifndef PRAGMA_GCC
27             #define PRAGMA_GCC(X)
28             #endif
29              
30             #ifdef DEVEL
31             #define WARNINGS_RESET PRAGMA_GCC(diagnostic pop)
32             #define WARNINGS_ENABLEW(X) PRAGMA_GCC(diagnostic error #X)
33             #define WARNINGS_ENABLE \
34             WARNINGS_ENABLEW(-Wall) \
35             WARNINGS_ENABLEW(-Wextra) \
36             WARNINGS_ENABLEW(-Wundef) \
37             WARNINGS_ENABLEW(-Wshadow) \
38             WARNINGS_ENABLEW(-Wbad-function-cast) \
39             WARNINGS_ENABLEW(-Wcast-align) \
40             WARNINGS_ENABLEW(-Wwrite-strings) \
41             WARNINGS_ENABLEW(-Wstrict-prototypes) \
42             WARNINGS_ENABLEW(-Wmissing-prototypes) \
43             WARNINGS_ENABLEW(-Winline) \
44             WARNINGS_ENABLEW(-Wdisabled-optimization) \
45             IF_HAVE_GCC_5(WARNINGS_ENABLEW(-Wnested-externs))
46              
47             #else
48             #define WARNINGS_RESET
49             #define WARNINGS_ENABLE
50             #endif
51              
52              
53             #define PERL_NO_GET_CONTEXT
54             #include "EXTERN.h"
55             #include "perl.h"
56             #include "XSUB.h"
57              
58             #include
59              
60             #ifdef DEVEL
61             #undef NDEBUG
62             #include
63             #endif
64              
65             #ifdef PERL_MAD
66             #error "MADness is not supported."
67             #endif
68              
69             #define HAVE_PERL_VERSION(R, V, S) \
70             (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
71              
72             #if HAVE_PERL_VERSION(5, 19, 3)
73             #define IF_HAVE_PERL_5_19_3(YES, NO) YES
74             #else
75             #define IF_HAVE_PERL_5_19_3(YES, NO) NO
76             #endif
77              
78             #ifndef SvREFCNT_dec_NN
79             #define SvREFCNT_dec_NN(SV) SvREFCNT_dec(SV)
80             #endif
81              
82              
83             #define MY_PKG "Function::Parameters"
84              
85             /* 5.22+ shouldn't require any hax */
86             #if !HAVE_PERL_VERSION(5, 22, 0)
87              
88             #if !HAVE_PERL_VERSION(5, 16, 0)
89             #include "hax/pad_alloc.c.inc"
90             #include "hax/pad_add_name_sv.c.inc"
91             #include "hax/pad_add_name_pvs.c.inc"
92              
93             #ifndef padadd_NO_DUP_CHECK
94             #define padadd_NO_DUP_CHECK 0
95             #endif
96             #endif
97              
98             #include "hax/newDEFSVOP.c.inc"
99             #include "hax/intro_my.c.inc"
100             #include "hax/block_start.c.inc"
101             #include "hax/block_end.c.inc"
102              
103             #include "hax/op_convert_list.c.inc" /* < 5.22 */
104             #include "hax/STATIC_ASSERT_STMT.c.inc"
105             #endif
106              
107              
108             WARNINGS_ENABLE
109              
110             #define HAVE_BUG_GH_15557 (HAVE_PERL_VERSION(5, 21, 7) && !HAVE_PERL_VERSION(5, 25, 5))
111              
112             #define HINTK_CONFIG MY_PKG "/config"
113             #define HINTSK_FLAGS "flags"
114             #define HINTSK_SHIFT "shift"
115             #define HINTSK_SHIF2 "shift_types"
116             #define HINTSK_ATTRS "attrs"
117             #define HINTSK_REIFY "reify"
118             #define HINTSK_INSTL "instl"
119              
120             #define DEFSTRUCT(T) typedef struct T T; struct T
121              
122             #define VEC(B) B ## _Vec
123              
124             #define DEFVECTOR(B) DEFSTRUCT(VEC(B)) { \
125             B (*data); \
126             size_t used, size; \
127             }
128              
129             #define DEFVECTOR_INIT(N, B) static void N(VEC(B) *p) { \
130             p->used = 0; \
131             p->size = 23; \
132             Newx(p->data, p->size, B); \
133             } static void N(VEC(B) *)
134              
135             #define DEFVECTOR_EXTEND(N, B) static B (*N(VEC(B) *p)) { \
136             assert(p->used <= p->size); \
137             if (p->used == p->size) { \
138             const size_t n = p->size / 2 * 3 + 1; \
139             Renew(p->data, n, B); \
140             p->size = n; \
141             } \
142             return &p->data[p->used]; \
143             } static B (*N(VEC(B) *))
144              
145             #define DEFVECTOR_CLEAR_GENERIC(N, N_PARAM_, B, F, F_ARG_) static void N(N_PARAM_ VEC(B) *p) { \
146             while (p->used) { \
147             p->used--; \
148             F(F_ARG_ &p->data[p->used]); \
149             } \
150             Safefree(p->data); \
151             p->data = NULL; \
152             p->size = 0; \
153             } static void N(N_PARAM_ VEC(B) *)
154              
155             #define DEFVECTOR_CLEAR(N, B, F) DEFVECTOR_CLEAR_GENERIC(N, , B, F, )
156             #define DEFVECTOR_CLEAR_THX(N, B, F) DEFVECTOR_CLEAR_GENERIC(N, pTHX_, B, F, aTHX_)
157              
158             enum {
159             FLAG_NAME_OK = 0x001,
160             FLAG_ANON_OK = 0x002,
161             FLAG_DEFAULT_ARGS = 0x004,
162             FLAG_CHECK_NARGS = 0x008,
163             FLAG_INVOCANT = 0x010,
164             FLAG_NAMED_PARAMS = 0x020,
165             FLAG_TYPES_OK = 0x040,
166             FLAG_CHECK_TARGS = 0x080,
167             FLAG_RUNTIME = 0x100
168             };
169              
170             DEFSTRUCT(SpecParam) {
171             SV *name;
172             SV *type;
173             };
174              
175             DEFVECTOR(SpecParam);
176 1236 50         DEFVECTOR_INIT(spv_init, SpecParam);
177              
178 196           static void sp_clear(SpecParam *p) {
179 196           p->name = NULL;
180 196           p->type = NULL;
181 196           }
182              
183 1432 100         DEFVECTOR_CLEAR(spv_clear, SpecParam, sp_clear);
184              
185 392 50         DEFVECTOR_EXTEND(spv_extend, SpecParam);
    0          
186              
187 196           static void spv_push(VEC(SpecParam) *ps, SV *name, SV *type) {
188 196           SpecParam *p = spv_extend(ps);
189 196           p->name = name;
190 196           p->type = type;
191 196           ps->used++;
192 196           }
193              
194             DEFSTRUCT(KWSpec) {
195             unsigned flags;
196             SV *reify_type;
197             VEC(SpecParam) shift;
198             SV *attrs;
199             SV *install_sub;
200             };
201              
202 618           static void kws_free_void(pTHX_ void *p) {
203 618           KWSpec *const spec = p;
204             PERL_UNUSED_CONTEXT;
205 618           spv_clear(&spec->shift);
206 618           spec->attrs = NULL;
207 618           spec->install_sub = NULL;
208 618           Safefree(spec);
209 618           }
210              
211             DEFSTRUCT(Resource) {
212             Resource *next;
213             void *data;
214             void (*destroy)(pTHX_ void *);
215             };
216              
217             typedef Resource *Sentinel[1];
218              
219 618           static void sentinel_clear_void(pTHX_ void *pv) {
220 618           Resource **pp = pv;
221 618           Resource *p = *pp;
222 618           Safefree(pp);
223 7312 100         while (p) {
224 6694           Resource *cur = p;
225 6694 50         if (cur->destroy) {
226 6694           cur->destroy(aTHX_ cur->data);
227             }
228 6694           cur->data = (void *)"no";
229 6694           cur->destroy = NULL;
230 6694           p = cur->next;
231 6694           Safefree(cur);
232             }
233 618           }
234              
235 6694           static Resource *sentinel_register(Sentinel sen, void *data, void (*destroy)(pTHX_ void *)) {
236             Resource *cur;
237              
238 6694           Newx(cur, 1, Resource);
239 6694           cur->data = data;
240 6694           cur->destroy = destroy;
241 6694           cur->next = *sen;
242 6694           *sen = cur;
243              
244 6694           return cur;
245             }
246              
247 0           static void sentinel_disarm(Resource *p) {
248 0           p->destroy = NULL;
249 0           }
250              
251 3682           static void my_sv_refcnt_dec_void(pTHX_ void *p) {
252 3682           SV *sv = p;
253 3682           SvREFCNT_dec(sv);
254 3682           }
255              
256 3682           static SV *sentinel_mortalize(Sentinel sen, SV *sv) {
257 3682           sentinel_register(sen, sv, my_sv_refcnt_dec_void);
258 3682           return sv;
259             }
260              
261              
262             #if HAVE_PERL_VERSION(5, 17, 2)
263             #define MY_OP_SLABBED(O) ((O)->op_slabbed)
264             #else
265             #define MY_OP_SLABBED(O) 0
266             #endif
267              
268             DEFSTRUCT(OpGuard) {
269             OP *op;
270             bool needs_freed;
271             };
272              
273 3135           static void op_guard_init(OpGuard *p) {
274 3135           p->op = NULL;
275 3135           p->needs_freed = FALSE;
276 3135           }
277              
278 131           static OpGuard op_guard_transfer(OpGuard *p) {
279 131           OpGuard r = *p;
280 131           op_guard_init(p);
281 131           return r;
282             }
283              
284 1213           static OP *op_guard_relinquish(OpGuard *p) {
285 1213           OP *o = p->op;
286 1213           op_guard_init(p);
287 1213           return o;
288             }
289              
290 2115           static void op_guard_update(OpGuard *p, OP *o) {
291 2115           p->op = o;
292 2115 100         p->needs_freed = o && !MY_OP_SLABBED(o);
    50          
293 2115           }
294              
295 1922           static void op_guard_clear(pTHX_ OpGuard *p) {
296 1922 50         if (p->needs_freed) {
297 0           op_free(p->op);
298             }
299 1922           }
300              
301 1791           static void free_op_guard_void(pTHX_ void *vp) {
302 1791           OpGuard *p = vp;
303 1791           op_guard_clear(aTHX_ p);
304 1791           Safefree(p);
305 1791           }
306              
307 0           static void free_op_void(pTHX_ void *vp) {
308 0           OP *p = vp;
309 0           op_free(p);
310 0           }
311              
312             #define sv_eq_pvs(SV, S) my_sv_eq_pvn(aTHX_ SV, "" S "", sizeof S - 1)
313              
314 3017           static int my_sv_eq_pvn(pTHX_ SV *sv, const char *p, STRLEN n) {
315             STRLEN sv_len;
316 3017 50         const char *sv_p = SvPV(sv, sv_len);
317 3017 100         return sv_len == n && memcmp(sv_p, p, n) == 0;
    100          
318             }
319              
320              
321             #ifndef newMETHOP
322             #define newMETHOP newUNOP
323             #endif
324              
325             enum {
326             MY_ATTR_LVALUE = 0x01,
327             MY_ATTR_METHOD = 0x02,
328             MY_ATTR_SPECIAL = 0x04
329             };
330              
331 11149           static void my_sv_cat_c(pTHX_ SV *sv, U32 c) {
332             char ds[UTF8_MAXBYTES + 1], *d;
333 11149           d = (char *)uvchr_to_utf8((U8 *)ds, c);
334 11149 100         if (d - ds > 1) {
335 28           sv_utf8_upgrade(sv);
336             }
337 11149           sv_catpvn(sv, ds, d - ds);
338 11149           }
339              
340              
341             #define MY_UNI_IDFIRST(C) isIDFIRST_uni(C)
342             #define MY_UNI_IDCONT(C) isALNUM_uni(C)
343             #if HAVE_PERL_VERSION(5, 25, 9)
344             #define MY_UNI_IDFIRST_utf8(P, Z) isIDFIRST_utf8_safe((const unsigned char *)(P), (const unsigned char *)(Z))
345             #define MY_UNI_IDCONT_utf8(P, Z) isWORDCHAR_utf8_safe((const unsigned char *)(P), (const unsigned char *)(Z))
346             #else
347             #define MY_UNI_IDFIRST_utf8(P, Z) isIDFIRST_utf8((const unsigned char *)(P))
348             #define MY_UNI_IDCONT_utf8(P, Z) isALNUM_utf8((const unsigned char *)(P))
349             #endif
350              
351 2029           static SV *my_scan_word(pTHX_ Sentinel sen, bool allow_package) {
352             bool at_start, at_substart;
353             I32 c;
354 2029           SV *sv = sentinel_mortalize(sen, newSVpvs(""));
355 2029 100         if (lex_bufutf8()) {
356 31           SvUTF8_on(sv);
357             }
358              
359 2029           at_start = at_substart = TRUE;
360 2029           c = lex_peek_unichar(0);
361              
362 12972 50         while (c != -1) {
363 12972 100         if (at_substart ? MY_UNI_IDFIRST(c) : MY_UNI_IDCONT(c)) {
    100          
    50          
    100          
    100          
    50          
    100          
    100          
364 10915           lex_read_unichar(0);
365 10915           my_sv_cat_c(aTHX_ sv, c);
366 10915           at_substart = FALSE;
367 10915           c = lex_peek_unichar(0);
368 2057 100         } else if (allow_package && !at_substart && c == '\'') {
    100          
    50          
369 0           lex_read_unichar(0);
370 0           c = lex_peek_unichar(0);
371 0 0         if (!MY_UNI_IDFIRST(c)) {
    0          
    0          
    0          
372 0           lex_stuff_pvs("'", 0);
373 0           break;
374             }
375 0           sv_catpvs(sv, "'");
376 0           at_substart = TRUE;
377 2057 100         } else if (allow_package && (at_start || !at_substart) && c == ':') {
    100          
    50          
    100          
378 30           lex_read_unichar(0);
379 30 50         if (lex_peek_unichar(0) != ':') {
380 0           lex_stuff_pvs(":", 0);
381 0           break;
382             }
383 30           lex_read_unichar(0);
384 30           c = lex_peek_unichar(0);
385 30 50         if (!MY_UNI_IDFIRST(c)) {
    50          
    100          
    100          
386 2           lex_stuff_pvs("::", 0);
387 2           break;
388             }
389 28           sv_catpvs(sv, "::");
390 28           at_substart = TRUE;
391             } else {
392             break;
393             }
394 10943           at_start = FALSE;
395             }
396              
397 2029 100         return SvCUR(sv) ? sv : NULL;
398             }
399              
400 68           static SV *my_scan_parens_tail(pTHX_ Sentinel sen, bool keep_backslash) {
401             I32 c, nesting;
402             SV *sv;
403             line_t start;
404              
405 68           start = CopLINE(PL_curcop);
406              
407 68           sv = sentinel_mortalize(sen, newSVpvs(""));
408 68 50         if (lex_bufutf8()) {
409 0           SvUTF8_on(sv);
410             }
411              
412 68           nesting = 0;
413             for (;;) {
414 242           c = lex_read_unichar(0);
415 242 50         if (c == EOF) {
416 0           CopLINE_set(PL_curcop, start);
417 0           return NULL;
418             }
419              
420 242 100         if (c == '\\') {
421 26           c = lex_read_unichar(0);
422 26 50         if (c == EOF) {
423 0           CopLINE_set(PL_curcop, start);
424 0           return NULL;
425             }
426 26 50         if (keep_backslash || (c != '(' && c != ')')) {
    0          
    0          
427 26           sv_catpvs(sv, "\\");
428             }
429 216 50         } else if (c == '(') {
430 0           nesting++;
431 216 100         } else if (c == ')') {
432 68 50         if (!nesting) {
433 68           break;
434             }
435 0           nesting--;
436             }
437              
438 174           my_sv_cat_c(aTHX_ sv, c);
439 174           }
440              
441 68           return sv;
442             }
443              
444 67           static void my_check_prototype(pTHX_ Sentinel sen, const SV *declarator, SV *proto) {
445             char *start, *r, *w, *end;
446             STRLEN len;
447              
448             /* strip spaces */
449 67 50         start = SvPVbyte_force(proto, len);
450 67           end = start + len;
451              
452 266 100         for (w = r = start; r < end; r++) {
453 199 100         if (!isSPACE(*r)) {
454 178           *w++ = *r;
455             }
456             }
457 67           *w = '\0';
458 67           SvCUR_set(proto, w - start);
459 67           end = w;
460 67           len = end - start;
461              
462 67 100         if (!ckWARN(WARN_ILLEGALPROTO)) {
463 22           return;
464             }
465              
466             /* check for bad characters */
467 45 50         if (strspn(start, "$@%*;[]&\\_+") != len) {
468 0           SV *dsv = sentinel_mortalize(sen, newSVpvs(""));
469 0 0         warner(
470             packWARN(WARN_ILLEGALPROTO),
471             "Illegal character in prototype for %"SVf" : %s",
472             SVfARG(declarator),
473 0           SvUTF8(proto)
474 0           ? sv_uni_display(
475             dsv,
476             proto,
477             len,
478             UNI_DISPLAY_ISPRINT
479             )
480 0           : pv_pretty(dsv, start, len, 60, NULL, NULL,
481             PERL_PV_ESCAPE_NONASCII
482             )
483             );
484 0           return;
485             }
486              
487 81 100         for (r = start; r < end; r++) {
488 58           switch (*r) {
489             default:
490 6           warner(
491             packWARN(WARN_ILLEGALPROTO),
492             "Illegal character in prototype for %"SVf" : %s",
493             SVfARG(declarator), r
494             );
495 0           return;
496              
497             case '_':
498 11 100         if (r[1] && !strchr(";@%", r[1])) {
    100          
499 6           warner(
500             packWARN(WARN_ILLEGALPROTO),
501             "Illegal character after '_' in prototype for %"SVf" : %s",
502             SVfARG(declarator), r + 1
503             );
504 0           return;
505             }
506 5           break;
507              
508             case '@':
509             case '%':
510 5 50         if (r[1]) {
511 0           warner(
512             packWARN(WARN_ILLEGALPROTO),
513             "prototype after '%c' for %"SVf": %s",
514 0           *r, SVfARG(declarator), r + 1
515             );
516 0           return;
517             }
518 5           break;
519              
520             case '\\':
521 12           r++;
522 12 100         if (strchr("$@%&*", *r)) {
523 2           break;
524             }
525 10 100         if (*r == '[') {
526 4           r++;
527 4 50         for (; r < end && *r != ']'; r++) {
    50          
528 4 50         if (!strchr("$@%&*", *r)) {
529 4           break;
530             }
531             }
532 4 50         if (*r == ']' && r[-1] != '[') {
    0          
533 0           break;
534             }
535             }
536 10           warner(
537             packWARN(WARN_ILLEGALPROTO),
538             "Illegal character after '\\' in prototype for %"SVf" : %s",
539             SVfARG(declarator), r
540             );
541 0           return;
542              
543             case '$':
544             case '*':
545             case '&':
546             case ';':
547             case '+':
548 24           break;
549             }
550             }
551             }
552              
553             static SV *parse_type(pTHX_ Sentinel, const SV *, char);
554              
555 75           static SV *parse_type_paramd(pTHX_ Sentinel sen, const SV *declarator, char prev) {
556             I32 c;
557             SV *t;
558              
559 75 100         if (!(t = my_scan_word(aTHX_ sen, TRUE))) {
560 1           Perl_croak(aTHX_ "In %"SVf": missing type name after '%c'", SVfARG(declarator), prev);
561             }
562 74           lex_read_space(0);
563              
564 74           c = lex_peek_unichar(0);
565 74 100         if (c == '[') {
566             do {
567             SV *u;
568              
569 22           lex_read_unichar(0);
570 22           lex_read_space(0);
571 22           my_sv_cat_c(aTHX_ t, c);
572              
573 22           u = parse_type(aTHX_ sen, declarator, c);
574 21           sv_catsv(t, u);
575              
576 21           c = lex_peek_unichar(0);
577 21 100         } while (c == ',');
578 13 50         if (c != ']') {
579 0           Perl_croak(aTHX_ "In %"SVf": missing ']' after '%"SVf"'", SVfARG(declarator), SVfARG(t));
580             }
581 13           lex_read_unichar(0);
582 13           lex_read_space(0);
583              
584 13           my_sv_cat_c(aTHX_ t, c);
585             }
586              
587 73           return t;
588             }
589              
590 77           static SV *parse_type_term(pTHX_ Sentinel sen, const SV *declarator, char prev) {
591             I32 c;
592             SV *t, *u;
593              
594 77           t = sentinel_mortalize(sen, newSVpvs(""));
595              
596 81 100         while ((c = lex_peek_unichar(0)) == '~') {
597 4           lex_read_unichar(0);
598 4           lex_read_space(0);
599              
600 4           my_sv_cat_c(aTHX_ t, c);
601 4           prev = c;
602             }
603              
604 77 100         if (c == '(') {
605 2           lex_read_unichar(0);
606 2           lex_read_space(0);
607              
608 2           my_sv_cat_c(aTHX_ t, c);
609 2           u = parse_type(aTHX_ sen, declarator, c);
610 2           sv_catsv(t, u);
611              
612 2           c = lex_peek_unichar(0);
613 2 50         if (c != ')') {
614 0           Perl_croak(aTHX_ "In %"SVf": missing ')' after '%"SVf"'", SVfARG(declarator), SVfARG(t));
615             }
616 2           my_sv_cat_c(aTHX_ t, c);
617 2           lex_read_unichar(0);
618 2           lex_read_space(0);
619              
620 2           return t;
621             }
622              
623 75           u = parse_type_paramd(aTHX_ sen, declarator, prev);
624 73           sv_catsv(t, u);
625 73           return t;
626             }
627              
628 75           static SV *parse_type_alt(pTHX_ Sentinel sen, const SV *declarator, char prev) {
629             I32 c;
630             SV *t;
631              
632 75           t = parse_type_term(aTHX_ sen, declarator, prev);
633              
634 75 100         while ((c = lex_peek_unichar(0)) == '/') {
635             SV *u;
636              
637 2           lex_read_unichar(0);
638 2           lex_read_space(0);
639              
640 2           my_sv_cat_c(aTHX_ t, c);
641 2           u = parse_type_term(aTHX_ sen, declarator, c);
642 2           sv_catsv(t, u);
643             }
644              
645 73           return t;
646             }
647              
648 71           static SV *parse_type_intersect(pTHX_ Sentinel sen, const SV *declarator, char prev) {
649             I32 c;
650             SV *t;
651              
652 71           t = parse_type_alt(aTHX_ sen, declarator, prev);
653              
654 73 100         while ((c = lex_peek_unichar(0)) == '&') {
655             SV *u;
656              
657 4           lex_read_unichar(0);
658 4           lex_read_space(0);
659              
660 4           my_sv_cat_c(aTHX_ t, c);
661 4           u = parse_type_alt(aTHX_ sen, declarator, c);
662 4           sv_catsv(t, u);
663             }
664              
665 69           return t;
666             }
667              
668 60           static SV *parse_type(pTHX_ Sentinel sen, const SV *declarator, char prev) {
669             I32 c;
670             SV *t;
671              
672 60           t = parse_type_intersect(aTHX_ sen, declarator, prev);
673              
674 69 100         while ((c = lex_peek_unichar(0)) == '|') {
675             SV *u;
676              
677 11           lex_read_unichar(0);
678 11           lex_read_space(0);
679              
680 11           my_sv_cat_c(aTHX_ t, c);
681 11           u = parse_type_intersect(aTHX_ sen, declarator, c);
682 11           sv_catsv(t, u);
683             }
684              
685 58           return t;
686             }
687              
688 62           static SV *call_from_curstash(pTHX_ Sentinel sen, SV *sv, SV **args, size_t nargs, I32 flags) {
689             SV *r;
690             COP curcop_with_stash;
691             I32 want;
692 62           dSP;
693              
694             assert(sv != NULL);
695              
696 62 100         if ((flags & G_WANT) == 0) {
697 58           flags |= G_SCALAR;
698             }
699 62           want = flags & G_WANT;
700              
701 62           ENTER;
702 62           SAVETMPS;
703              
704 62 50         PUSHMARK(SP);
705 62 100         if (!args) {
706 12           flags |= G_NOARGS;
707             } else {
708             size_t i;
709 50 50         EXTEND(SP, (SSize_t)nargs);
    50          
710 104 100         for (i = 0; i < nargs; i++) {
711 54           PUSHs(args[i]);
712             }
713             }
714 62           PUTBACK;
715              
716             assert(PL_curcop == &PL_compiling);
717 62           curcop_with_stash = PL_compiling;
718 62           CopSTASH_set(&curcop_with_stash, PL_curstash);
719 62           PL_curcop = &curcop_with_stash;
720 62           call_sv(sv, flags);
721 59           PL_curcop = &PL_compiling;
722              
723 59 100         if (want == G_VOID) {
724 4           r = NULL;
725             } else {
726             assert(want == G_SCALAR);
727 55           SPAGAIN;
728 55           r = sentinel_mortalize(sen, SvREFCNT_inc(POPs));
729 55           PUTBACK;
730             }
731              
732 59 100         FREETMPS;
733 59           LEAVE;
734              
735 59           return r;
736             }
737              
738 40           static SV *reify_type(pTHX_ Sentinel sen, const SV *declarator, const KWSpec *spec, SV *name) {
739             SV *t;
740              
741 40           t = call_from_curstash(aTHX_ sen, spec->reify_type, &name, 1, 0);
742              
743 37 50         if (!sv_isobject(t)) {
744 0           Perl_croak(aTHX_ "In %"SVf": invalid type '%"SVf"' (%"SVf" is not a type object)", SVfARG(declarator), SVfARG(name), SVfARG(t));
745             }
746              
747 37           return t;
748             }
749              
750              
751             DEFSTRUCT(Param) {
752             SV *name;
753             PADOFFSET padoff;
754             SV *type;
755             };
756              
757             typedef enum {
758             ICOND_EXISTS,
759             ICOND_DEFINED
760             } InitCond;
761              
762             DEFSTRUCT(ParamInit) {
763             Param param;
764             OpGuard init;
765             InitCond cond;
766             };
767              
768             DEFVECTOR(Param);
769             DEFVECTOR(ParamInit);
770              
771             DEFSTRUCT(ParamSpec) {
772             size_t shift;
773             VEC(Param) positional_required;
774             VEC(ParamInit) positional_optional;
775             VEC(Param) named_required;
776             VEC(ParamInit) named_optional;
777             Param slurpy;
778             PADOFFSET rest_hash;
779             };
780              
781 2412 50         DEFVECTOR_INIT(pv_init, Param);
782 2412 50         DEFVECTOR_INIT(piv_init, ParamInit);
783              
784 760           static void p_init(Param *p) {
785 760           p->name = NULL;
786 760           p->padoff = NOT_IN_PAD;
787 760           p->type = NULL;
788 760           }
789              
790 603           static void ps_init(ParamSpec *ps) {
791 603           ps->shift = 0;
792 603           pv_init(&ps->positional_required);
793 603           piv_init(&ps->positional_optional);
794 603           pv_init(&ps->named_required);
795 603           piv_init(&ps->named_optional);
796 603           p_init(&ps->slurpy);
797 603           ps->rest_hash = NOT_IN_PAD;
798 603           }
799              
800 1380 100         DEFVECTOR_EXTEND(pv_extend, Param);
    50          
801 262 50         DEFVECTOR_EXTEND(piv_extend, ParamInit);
    0          
802              
803 690           static void pv_push(VEC(Param) *ps, SV *name, PADOFFSET padoff, SV *type) {
804 690           Param *p = pv_extend(ps);
805 690           p->name = name;
806 690           p->padoff = padoff;
807 690           p->type = type;
808 690           ps->used++;
809 690           }
810              
811 151           static Param *pv_unshift(VEC(Param) *ps, size_t n) {
812             size_t i;
813             assert(ps->used <= ps->size);
814 151 50         if (ps->used + n > ps->size) {
815 0           const size_t n2 = ps->used + n + 10;
816 0 0         Renew(ps->data, n2, Param);
817 0           ps->size = n2;
818             }
819 151 50         Move(ps->data, ps->data + n, ps->used, Param);
820 308 100         for (i = 0; i < n; i++) {
821 157           p_init(&ps->data[i]);
822             }
823 151           ps->used += n;
824 151           return ps->data;
825             }
826              
827 1581           static void p_clear(Param *p) {
828 1581           p->name = NULL;
829 1581           p->padoff = NOT_IN_PAD;
830 1581           p->type = NULL;
831 1581           }
832              
833 131           static void pi_clear(pTHX_ ParamInit *pi) {
834 131           p_clear(&pi->param);
835 131           op_guard_clear(aTHX_ &pi->init);
836 131           }
837              
838 3259 100         DEFVECTOR_CLEAR(pv_clear, Param, p_clear);
839 2543 100         DEFVECTOR_CLEAR_THX(piv_clear, ParamInit, pi_clear);
840              
841 603           static void ps_clear(pTHX_ ParamSpec *ps) {
842 603           pv_clear(&ps->positional_required);
843 603           piv_clear(aTHX_ &ps->positional_optional);
844              
845 603           pv_clear(&ps->named_required);
846 603           piv_clear(aTHX_ &ps->named_optional);
847              
848 603           p_clear(&ps->slurpy);
849 603           }
850              
851 964           static int ps_contains(pTHX_ const ParamSpec *ps, SV *sv) {
852             size_t i, lim;
853              
854 46576 100         for (i = 0, lim = ps->positional_required.used; i < lim; i++) {
855 45614 100         if (sv_eq(sv, ps->positional_required.data[i].name)) {
856 2           return 1;
857             }
858             }
859              
860 1032 100         for (i = 0, lim = ps->positional_optional.used; i < lim; i++) {
861 70 50         if (sv_eq(sv, ps->positional_optional.data[i].param.name)) {
862 0           return 1;
863             }
864             }
865              
866 1065 100         for (i = 0, lim = ps->named_required.used; i < lim; i++) {
867 104 100         if (sv_eq(sv, ps->named_required.data[i].name)) {
868 1           return 1;
869             }
870             }
871              
872 973 100         for (i = 0, lim = ps->named_optional.used; i < lim; i++) {
873 12 50         if (sv_eq(sv, ps->named_optional.data[i].param.name)) {
874 0           return 1;
875             }
876             }
877              
878 961           return 0;
879             }
880              
881 603           static void ps_free_void(pTHX_ void *p) {
882 603           ps_clear(aTHX_ p);
883 603           Safefree(p);
884 603           }
885              
886 525           static int args_min(const ParamSpec *ps) {
887 525           return ps->positional_required.used + ps->named_required.used * 2;
888             }
889              
890 525           static int args_max(const ParamSpec *ps) {
891 525 100         if (ps->named_required.used || ps->named_optional.used || ps->slurpy.name) {
    100          
    100          
892 60           return -1;
893             }
894 465           return ps->positional_required.used + ps->positional_optional.used;
895             }
896              
897 29           static size_t count_positional_params(const ParamSpec *ps) {
898 29           return ps->positional_required.used + ps->positional_optional.used;
899             }
900              
901 2379           static size_t count_named_params(const ParamSpec *ps) {
902 2379           return ps->named_required.used + ps->named_optional.used;
903             }
904              
905 12           static SV *my_eval(pTHX_ Sentinel sen, I32 floor_ix, OP *op) {
906             CV *cv;
907 12           cv = newATTRSUB(floor_ix, NULL, NULL, NULL, op);
908 12           return call_from_curstash(aTHX_ sen, (SV *)cv, NULL, 0, 0);
909             }
910              
911 1395           static OP *my_var_g(pTHX_ I32 type, I32 flags, PADOFFSET padoff) {
912 1395           OP *var = newOP(type, flags);
913 1395           var->op_targ = padoff;
914 1395           return var;
915             }
916              
917 1142           static OP *my_var(pTHX_ I32 flags, PADOFFSET padoff) {
918 1142           return my_var_g(aTHX_ OP_PADSV, flags, padoff);
919             }
920              
921 146           static OP *mkhvelem(pTHX_ PADOFFSET h, OP *k) {
922 146           OP *hv = my_var_g(aTHX_ OP_PADHV, OPf_REF, h);
923 146           return newBINOP(OP_HELEM, 0, hv, k);
924             }
925              
926 4361           static OP *mkconstsv(pTHX_ SV *sv) {
927 4361           return newSVOP(OP_CONST, 0, sv);
928             }
929              
930 960           static OP *mkconstiv(pTHX_ IV i) {
931 960           return mkconstsv(aTHX_ newSViv(i));
932             }
933              
934 1054           static OP *mkconstpv(pTHX_ const char *p, size_t n) {
935 1054           return mkconstsv(aTHX_ newSVpv(p, n));
936             }
937              
938             #define mkconstpvs(S) mkconstpv(aTHX_ "" S "", sizeof S - 1)
939              
940 943           static OP *mkcroak(pTHX_ OP *msg) {
941             OP *xcroak;
942 943           xcroak = newCVREF(
943             OPf_WANT_SCALAR,
944             mkconstsv(aTHX_ newSVpvs(MY_PKG "::_croak"))
945             );
946 943           xcroak = newUNOP(OP_ENTERSUB, OPf_STACKED, op_append_elem(OP_LIST, msg, xcroak));
947 943           return xcroak;
948             }
949              
950 46           static OP *mktypecheckv(pTHX_ Sentinel sen, const SV *declarator, size_t nr, SV *name, PADOFFSET padoff, SV *type, int is_invocant) {
951             /* $type->can("has_coercion") && $type->has_coercion
952             * ? $type->check($value = $type->coerce($value)) or F:P::_croak "...: " . $type->get_message($value)
953             * : $type->check($value) or F:P::_croak "...: " . $type->get_message($value)
954             */
955             OP *chk, *err, *msg, *xcroak;
956 46           bool has_coercion = FALSE, can_be_inlined = FALSE;
957              
958             {
959             GV *can_has_coercion;
960 46 100         if ((can_has_coercion = gv_fetchmethod_autoload(SvSTASH(SvRV(type)), "has_coercion", TRUE))) {
961 6           SV *ret = call_from_curstash(aTHX_ sen, MUTABLE_SV(GvCV(can_has_coercion)), &type, 1, 0);
962 6 50         if (SvTRUE(ret)) {
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    100          
963 3           has_coercion = TRUE;
964             }
965             }
966             }
967              
968             {
969             GV *can_can_be_inlined;
970 46 50         if ((can_can_be_inlined = gv_fetchmethod_autoload(SvSTASH(SvRV(type)), "can_be_inlined", TRUE))) {
971 0           SV *ret = call_from_curstash(aTHX_ sen, MUTABLE_SV(GvCV(can_can_be_inlined)), &type, 1, 0);
972 0 0         if (SvTRUE(ret)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
973 0           can_be_inlined = TRUE;
974             }
975             }
976             }
977              
978 46 50         if (can_be_inlined) {
979             GV *can_inline_check;
980             SV *src;
981              
982 0           can_inline_check = gv_fetchmethod_autoload(SvSTASH(SvRV(type)), "inline_check", FALSE);
983 0 0         if (!can_inline_check) {
984 0           can_inline_check = gv_fetchmethod_autoload(SvSTASH(SvRV(type)), "_inline_check", TRUE);
985 0 0         if (!can_inline_check) {
986 0           goto cannot_inline;
987             }
988             }
989              
990             {
991             SV *f_args[2];
992 0           f_args[0] = type;
993 0           f_args[1] = padoff == NOT_IN_PAD
994 0           ? sentinel_mortalize(sen, newSVpvs("$_"))
995 0 0         : name;
996 0           src = call_from_curstash(aTHX_ sen, MUTABLE_SV(GvCV(can_inline_check)), f_args, 2, 0);
997             }
998              
999 0           ENTER;
1000 0           SAVETMPS;
1001              
1002 0           lex_start(src, NULL, 0);
1003 0           chk = parse_fullexpr(0);
1004 0 0         if (PL_parser->error_count) {
1005 0           op_free(chk);
1006 0           chk = NULL;
1007             }
1008 0 0         if (!chk) {
1009 0 0         Perl_croak(aTHX_ "In %"SVf": inlining type constraint %"SVf" for %s %lu (%"SVf") failed", SVfARG(declarator), SVfARG(type), is_invocant ? "invocant" : "parameter", (unsigned long)nr, SVfARG(name));
1010             }
1011              
1012 0 0         FREETMPS;
1013 0           LEAVE;
1014              
1015 0 0         if (has_coercion) {
1016 0           OP *args2 = NULL, *coerce;
1017              
1018 0           args2 = op_append_elem(OP_LIST, args2, mkconstsv(aTHX_ SvREFCNT_inc_simple_NN(type)));
1019 0 0         args2 = op_append_elem(OP_LIST, args2, padoff == NOT_IN_PAD ? newDEFSVOP() : my_var(aTHX_ 0, padoff));
1020              
1021 0           coerce = op_convert_list(
1022             OP_ENTERSUB, OPf_STACKED,
1023             op_append_elem(OP_LIST, args2, newMETHOP(OP_METHOD, 0, mkconstpvs("coerce")))
1024             );
1025              
1026 0 0         coerce = newASSIGNOP(
1027             OPf_STACKED,
1028             padoff == NOT_IN_PAD ? newDEFSVOP() : my_var(aTHX_ 0, padoff),
1029             0,
1030             coerce
1031             );
1032              
1033 0           chk = op_append_elem(OP_LIST, coerce, chk);
1034             }
1035             } else cannot_inline: {
1036 46           OP *args = NULL, *arg;
1037              
1038 46           arg = padoff == NOT_IN_PAD
1039             ? newDEFSVOP()
1040 46 100         : my_var(aTHX_ 0, padoff);
1041              
1042 46 100         if (has_coercion) {
1043 3           OP *args2 = NULL, *coerce;
1044              
1045 3           args2 = op_append_elem(OP_LIST, args2, mkconstsv(aTHX_ SvREFCNT_inc_simple_NN(type)));
1046 3           args2 = op_append_elem(OP_LIST, args2, arg);
1047              
1048 3           coerce = op_convert_list(
1049             OP_ENTERSUB, OPf_STACKED,
1050             op_append_elem(OP_LIST, args2, newMETHOP(OP_METHOD, 0, mkconstpvs("coerce")))
1051             );
1052              
1053 3 50         arg = newASSIGNOP(
1054             OPf_STACKED,
1055             padoff == NOT_IN_PAD ? newDEFSVOP() : my_var(aTHX_ 0, padoff),
1056             0,
1057             coerce
1058             );
1059             }
1060              
1061 46           args = op_append_elem(OP_LIST, args, mkconstsv(aTHX_ SvREFCNT_inc_simple_NN(type)));
1062 46           args = op_append_elem(OP_LIST, args, arg);
1063              
1064 46           chk = op_convert_list(
1065             OP_ENTERSUB, OPf_STACKED,
1066             op_append_elem(OP_LIST, args, newMETHOP(OP_METHOD, 0, mkconstpvs("check")))
1067             );
1068             }
1069              
1070 89 100         err = mkconstsv(
1071             aTHX_
1072             is_invocant == -1
1073             ? newSVpvf("In %"SVf": invocant (%"SVf"): ", SVfARG(declarator), SVfARG(name))
1074 43 100         : newSVpvf("In %"SVf": %s %lu (%"SVf"): ", SVfARG(declarator), is_invocant ? "invocant" : "parameter", (unsigned long)nr, SVfARG(name))
1075             );
1076              
1077             {
1078 46           OP *args = NULL;
1079              
1080 46           args = op_append_elem(OP_LIST, args, mkconstsv(aTHX_ SvREFCNT_inc_simple_NN(type)));
1081 46 100         args = op_append_elem(
1082             OP_LIST, args,
1083             padoff == NOT_IN_PAD
1084             ? newDEFSVOP()
1085             : my_var(aTHX_ 0, padoff)
1086             );
1087              
1088 46           msg = op_convert_list(
1089             OP_ENTERSUB, OPf_STACKED,
1090             op_append_elem(OP_LIST, args, newMETHOP(OP_METHOD, 0, mkconstpvs("get_message")))
1091             );
1092             }
1093              
1094 46           msg = newBINOP(OP_CONCAT, 0, err, msg);
1095              
1096 46           xcroak = mkcroak(aTHX_ msg);
1097              
1098 46           chk = newLOGOP(OP_OR, 0, chk, xcroak);
1099 46           return chk;
1100             }
1101              
1102 1           static OP *mktypecheck(pTHX_ Sentinel sen, const SV *declarator, size_t nr, SV *name, PADOFFSET padoff, SV *type) {
1103 1           return mktypecheckv(aTHX_ sen, declarator, nr, name, padoff, type, 0);
1104             }
1105              
1106 0           static OP *mktypecheckp(pTHX_ Sentinel sen, const SV *declarator, size_t nr, const Param *param) {
1107 0           return mktypecheck(aTHX_ sen, declarator, nr, param->name, param->padoff, param->type);
1108             }
1109              
1110 45           static OP *mktypecheckpv(pTHX_ Sentinel sen, const SV *declarator, size_t nr, const Param *param, int is_invocant) {
1111 45           return mktypecheckv(aTHX_ sen, declarator, nr, param->name, param->padoff, param->type, is_invocant);
1112             }
1113              
1114 238           static OP *mkanonsub(pTHX_ CV *cv) {
1115             #if HAVE_PERL_VERSION(5, 37, 5)
1116             return newSVOP(OP_ANONCODE, OPf_REF, (SV *)cv);
1117             #else
1118 238           return newUNOP(
1119             OP_REFGEN, 0,
1120             newSVOP(OP_ANONCODE, 0, (SV *)cv)
1121             );
1122             #endif
1123             }
1124              
1125             enum {
1126             PARAM_INVOCANT = 0x01,
1127             PARAM_NAMED = 0x02,
1128             PARAM_DEFINED_OR = 0x04
1129             };
1130              
1131 889           static PADOFFSET parse_param(
1132             pTHX_
1133             Sentinel sen,
1134             const SV *declarator, const KWSpec *spec, ParamSpec *param_spec,
1135             int *pflags, SV **pname, OpGuard *ginit, SV **ptype
1136             ) {
1137             I32 c;
1138             char sigil;
1139             SV *name;
1140             bool is_defined_or;
1141              
1142             assert(!ginit->op);
1143 889           *pflags = 0;
1144 889           *ptype = NULL;
1145              
1146 889           c = lex_peek_unichar(0);
1147              
1148 889 50         if (spec->flags & FLAG_TYPES_OK) {
1149 889 100         if (c == '(') {
1150             I32 floor_ix;
1151             OP *expr;
1152             Resource *expr_sentinel;
1153              
1154 12           lex_read_unichar(0);
1155              
1156 12           floor_ix = start_subparse(FALSE, 0);
1157 12           SAVEFREESV(PL_compcv);
1158 12           CvSPECIAL_on(PL_compcv);
1159              
1160 12 50         if (!(expr = parse_fullexpr(PARSE_OPTIONAL))) {
1161 0           Perl_croak(aTHX_ "In %"SVf": invalid type expression", SVfARG(declarator));
1162             }
1163 12 50         if (MY_OP_SLABBED(expr)) {
1164 12           expr_sentinel = NULL;
1165             } else {
1166 0           expr_sentinel = sentinel_register(sen, expr, free_op_void);
1167             }
1168              
1169 12           lex_read_space(0);
1170 12           c = lex_peek_unichar(0);
1171 12 50         if (c != ')') {
1172 0           Perl_croak(aTHX_ "In %"SVf": missing ')' after type expression", SVfARG(declarator));
1173             }
1174 12           lex_read_unichar(0);
1175 12           lex_read_space(0);
1176              
1177 12 50         SvREFCNT_inc_simple_void(PL_compcv);
1178 12 50         if (expr_sentinel) {
1179 0           sentinel_disarm(expr_sentinel);
1180             }
1181 12           *ptype = my_eval(aTHX_ sen, floor_ix, expr);
1182 12 100         if (!SvROK(*ptype)) {
1183 5           *ptype = reify_type(aTHX_ sen, declarator, spec, *ptype);
1184 7 50         } else if (!sv_isobject(*ptype)) {
1185 0           Perl_croak(aTHX_ "In %"SVf": invalid type (%"SVf" is not a type object)", SVfARG(declarator), SVfARG(*ptype));
1186             }
1187              
1188 11           c = lex_peek_unichar(0);
1189 877 50         } else if (MY_UNI_IDFIRST(c) || c == '~') {
    50          
    100          
    100          
    0          
    50          
1190 36           *ptype = parse_type(aTHX_ sen, declarator, ',');
1191 35           *ptype = reify_type(aTHX_ sen, declarator, spec, *ptype);
1192              
1193 33           c = lex_peek_unichar(0);
1194             }
1195             }
1196              
1197 885 100         if (c == ':') {
1198 81           lex_read_unichar(0);
1199 81           lex_read_space(0);
1200              
1201 81           *pflags |= PARAM_NAMED;
1202              
1203 81           c = lex_peek_unichar(0);
1204             }
1205              
1206 885 50         if (c == -1) {
1207 0           Perl_croak(aTHX_ "In %"SVf": unterminated parameter list", SVfARG(declarator));
1208             }
1209              
1210 885 100         if (!(c == '$' || c == '@' || c == '%')) {
    100          
    50          
1211 0           Perl_croak(aTHX_ "In %"SVf": unexpected '%c' in parameter list (expecting a sigil)", SVfARG(declarator), (int)c);
1212             }
1213              
1214 885           sigil = c;
1215              
1216 885           lex_read_unichar(0);
1217              
1218 885           c = lex_peek_unichar(0);
1219 885 50         if (c == '#') {
1220 0           Perl_croak(aTHX_ "In %"SVf": unexpected '%c#' in parameter list (expecting an identifier)", SVfARG(declarator), sigil);
1221             }
1222              
1223 885           lex_read_space(0);
1224              
1225 885 100         if (!(name = my_scan_word(aTHX_ sen, FALSE))) {
1226 17           name = sentinel_mortalize(sen, newSVpvs(""));
1227 868 50         } else if (sv_eq_pvs(name, "_")) {
1228 0           Perl_croak(aTHX_ "In %"SVf": Can't use global %c_ as a parameter", SVfARG(declarator), sigil);
1229             }
1230 885           sv_insert(name, 0, 0, &sigil, 1);
1231 885           *pname = name;
1232              
1233 885           lex_read_space(0);
1234 885           c = lex_peek_unichar(0);
1235              
1236 885           is_defined_or = FALSE;
1237 885 100         if (c == '/') {
1238 17           lex_read_unichar(0);
1239 17           c = lex_peek_unichar(0);
1240 17 50         if (c != '/') {
1241 0 0         Perl_croak(aTHX_ "In %"SVf": unexpected '%s' after '%"SVf"' (expecting '//=' or '=')", SVfARG(declarator), c == '=' ? "/=" : "/", SVfARG(name));
1242             }
1243 17           lex_read_unichar(0);
1244 17           c = lex_peek_unichar(0);
1245              
1246 17 50         if (c != '=') {
1247 0           Perl_croak(aTHX_ "In %"SVf": unexpected '%c' after '%"SVf" //' (expecting '=')", SVfARG(declarator), (int)c, SVfARG(name));
1248             }
1249 17           *pflags |= PARAM_DEFINED_OR;
1250 17           is_defined_or = TRUE;
1251             /* fall through */
1252             }
1253              
1254 885 100         if (c == '=') {
1255 137           lex_read_unichar(0);
1256 137           lex_read_space(0);
1257              
1258 137           c = lex_peek_unichar(0);
1259 137 100         if (c == ',' || c == ')') {
    100          
1260 6 50         if (is_defined_or) {
1261 0           Perl_croak(aTHX_ "In %"SVf": unexpected '%c' after '//=' (expecting expression)", SVfARG(declarator), (int)c);
1262             }
1263 6           op_guard_update(ginit, newOP(OP_UNDEF, 0));
1264             } else {
1265 131 100         if (param_spec->shift == 0 && spec->shift.used) {
    100          
1266 11           size_t i, lim = spec->shift.used;
1267 11           Param *p = pv_unshift(¶m_spec->positional_required, lim);
1268 23 100         for (i = 0; i < lim; i++) {
1269 12           p[i].name = spec->shift.data[i].name;
1270 12           p[i].padoff = pad_add_name_sv(p[i].name, 0, NULL, NULL);
1271 12           p[i].type = spec->shift.data[i].type;
1272             }
1273 11           param_spec->shift = lim;
1274 11           intro_my();
1275             }
1276              
1277 131           op_guard_update(ginit, parse_termexpr(0));
1278              
1279 131           lex_read_space(0);
1280 131           c = lex_peek_unichar(0);
1281             }
1282             }
1283              
1284 885 100         if (c == ':') {
1285 35           *pflags |= PARAM_INVOCANT;
1286 35           lex_read_unichar(0);
1287 35           lex_read_space(0);
1288 850 100         } else if (c == ',') {
1289 553           lex_read_unichar(0);
1290 553           lex_read_space(0);
1291 297 50         } else if (c != ')') {
1292 0 0         if (c == -1) {
1293 0           Perl_croak(aTHX_ "In %"SVf": unterminated parameter list", SVfARG(declarator));
1294             }
1295 0           Perl_croak(aTHX_ "In %"SVf": unexpected '%c' in parameter list (expecting ',')", SVfARG(declarator), (int)c);
1296             }
1297              
1298 885           return SvCUR(*pname) < 2
1299             ? NOT_IN_PAD
1300 885 100         : pad_add_name_sv(*pname, padadd_NO_DUP_CHECK, NULL, NULL)
1301             ;
1302             }
1303              
1304 547           static void register_info(pTHX_ UV key, SV *declarator, const ParamSpec *ps) {
1305 547           dSP;
1306              
1307 547           ENTER;
1308 547           SAVETMPS;
1309              
1310 547 50         PUSHMARK(SP);
1311 547 50         EXTEND(SP, 9);
1312              
1313             /* 0 */ {
1314 547           mPUSHu(key);
1315             }
1316             /* 1 */ {
1317             STRLEN n;
1318 547 50         char *p = SvPV(declarator, n);
1319 547           char *q = memchr(p, ' ', n);
1320 547 50         SV *tmp = newSVpvn_utf8(p, q ? (size_t)(q - p) : n, SvUTF8(declarator));
1321 547           mPUSHs(tmp);
1322             }
1323             /* 2 */ {
1324 547           mPUSHu(ps->shift);
1325             }
1326             /* 3 */ {
1327             size_t i, lim;
1328             AV *av;
1329              
1330 547           lim = ps->positional_required.used;
1331              
1332 547           av = newAV();
1333 547 100         if (lim) {
1334 331           av_extend(av, (lim - 1) * 2);
1335 1101 100         for (i = 0; i < lim; i++) {
1336 770           Param *cur = &ps->positional_required.data[i];
1337 770           av_push(av, SvREFCNT_inc_simple_NN(cur->name));
1338 770 100         av_push(av, cur->type ? SvREFCNT_inc_simple_NN(cur->type) : &PL_sv_undef);
1339             }
1340             }
1341              
1342 547           mPUSHs(newRV_noinc((SV *)av));
1343             }
1344             /* 4 */ {
1345             size_t i, lim;
1346             AV *av;
1347              
1348 547           lim = ps->positional_optional.used;
1349              
1350 547           av = newAV();
1351 547 100         if (lim) {
1352 72           av_extend(av, (lim - 1) * 2);
1353 183 100         for (i = 0; i < lim; i++) {
1354 111           Param *cur = &ps->positional_optional.data[i].param;
1355 111           av_push(av, SvREFCNT_inc_simple_NN(cur->name));
1356 111 50         av_push(av, cur->type ? SvREFCNT_inc_simple_NN(cur->type) : &PL_sv_undef);
1357             }
1358             }
1359              
1360 547           mPUSHs(newRV_noinc((SV *)av));
1361             }
1362             /* 5 */ {
1363             size_t i, lim;
1364             AV *av;
1365              
1366 547           lim = ps->named_required.used;
1367              
1368 547           av = newAV();
1369 547 100         if (lim) {
1370 22           av_extend(av, (lim - 1) * 2);
1371 78 100         for (i = 0; i < lim; i++) {
1372 56           Param *cur = &ps->named_required.data[i];
1373 56           av_push(av, SvREFCNT_inc_simple_NN(cur->name));
1374 56 50         av_push(av, cur->type ? SvREFCNT_inc_simple_NN(cur->type) : &PL_sv_undef);
1375             }
1376             }
1377              
1378 547           mPUSHs(newRV_noinc((SV *)av));
1379             }
1380             /* 6 */ {
1381             size_t i, lim;
1382             AV *av;
1383              
1384 547           lim = ps->named_optional.used;
1385              
1386 547           av = newAV();
1387 547 100         if (lim) {
1388 11           av_extend(av, (lim - 1) * 2);
1389 30 100         for (i = 0; i < lim; i++) {
1390 19           Param *cur = &ps->named_optional.data[i].param;
1391 19           av_push(av, SvREFCNT_inc_simple_NN(cur->name));
1392 19 50         av_push(av, cur->type ? SvREFCNT_inc_simple_NN(cur->type) : &PL_sv_undef);
1393             }
1394             }
1395              
1396 547           mPUSHs(newRV_noinc((SV *)av));
1397             }
1398             /* 7, 8 */ {
1399 547 100         if (ps->slurpy.name) {
1400 36           PUSHs(ps->slurpy.name);
1401 36 100         if (ps->slurpy.type) {
1402 1           PUSHs(ps->slurpy.type);
1403             } else {
1404 36           PUSHmortal;
1405             }
1406             } else {
1407 511           PUSHmortal;
1408 511           PUSHmortal;
1409             }
1410             }
1411 547           PUTBACK;
1412              
1413 547           call_pv(MY_PKG "::_register_info", G_VOID);
1414              
1415 547 50         FREETMPS;
1416 547           LEAVE;
1417 547           }
1418              
1419 618           static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRLEN keyword_len, const KWSpec *spec) {
1420             ParamSpec *param_spec;
1421             SV *declarator;
1422             I32 floor_ix;
1423             int save_ix;
1424             SV *saw_name;
1425             OpGuard *prelude_sentinel;
1426             SV *proto;
1427             OpGuard *attrs_sentinel;
1428             OP *body;
1429             unsigned builtin_attrs;
1430             I32 c;
1431              
1432 618           declarator = sentinel_mortalize(sen, newSVpvn(keyword_ptr, keyword_len));
1433 618 100         if (lex_bufutf8()) {
1434 22           SvUTF8_on(declarator);
1435             }
1436              
1437 618           lex_read_space(0);
1438              
1439 618           builtin_attrs = 0;
1440              
1441             /* function name */
1442 618           saw_name = NULL;
1443 618 100         if ((spec->flags & FLAG_NAME_OK) && (saw_name = my_scan_word(aTHX_ sen, TRUE))) {
    100          
1444              
1445 347 100         if (PL_parser->expect != XSTATE) {
1446             /* bail out early so we don't predeclare $saw_name */
1447 2           Perl_croak(aTHX_ "In %"SVf": I was expecting a parameter list, not \"%"SVf"\"", SVfARG(declarator), SVfARG(saw_name));
1448             }
1449              
1450 345           sv_catpvs(declarator, " ");
1451 345           sv_catsv(declarator, saw_name);
1452              
1453 345 50         if (
1454 690 50         sv_eq_pvs(saw_name, "BEGIN") ||
1455 690 50         sv_eq_pvs(saw_name, "END") ||
1456 690 50         sv_eq_pvs(saw_name, "INIT") ||
1457 690 50         sv_eq_pvs(saw_name, "CHECK") ||
1458 345           sv_eq_pvs(saw_name, "UNITCHECK")
1459             ) {
1460 0           builtin_attrs |= MY_ATTR_SPECIAL;
1461             }
1462              
1463 345           lex_read_space(0);
1464 271 100         } else if (!(spec->flags & FLAG_ANON_OK)) {
1465 3           Perl_croak(aTHX_ "I was expecting a function name, not \"%.*s\"", (int)(PL_parser->bufend - PL_parser->bufptr), PL_parser->bufptr);
1466             } else {
1467 268           sv_catpvs(declarator, " (anon)");
1468             }
1469              
1470             /* we're a subroutine declaration */
1471 613 100         floor_ix = start_subparse(FALSE, saw_name ? 0 : CVf_ANON);
1472 613           SAVEFREESV(PL_compcv);
1473              
1474             /* create outer block: '{' */
1475 613           save_ix = block_start(TRUE);
1476              
1477             /* initialize synthetic optree */
1478 613           Newx(prelude_sentinel, 1, OpGuard);
1479 613           op_guard_init(prelude_sentinel);
1480 613           sentinel_register(sen, prelude_sentinel, free_op_guard_void);
1481              
1482             /* parameters */
1483 613           c = lex_peek_unichar(0);
1484 613 100         if (c != '(') {
1485 10           Perl_croak(aTHX_ "In %"SVf": I was expecting a parameter list, not \"%c\"", SVfARG(declarator), (int)c);
1486             }
1487              
1488 603           lex_read_unichar(0);
1489 603           lex_read_space(0);
1490              
1491 603           Newx(param_spec, 1, ParamSpec);
1492 603           ps_init(param_spec);
1493 603           sentinel_register(sen, param_spec, ps_free_void);
1494              
1495             {
1496             OpGuard *init_sentinel;
1497              
1498 603           Newx(init_sentinel, 1, OpGuard);
1499 603           op_guard_init(init_sentinel);
1500 603           sentinel_register(sen, init_sentinel, free_op_guard_void);
1501              
1502 1466 100         while ((c = lex_peek_unichar(0)) != ')') {
1503             int flags;
1504             SV *name, *type;
1505             char sigil;
1506             PADOFFSET padoff;
1507              
1508 889           padoff = parse_param(aTHX_ sen, declarator, spec, param_spec, &flags, &name, init_sentinel, &type);
1509              
1510 885 100         if (padoff != NOT_IN_PAD) {
1511 868           intro_my();
1512             }
1513              
1514 885 50         sigil = SvPV_nolen(name)[0];
1515              
1516             /* internal consistency */
1517 885 100         if (flags & PARAM_NAMED) {
1518 81 50         if (padoff == NOT_IN_PAD) {
1519 0           Perl_croak(aTHX_ "In %"SVf": named parameter %"SVf" can't be unnamed", SVfARG(declarator), SVfARG(name));
1520             }
1521 81 100         if (flags & PARAM_INVOCANT) {
1522 1           Perl_croak(aTHX_ "In %"SVf": invocant %"SVf" can't be a named parameter", SVfARG(declarator), SVfARG(name));
1523             }
1524 80 50         if (sigil != '$') {
1525 0 0         Perl_croak(aTHX_ "In %"SVf": named parameter %"SVf" can't be a%s", SVfARG(declarator), SVfARG(name), sigil == '@' ? "n array" : " hash");
1526             }
1527 804 100         } else if (flags & PARAM_INVOCANT) {
1528 34 50         if (init_sentinel->op) {
1529 0           Perl_croak(aTHX_ "In %"SVf": invocant %"SVf" can't have a default value", SVfARG(declarator), SVfARG(name));
1530             }
1531 34 100         if (sigil != '$') {
1532 2 100         Perl_croak(aTHX_ "In %"SVf": invocant %"SVf" can't be a%s", SVfARG(declarator), SVfARG(name), sigil == '@' ? "n array" : " hash");
1533             }
1534 770 100         } else if (sigil != '$' && init_sentinel->op) {
    100          
1535 4 100         Perl_croak(aTHX_ "In %"SVf": %s %"SVf" can't have a default value", SVfARG(declarator), sigil == '@' ? "array" : "hash", SVfARG(name));
1536             }
1537 878 100         if (type && padoff == NOT_IN_PAD) {
    50          
1538 0           Perl_croak(aTHX_ "In %"SVf": unnamed parameter %"SVf" can't have a type", SVfARG(declarator), SVfARG(name));
1539             }
1540              
1541             /* external constraints */
1542 878 100         if (param_spec->slurpy.name) {
1543 5           Perl_croak(aTHX_ "In %"SVf": \"%"SVf"\" can't appear after slurpy parameter \"%"SVf"\"", SVfARG(declarator), SVfARG(name), SVfARG(param_spec->slurpy.name));
1544             }
1545 873 100         if (sigil != '$') {
1546             assert(!init_sentinel->op);
1547 42           param_spec->slurpy.name = name;
1548 42           param_spec->slurpy.padoff = padoff;
1549 42           param_spec->slurpy.type = type;
1550 42           continue;
1551             }
1552              
1553 831 100         if (!(flags & PARAM_NAMED) && count_named_params(param_spec)) {
    100          
1554 1 50         Perl_croak(aTHX_ "In %"SVf": positional parameter %"SVf" can't appear after named parameter %"SVf"", SVfARG(declarator), SVfARG(name), SVfARG((param_spec->named_required.used ? param_spec->named_required.data[0] : param_spec->named_optional.data[0].param).name));
1555             }
1556              
1557 830 100         if (flags & PARAM_INVOCANT) {
1558 32 50         if (param_spec->shift) {
1559             assert(param_spec->shift <= param_spec->positional_required.used);
1560 0           Perl_croak(aTHX_ "In %"SVf": invalid double invocants (... %"SVf": ... %"SVf":)", SVfARG(declarator), SVfARG(param_spec->positional_required.data[param_spec->shift - 1].name), SVfARG(name));
1561             }
1562 32 100         if (!(spec->flags & FLAG_INVOCANT)) {
1563 2           Perl_croak(aTHX_ "In %"SVf": invocant %"SVf" not allowed here", SVfARG(declarator), SVfARG(name));
1564             }
1565 30 100         if (spec->shift.used && spec->shift.used != param_spec->positional_required.used + 1) {
    100          
1566 3           Perl_croak(aTHX_ "In %"SVf": number of invocants in parameter list (%lu) differs from number of invocants in keyword definition (%lu)", SVfARG(declarator), (unsigned long)(param_spec->positional_required.used + 1), (unsigned long)spec->shift.used);
1567             }
1568             }
1569              
1570 825 100         if (!(flags & PARAM_NAMED) && !init_sentinel->op && param_spec->positional_optional.used) {
    100          
    50          
1571 0           Perl_croak(aTHX_ "In %"SVf": required parameter %"SVf" can't appear after optional parameter %"SVf"", SVfARG(declarator), SVfARG(name), SVfARG(param_spec->positional_optional.data[0].param.name));
1572             }
1573              
1574 825 100         if (init_sentinel->op && !(spec->flags & FLAG_DEFAULT_ARGS)) {
    100          
1575 2           Perl_croak(aTHX_ "In %"SVf": default argument for %"SVf" not allowed here", SVfARG(declarator), SVfARG(name));
1576             }
1577              
1578 823 100         if (padoff != NOT_IN_PAD && ps_contains(aTHX_ param_spec, name)) {
    100          
1579 1           Perl_croak(aTHX_ "In %"SVf": %"SVf" can't appear twice in the same parameter list", SVfARG(declarator), SVfARG(name));
1580             }
1581              
1582 822 100         if (flags & PARAM_NAMED) {
1583 78 50         if (!(spec->flags & FLAG_NAMED_PARAMS)) {
1584 0           Perl_croak(aTHX_ "In %"SVf": named parameter :%"SVf" not allowed here", SVfARG(declarator), SVfARG(name));
1585             }
1586              
1587 78 100         if (init_sentinel->op) {
1588 19           ParamInit *pi = piv_extend(¶m_spec->named_optional);
1589 19           pi->param.name = name;
1590 19           pi->param.padoff = padoff;
1591 19           pi->param.type = type;
1592 19           pi->init = op_guard_transfer(init_sentinel);
1593 19           pi->cond = flags & PARAM_DEFINED_OR ? ICOND_DEFINED : ICOND_EXISTS;
1594 19           param_spec->named_optional.used++;
1595             } else {
1596 59 100         if (param_spec->positional_optional.used) {
1597 1           Perl_croak(aTHX_ "In %"SVf": can't combine optional positional (%"SVf") and required named (%"SVf") parameters", SVfARG(declarator), SVfARG(param_spec->positional_optional.data[0].param.name), SVfARG(name));
1598             }
1599              
1600 77           pv_push(¶m_spec->named_required, name, padoff, type);
1601             }
1602             } else {
1603 744 100         if (init_sentinel->op) {
1604 112           ParamInit *pi = piv_extend(¶m_spec->positional_optional);
1605 112           pi->param.name = name;
1606 112           pi->param.padoff = padoff;
1607 112           pi->param.type = type;
1608 112           pi->init = op_guard_transfer(init_sentinel);
1609 112           pi->cond = flags & PARAM_DEFINED_OR ? ICOND_DEFINED : ICOND_EXISTS;
1610 112           param_spec->positional_optional.used++;
1611             } else {
1612             assert(param_spec->positional_optional.used == 0);
1613 632           pv_push(¶m_spec->positional_required, name, padoff, type);
1614 632 100         if (flags & PARAM_INVOCANT) {
1615             assert(param_spec->shift == 0);
1616 821           param_spec->shift = param_spec->positional_required.used;
1617             }
1618             }
1619             }
1620              
1621             }
1622 577           lex_read_unichar(0);
1623 577           lex_read_space(0);
1624              
1625 577 100         if (param_spec->shift == 0 && spec->shift.used) {
    100          
1626 140           size_t i, lim = spec->shift.used;
1627             Param *p;
1628 140           p = pv_unshift(¶m_spec->positional_required, lim);
1629 282 100         for (i = 0; i < lim; i++) {
1630 144           const SpecParam *const cur = &spec->shift.data[i];
1631 144 100         if (ps_contains(aTHX_ param_spec, cur->name)) {
1632 2           Perl_croak(aTHX_ "In %"SVf": %"SVf" can't appear twice in the same parameter list", SVfARG(declarator), SVfARG(cur->name));
1633             }
1634              
1635 142           p[i].name = cur->name;
1636 142           p[i].padoff = pad_add_name_sv(p[i].name, 0, NULL, NULL);
1637 142           p[i].type = cur->type;
1638             }
1639 138           param_spec->shift = lim;
1640             }
1641             }
1642              
1643             /* attributes */
1644 575           Newx(attrs_sentinel, 1, OpGuard);
1645 575           op_guard_init(attrs_sentinel);
1646 575           sentinel_register(sen, attrs_sentinel, free_op_guard_void);
1647 575           proto = NULL;
1648              
1649 575           c = lex_peek_unichar(0);
1650 575 100         if (c == ':' || c == '{') /* '}' - hi, vim */ {
    50          
1651              
1652             /* kludge default attributes in */
1653 575 50         if (SvTRUE(spec->attrs) && SvPV_nolen(spec->attrs)[0] == ':') {
    50          
    50          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
1654 172           lex_stuff_sv(spec->attrs, 0);
1655 172           c = ':';
1656             }
1657              
1658 575 100         if (c == ':') {
1659 234           lex_read_unichar(0);
1660 234           lex_read_space(0);
1661 234           c = lex_peek_unichar(0);
1662              
1663             for (;;) {
1664             SV *attr;
1665              
1666 453 100         if (!(attr = my_scan_word(aTHX_ sen, FALSE))) {
1667 211           break;
1668             }
1669              
1670 242           lex_read_space(0);
1671 242           c = lex_peek_unichar(0);
1672              
1673 242 100         if (c != '(') {
1674 174 100         if (sv_eq_pvs(attr, "lvalue")) {
1675 3           builtin_attrs |= MY_ATTR_LVALUE;
1676 3           attr = NULL;
1677 171 50         } else if (sv_eq_pvs(attr, "method")) {
1678 171           builtin_attrs |= MY_ATTR_METHOD;
1679 174           attr = NULL;
1680             }
1681             } else {
1682             SV *sv;
1683 68           lex_read_unichar(0);
1684 68 50         if (!(sv = my_scan_parens_tail(aTHX_ sen, TRUE))) {
1685 0           Perl_croak(aTHX_ "In %"SVf": unterminated attribute parameter in attribute list", SVfARG(declarator));
1686             }
1687              
1688 68 50         if (sv_eq_pvs(attr, "prototype")) {
1689 68 100         if (proto) {
1690 1           Perl_croak(aTHX_ "In %"SVf": Can't redefine prototype (%"SVf") using attribute prototype(%"SVf")", SVfARG(declarator), SVfARG(proto), SVfARG(sv));
1691             }
1692 67           proto = sv;
1693 67           my_check_prototype(aTHX_ sen, declarator, proto);
1694 45           attr = NULL;
1695             } else {
1696 0           sv_catpvs(attr, "(");
1697 0           sv_catsv(attr, sv);
1698 0           sv_catpvs(attr, ")");
1699             }
1700              
1701 45           lex_read_space(0);
1702 45           c = lex_peek_unichar(0);
1703             }
1704              
1705 219 50         if (attr) {
1706 0           op_guard_update(attrs_sentinel, op_append_elem(OP_LIST, attrs_sentinel->op, mkconstsv(aTHX_ SvREFCNT_inc_simple_NN(attr))));
1707             }
1708              
1709 219 100         if (c == ':') {
1710 9           lex_read_unichar(0);
1711 9           lex_read_space(0);
1712 9           c = lex_peek_unichar(0);
1713             }
1714 219           }
1715             }
1716             }
1717              
1718             /* body */
1719 552 100         if (c != '{') /* '}' - hi, vim */ {
1720 1           Perl_croak(aTHX_ "In %"SVf": I was expecting a function body, not \"%c\"", SVfARG(declarator), (int)c);
1721             }
1722              
1723             /* surprise predeclaration! */
1724 551 100         if (saw_name && !spec->install_sub && !(spec->flags & FLAG_RUNTIME)) {
    100          
    100          
1725             /* 'sub NAME (PROTO);' to make name/proto known to perl before it
1726             starts parsing the body */
1727 309           const I32 sub_ix = start_subparse(FALSE, 0);
1728 309           SAVEFREESV(PL_compcv);
1729              
1730 309 50         SvREFCNT_inc_simple_void(PL_compcv);
1731              
1732             #if HAVE_BUG_GH_15557
1733             {
1734             CV *const outside = CvOUTSIDE(PL_compcv);
1735             if (outside) {
1736             CvOUTSIDE(PL_compcv) = NULL;
1737             if (!CvWEAKOUTSIDE(PL_compcv)) {
1738             SvREFCNT_dec_NN(outside);
1739             }
1740             }
1741             }
1742             #endif
1743 309 100         newATTRSUB(
1744             sub_ix,
1745             mkconstsv(aTHX_ SvREFCNT_inc_simple_NN(saw_name)),
1746             proto ? mkconstsv(aTHX_ SvREFCNT_inc_simple_NN(proto)) : NULL,
1747             NULL,
1748             NULL
1749             );
1750             }
1751              
1752 551 100         if (builtin_attrs & MY_ATTR_LVALUE) {
1753 3           CvLVALUE_on(PL_compcv);
1754             }
1755 551 100         if (builtin_attrs & MY_ATTR_METHOD) {
1756 171           CvMETHOD_on(PL_compcv);
1757             }
1758 551 50         if (builtin_attrs & MY_ATTR_SPECIAL) {
1759 0           CvSPECIAL_on(PL_compcv);
1760             }
1761              
1762             /* check number of arguments */
1763 551 100         if (spec->flags & FLAG_CHECK_NARGS) {
1764             int amin, amax;
1765              
1766 525           amin = args_min(param_spec);
1767 525 100         if (amin > 0) {
1768             OP *chk, *cond, *err;
1769              
1770 325           err = mkconstsv(aTHX_ newSVpvf("Too few arguments for %"SVf" (expected %d, got ", SVfARG(declarator), amin));
1771 325           err = newBINOP(
1772             OP_CONCAT, 0,
1773             err,
1774             newAVREF(newGVOP(OP_GV, 0, PL_defgv))
1775             );
1776 325           err = newBINOP(
1777             OP_CONCAT, 0,
1778             err,
1779             mkconstpvs(")")
1780             );
1781              
1782 325           err = mkcroak(aTHX_ err);
1783              
1784 325           cond = newBINOP(OP_LT, 0,
1785             newAVREF(newGVOP(OP_GV, 0, PL_defgv)),
1786             mkconstiv(aTHX_ amin));
1787 325           chk = newLOGOP(OP_AND, 0, cond, err);
1788              
1789 325           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, chk)));
1790             }
1791              
1792 525           amax = args_max(param_spec);
1793 525 100         if (amax >= 0) {
1794             OP *chk, *cond, *err;
1795              
1796 465           err = mkconstsv(aTHX_ newSVpvf("Too many arguments for %"SVf" (expected %d, got ", SVfARG(declarator), amax));
1797 465           err = newBINOP(
1798             OP_CONCAT, 0,
1799             err,
1800             newAVREF(newGVOP(OP_GV, 0, PL_defgv))
1801             );
1802 465           err = newBINOP(
1803             OP_CONCAT, 0,
1804             err,
1805             mkconstpvs(")")
1806             );
1807              
1808 465           err = mkcroak(aTHX_ err);
1809              
1810 465           cond = newBINOP(
1811             OP_GT, 0,
1812             newAVREF(newGVOP(OP_GV, 0, PL_defgv)),
1813             mkconstiv(aTHX_ amax)
1814             );
1815 465           chk = newLOGOP(OP_AND, 0, cond, err);
1816              
1817 465           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, chk)));
1818             }
1819              
1820 525 100         if (count_named_params(param_spec) || (param_spec->slurpy.name && SvPV_nolen(param_spec->slurpy.name)[0] == '%')) {
    100          
    50          
    50          
1821             OP *chk, *cond, *err;
1822 29           const UV fixed = count_positional_params(param_spec);
1823              
1824 29           err = mkconstsv(aTHX_ newSVpvf("Odd number of paired arguments for %"SVf"", SVfARG(declarator)));
1825              
1826 29           err = mkcroak(aTHX_ err);
1827              
1828 29           cond = newBINOP(OP_GT, 0,
1829             newAVREF(newGVOP(OP_GV, 0, PL_defgv)),
1830             mkconstiv(aTHX_ fixed));
1831 29 100         cond = newLOGOP(OP_AND, 0,
1832             cond,
1833             newBINOP(OP_MODULO, 0,
1834             fixed
1835             ? newBINOP(OP_SUBTRACT, 0,
1836             newAVREF(newGVOP(OP_GV, 0, PL_defgv)),
1837             mkconstiv(aTHX_ fixed))
1838             : newAVREF(newGVOP(OP_GV, 0, PL_defgv)),
1839             mkconstiv(aTHX_ 2)));
1840 29           chk = newLOGOP(OP_AND, 0, cond, err);
1841              
1842 29           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, chk)));
1843             }
1844             }
1845              
1846             assert(param_spec->shift <= param_spec->positional_required.used);
1847 551 100         if (param_spec->shift) {
1848 176           bool all_anon = TRUE;
1849             {
1850             size_t i;
1851 176 50         for (i = 0; i < param_spec->shift; i++) {
1852 176 50         if (param_spec->positional_required.data[i].padoff != NOT_IN_PAD) {
1853 176           all_anon = FALSE;
1854 176           break;
1855             }
1856             }
1857             }
1858 176 100         if (param_spec->shift == 1) {
1859 169 50         if (all_anon) {
1860             /* shift; */
1861 0           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, newOP(OP_SHIFT, 0))));
1862             } else {
1863             /* my $invocant = shift; */
1864             OP *var;
1865              
1866 169           var = my_var(
1867             aTHX_
1868             OPf_MOD | (OPpLVAL_INTRO << 8),
1869 169           param_spec->positional_required.data[0].padoff
1870             );
1871 169           var = newASSIGNOP(OPf_STACKED, var, 0, newOP(OP_SHIFT, 0));
1872              
1873 169           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, var)));
1874             }
1875             } else {
1876 7           OP *const rhs = op_convert_list(OP_SPLICE, 0,
1877             op_append_elem(
1878             OP_LIST,
1879             op_append_elem(
1880             OP_LIST,
1881             newAVREF(newGVOP(OP_GV, 0, PL_defgv)),
1882             mkconstiv(aTHX_ 0)
1883             ),
1884             mkconstiv(aTHX_ param_spec->shift)));
1885 7 50         if (all_anon) {
1886             /* splice @_, 0, $n; */
1887 0           op_guard_update(
1888             prelude_sentinel,
1889             op_append_list(
1890             OP_LINESEQ,
1891             prelude_sentinel->op,
1892             newSTATEOP(0, NULL, rhs)));
1893             } else {
1894             /* my (...) = splice @_, 0, $n; */
1895             OP *lhs;
1896             size_t i, lim;
1897              
1898 7           lhs = NULL;
1899              
1900 21 100         for (i = 0, lim = param_spec->shift; i < lim; i++) {
1901 14           const PADOFFSET padoff = param_spec->positional_required.data[i].padoff;
1902 14 50         lhs = op_append_elem(
1903             OP_LIST,
1904             lhs,
1905             padoff == NOT_IN_PAD
1906             ? newOP(OP_UNDEF, 0)
1907             : my_var(
1908             aTHX_
1909             OPf_WANT_LIST | (OPpLVAL_INTRO << 8),
1910             padoff
1911             )
1912             );
1913             }
1914              
1915 7           lhs->op_flags |= OPf_PARENS;
1916              
1917 7           op_guard_update(prelude_sentinel, op_append_list(
1918             OP_LINESEQ, prelude_sentinel->op,
1919             newSTATEOP(
1920             0, NULL,
1921             newASSIGNOP(OPf_STACKED, lhs, 0, rhs)
1922             )
1923             ));
1924             }
1925             }
1926             }
1927              
1928             /* my (...) = @_; */
1929             {
1930             OP *lhs;
1931             size_t i, lim;
1932              
1933 551           lhs = NULL;
1934              
1935 1143 100         for (i = param_spec->shift, lim = param_spec->positional_required.used; i < lim; i++) {
1936 592           const PADOFFSET padoff = param_spec->positional_required.data[i].padoff;
1937 592 100         lhs = op_append_elem(
1938             OP_LIST,
1939             lhs,
1940             padoff == NOT_IN_PAD
1941             ? newOP(OP_UNDEF, 0)
1942             : my_var(
1943             aTHX_
1944             OPf_WANT_LIST | (OPpLVAL_INTRO << 8),
1945             padoff
1946             )
1947             );
1948             }
1949              
1950 662 100         for (i = 0, lim = param_spec->positional_optional.used; i < lim; i++) {
1951 111           const PADOFFSET padoff = param_spec->positional_optional.data[i].param.padoff;
1952 111 100         lhs = op_append_elem(
1953             OP_LIST,
1954             lhs,
1955             padoff == NOT_IN_PAD
1956             ? newOP(OP_UNDEF, 0)
1957             : my_var(
1958             aTHX_
1959             OPf_WANT_LIST | (OPpLVAL_INTRO << 8),
1960             padoff
1961             )
1962             );
1963             }
1964              
1965             {
1966             PADOFFSET padoff;
1967             I32 type;
1968             bool slurpy_hash;
1969              
1970             /*
1971             * cases:
1972             * 1) no named params
1973             * 1.1) slurpy
1974             * => put it in
1975             * 1.2) no slurpy
1976             * => nop
1977             * 2) named params
1978             * 2.1) no slurpy
1979             * => synthetic %{__rest}
1980             * 2.2) slurpy is a hash
1981             * => put it in
1982             * 2.3) slurpy is an array
1983             * => synthetic %{__rest}
1984             * remember to declare array later
1985             */
1986              
1987 551 100         slurpy_hash = param_spec->slurpy.name && SvPV_nolen(param_spec->slurpy.name)[0] == '%';
    50          
    100          
1988 551 100         if (!count_named_params(param_spec)) {
1989 521 100         if (param_spec->slurpy.name && param_spec->slurpy.padoff != NOT_IN_PAD) {
    100          
1990 17           padoff = param_spec->slurpy.padoff;
1991 17 50         type = slurpy_hash ? OP_PADHV : OP_PADAV;
1992             } else {
1993 504           padoff = NOT_IN_PAD;
1994 521           type = OP_PADSV;
1995             }
1996 30 100         } else if (slurpy_hash && param_spec->slurpy.padoff != NOT_IN_PAD) {
    50          
1997 2           padoff = param_spec->slurpy.padoff;
1998 2           type = OP_PADHV;
1999             } else {
2000 28           padoff = pad_add_name_pvs("%{__rest}", 0, NULL, NULL);
2001 28           type = OP_PADHV;
2002             }
2003              
2004 551 100         if (padoff != NOT_IN_PAD) {
2005 47           OP *const var = my_var_g(
2006             aTHX_
2007             type,
2008             OPf_WANT_LIST | (OPpLVAL_INTRO << 8),
2009             padoff
2010             );
2011              
2012 47           lhs = op_append_elem(OP_LIST, lhs, var);
2013              
2014 47 100         if (type == OP_PADHV) {
2015 30           param_spec->rest_hash = padoff;
2016             }
2017             }
2018             }
2019              
2020 551 100         if (lhs) {
2021 279           OP *const rhs = newAVREF(newGVOP(OP_GV, 0, PL_defgv));
2022 279           lhs->op_flags |= OPf_PARENS;
2023              
2024 279           op_guard_update(prelude_sentinel, op_append_list(
2025             OP_LINESEQ, prelude_sentinel->op,
2026             newSTATEOP(
2027             0, NULL,
2028             newASSIGNOP(OPf_STACKED, lhs, 0, rhs)
2029             )
2030             ));
2031             }
2032             }
2033              
2034             /* default positional arguments */
2035             {
2036             size_t i, lim, req;
2037             OP *nest, *sequ;
2038              
2039 551           nest = NULL;
2040 551           sequ = NULL;
2041              
2042 551           req = param_spec->positional_required.used - param_spec->shift;
2043 662 100         for (i = 0, lim = param_spec->positional_optional.used; i < lim; i++) {
2044 111           ParamInit *cur = ¶m_spec->positional_optional.data[i];
2045             OP *cond, *init;
2046              
2047             {
2048 111           OP *const init_op = cur->init.op;
2049 111 100         if (init_op->op_type == OP_UNDEF && !(init_op->op_flags & OPf_KIDS)) {
    50          
2050 18           continue;
2051             }
2052             }
2053              
2054 93           switch (cur->cond) {
2055              
2056             case ICOND_DEFINED:
2057 12           init = op_guard_relinquish(&cur->init);
2058 12 100         if (cur->param.padoff == NOT_IN_PAD) {
2059 1           OP *arg = newBINOP(
2060             OP_AELEM, 0,
2061             newAVREF(newGVOP(OP_GV, 0, PL_defgv)),
2062             mkconstiv(aTHX_ req + i)
2063             );
2064 1           init = newLOGOP(OP_DOR, 0, arg, init);
2065             } else {
2066 11           OP *var = my_var(aTHX_ 0, cur->param.padoff);
2067 11           init = newASSIGNOP(OPf_STACKED, var, OP_DORASSIGN, init);
2068             }
2069 12           sequ = op_append_list(OP_LINESEQ, sequ, nest);
2070 12           nest = NULL;
2071 12           sequ = op_append_list(OP_LINESEQ, sequ, init);
2072 12           break;
2073              
2074             case ICOND_EXISTS:
2075 81           cond = newBINOP(
2076             OP_LT, 0,
2077             newAVREF(newGVOP(OP_GV, 0, PL_defgv)),
2078             mkconstiv(aTHX_ req + i + 1)
2079             );
2080              
2081 81           init = op_guard_relinquish(&cur->init);
2082 81 100         if (cur->param.padoff != NOT_IN_PAD) {
2083 80           OP *var = my_var(aTHX_ 0, cur->param.padoff);
2084 80           init = newASSIGNOP(OPf_STACKED, var, 0, init);
2085             }
2086              
2087 81           nest = op_append_list(OP_LINESEQ, nest, init);
2088 81           nest = newCONDOP(0, cond, nest, NULL);
2089 81           break;
2090             }
2091             }
2092              
2093 551           sequ = op_append_list(OP_LINESEQ, sequ, nest);
2094              
2095 551           op_guard_update(prelude_sentinel, op_append_list(
2096             OP_LINESEQ, prelude_sentinel->op,
2097             sequ
2098             ));
2099             }
2100              
2101             /* named parameters */
2102 551 100         if (count_named_params(param_spec)) {
2103             size_t i, lim;
2104              
2105             assert(param_spec->rest_hash != NOT_IN_PAD);
2106              
2107 86 100         for (i = 0, lim = param_spec->named_required.used; i < lim; i++) {
2108 56           Param *cur = ¶m_spec->named_required.data[i];
2109             size_t n;
2110 56 50         char *p = SvPV(cur->name, n);
2111             OP *var, *cond;
2112              
2113             assert(cur->padoff != NOT_IN_PAD);
2114              
2115 56           cond = mkhvelem(aTHX_ param_spec->rest_hash, mkconstpv(aTHX_ p + 1, n - 1));
2116              
2117 56 100         if (spec->flags & FLAG_CHECK_NARGS) {
2118             OP *xcroak, *msg;
2119              
2120 55           var = mkhvelem(aTHX_ param_spec->rest_hash, mkconstpv(aTHX_ p + 1, n - 1));
2121 55           var = newUNOP(OP_DELETE, 0, var);
2122              
2123 55           msg = mkconstsv(aTHX_ newSVpvf("In %"SVf": missing named parameter: %.*s", SVfARG(declarator), (int)(n - 1), p + 1));
2124 55           xcroak = mkcroak(aTHX_ msg);
2125              
2126 55           cond = newUNOP(OP_EXISTS, 0, cond);
2127              
2128 55           cond = newCONDOP(0, cond, var, xcroak);
2129             }
2130              
2131 56           var = my_var(
2132             aTHX_
2133             OPf_MOD | (OPpLVAL_INTRO << 8),
2134             cur->padoff
2135             );
2136 56           var = newASSIGNOP(OPf_STACKED, var, 0, cond);
2137              
2138 56           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, var)));
2139             }
2140              
2141 49 100         for (i = 0, lim = param_spec->named_optional.used; i < lim; i++) {
2142 19           ParamInit *cur = ¶m_spec->named_optional.data[i];
2143             size_t n;
2144 19 50         char *p = SvPV(cur->param.name, n);
2145             OP *var, *expr;
2146              
2147 19           expr = mkhvelem(aTHX_ param_spec->rest_hash, mkconstpv(aTHX_ p + 1, n - 1));
2148 19           expr = newUNOP(OP_DELETE, 0, expr);
2149              
2150             {
2151 19           OP *const init = cur->init.op;
2152 19 100         if (!(init->op_type == OP_UNDEF && !(init->op_flags & OPf_KIDS))) {
    50          
2153 18           switch (cur->cond) {
2154             case ICOND_DEFINED:
2155 2           expr = newLOGOP(OP_DOR, 0, expr, op_guard_relinquish(&cur->init));
2156 2           break;
2157              
2158             case ICOND_EXISTS: {
2159             OP *cond;
2160              
2161 16           cond = mkhvelem(aTHX_ param_spec->rest_hash, mkconstpv(aTHX_ p + 1, n - 1));
2162 16           cond = newUNOP(OP_EXISTS, 0, cond);
2163              
2164 16           expr = newCONDOP(0, cond, expr, op_guard_relinquish(&cur->init));
2165 16           break;
2166             }
2167             }
2168             }
2169             }
2170              
2171 19           var = my_var(
2172             aTHX_
2173             OPf_MOD | (OPpLVAL_INTRO << 8),
2174             cur->param.padoff
2175             );
2176 19           var = newASSIGNOP(OPf_STACKED, var, 0, expr);
2177              
2178 19           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, var)));
2179             }
2180              
2181 30 100         if (!param_spec->slurpy.name) {
2182 24 100         if (spec->flags & FLAG_CHECK_NARGS) {
2183             /* croak if %{__rest} */
2184             OP *xcroak, *cond, *keys, *msg;
2185              
2186 23           keys = newUNOP(OP_KEYS, 0, my_var_g(aTHX_ OP_PADHV, 0, param_spec->rest_hash));
2187 23           keys = newLISTOP(OP_SORT, 0, newOP(OP_PUSHMARK, 0), keys);
2188 23           keys->op_flags = (keys->op_flags & ~OPf_WANT) | OPf_WANT_LIST;
2189 23           keys = op_convert_list(OP_JOIN, 0, op_prepend_elem(OP_LIST, mkconstpvs(", "), keys));
2190 23           keys->op_targ = pad_alloc(OP_JOIN, SVs_PADTMP);
2191              
2192 23           msg = mkconstsv(aTHX_ newSVpvf("In %"SVf": no such named parameter: ", SVfARG(declarator)));
2193 23           msg = newBINOP(OP_CONCAT, 0, msg, keys);
2194              
2195 23           xcroak = mkcroak(aTHX_ msg);
2196              
2197 23           cond = newUNOP(OP_KEYS, 0, my_var_g(aTHX_ OP_PADHV, 0, param_spec->rest_hash));
2198 23           xcroak = newCONDOP(0, cond, xcroak, NULL);
2199              
2200 23           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, xcroak)));
2201             } else {
2202             OP *clear;
2203              
2204 1           clear = newASSIGNOP(
2205             OPf_STACKED,
2206             my_var_g(aTHX_ OP_PADHV, 0, param_spec->rest_hash),
2207             0,
2208             newNULLLIST()
2209             );
2210              
2211 24           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, clear)));
2212             }
2213 6 100         } else if (param_spec->slurpy.padoff != param_spec->rest_hash) {
2214             OP *clear;
2215              
2216             assert(param_spec->rest_hash != NOT_IN_PAD);
2217 4 50         if (SvPV_nolen(param_spec->slurpy.name)[0] == '%') {
    50          
2218             assert(param_spec->slurpy.padoff == NOT_IN_PAD);
2219             } else {
2220              
2221             assert(SvPV_nolen(param_spec->slurpy.name)[0] == '@');
2222              
2223 4 50         if (param_spec->slurpy.padoff != NOT_IN_PAD) {
2224 4           OP *var = my_var_g(
2225             aTHX_
2226             OP_PADAV,
2227             OPf_MOD | (OPpLVAL_INTRO << 8),
2228             param_spec->slurpy.padoff
2229             );
2230              
2231 4           var = newASSIGNOP(OPf_STACKED, var, 0, my_var_g(aTHX_ OP_PADHV, 0, param_spec->rest_hash));
2232              
2233 4           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, var)));
2234             }
2235             }
2236              
2237 4           clear = newASSIGNOP(
2238             OPf_STACKED,
2239             my_var_g(aTHX_ OP_PADHV, 0, param_spec->rest_hash),
2240             0,
2241             newNULLLIST()
2242             );
2243              
2244 4           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, clear)));
2245             }
2246             }
2247              
2248 551 50         if (spec->flags & FLAG_CHECK_TARGS) {
2249             size_t i, lim, base;
2250              
2251 551           base = 1;
2252 1326 100         for (i = 0, lim = param_spec->positional_required.used; i < lim; i++) {
2253 775           Param *cur = ¶m_spec->positional_required.data[i];
2254              
2255 775 100         if (cur->type) {
2256 45           const bool is_invocant = i < param_spec->shift;
2257 45           const size_t shift = param_spec->shift;
2258             assert(cur->padoff != NOT_IN_PAD);
2259 45 100         op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, mktypecheckpv(aTHX_ sen, declarator, base + i - (is_invocant ? 0 : shift), cur, !is_invocant ? 0 : shift == 1 ? -1 : 1))));
    100          
    100          
2260             }
2261             }
2262 551           base += i - param_spec->shift;
2263              
2264 662 100         for (i = 0, lim = param_spec->positional_optional.used; i < lim; i++) {
2265 111           Param *cur = ¶m_spec->positional_optional.data[i].param;
2266              
2267 111 50         if (cur->type) {
2268             assert(cur->padoff != NOT_IN_PAD);
2269 0           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, mktypecheckp(aTHX_ sen, declarator, base + i, cur))));
2270             }
2271             }
2272 551           base += i;
2273              
2274 607 100         for (i = 0, lim = param_spec->named_required.used; i < lim; i++) {
2275 56           Param *cur = ¶m_spec->named_required.data[i];
2276              
2277 56 50         if (cur->type) {
2278             assert(cur->padoff != NOT_IN_PAD);
2279 0           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, mktypecheckp(aTHX_ sen, declarator, base + i, cur))));
2280             }
2281             }
2282 551           base += i;
2283              
2284 570 100         for (i = 0, lim = param_spec->named_optional.used; i < lim; i++) {
2285 19           Param *cur = ¶m_spec->named_optional.data[i].param;
2286              
2287 19 50         if (cur->type) {
2288             assert(cur->padoff != NOT_IN_PAD);
2289 0           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, mktypecheckp(aTHX_ sen, declarator, base + i, cur))));
2290             }
2291             }
2292 551           base += i;
2293              
2294 551 100         if (param_spec->slurpy.type) {
2295             /* $type->valid($_) or croak $type->get_message($_) for @rest / values %rest */
2296             OP *check, *list, *loop;
2297              
2298             assert(param_spec->slurpy.padoff != NOT_IN_PAD);
2299              
2300 1           check = mktypecheck(aTHX_ sen, declarator, base, param_spec->slurpy.name, NOT_IN_PAD, param_spec->slurpy.type);
2301              
2302 1 50         if (SvPV_nolen(param_spec->slurpy.name)[0] == '@') {
    50          
2303 1           list = my_var_g(aTHX_ OP_PADAV, 0, param_spec->slurpy.padoff);
2304             } else {
2305 0           list = my_var_g(aTHX_ OP_PADHV, 0, param_spec->slurpy.padoff);
2306 0           list = newUNOP(OP_VALUES, 0, list);
2307             }
2308              
2309 1           loop = newFOROP(0, NULL, list, check, NULL);
2310              
2311 1           op_guard_update(prelude_sentinel, op_append_list(OP_LINESEQ, prelude_sentinel->op, newSTATEOP(0, NULL, loop)));
2312             }
2313             }
2314              
2315             /* finally let perl parse the actual subroutine body */
2316 551           body = parse_block(0);
2317              
2318             /* add '();' to make function return nothing by default */
2319             /* (otherwise the invisible parameter initialization can "leak" into
2320             the return value: fun ($x) {}->("asdf", 0) == 2) */
2321 551 100         if (prelude_sentinel->op) {
2322 537           body = newSTATEOP(0, NULL, body);
2323             }
2324              
2325 551           body = op_append_list(OP_LINESEQ, op_guard_relinquish(prelude_sentinel), body);
2326              
2327             /* it's go time. */
2328             {
2329 551           const bool runtime = cBOOL(spec->flags & FLAG_RUNTIME);
2330             CV *cv;
2331 551           OP *const attrs = op_guard_relinquish(attrs_sentinel);
2332              
2333 551 50         SvREFCNT_inc_simple_void(PL_compcv);
2334              
2335             /* close outer block: '}' */
2336 551           body = block_end(save_ix, body);
2337              
2338 551 100         cv = newATTRSUB(
    100          
    100          
    100          
2339             floor_ix,
2340             saw_name && !runtime && !spec->install_sub
2341             ? newSVOP(OP_CONST, 0, SvREFCNT_inc_simple_NN(saw_name)) : NULL,
2342             proto
2343             ? newSVOP(OP_CONST, 0, SvREFCNT_inc_simple_NN(proto)) : NULL,
2344             attrs,
2345             body
2346             );
2347              
2348 551 100         if (cv) {
2349             assert(cv != CvOUTSIDE(cv));
2350 547           register_info(aTHX_ PTR2UV(CvROOT(cv)), declarator, param_spec);
2351             }
2352              
2353 551 100         if (saw_name) {
2354 334 100         if (!runtime) {
2355 313 100         if (spec->install_sub) {
2356             SV *args[2];
2357 4           args[0] = saw_name;
2358 4           args[1] = sentinel_mortalize(sen, newRV_noinc((SV *)cv));
2359 4           call_from_curstash(aTHX_ sen, spec->install_sub, args, 2, G_VOID);
2360             }
2361 313           *pop = newOP(OP_NULL, 0);
2362             } else {
2363 21 100         *pop = newUNOP(
2364             OP_ENTERSUB, OPf_STACKED,
2365             op_append_elem(
2366             OP_LIST,
2367             op_append_elem(
2368             OP_LIST,
2369             mkconstsv(aTHX_ SvREFCNT_inc_simple_NN(saw_name)),
2370             mkanonsub(aTHX_ cv)
2371             ),
2372             newCVREF(
2373             OPf_WANT_SCALAR,
2374             mkconstsv(aTHX_
2375             spec->install_sub
2376             ? SvREFCNT_inc_simple_NN(spec->install_sub)
2377             : newSVpvs(MY_PKG "::_defun")
2378             )
2379             )
2380             )
2381             );
2382             }
2383 334           return KEYWORD_PLUGIN_STMT;
2384             }
2385              
2386 217           *pop = mkanonsub(aTHX_ cv);
2387 217           return KEYWORD_PLUGIN_EXPR;
2388             }
2389             }
2390              
2391 72570           static int kw_flags_enter(pTHX_ Sentinel **ppsen, const char *kw_ptr, STRLEN kw_len, KWSpec **ppspec) {
2392             HV *hints, *config;
2393              
2394             /* don't bother doing anything fancy after a syntax error */
2395 72570 50         if (PL_parser && PL_parser->error_count) {
    100          
2396 3           return FALSE;
2397             }
2398              
2399             STATIC_ASSERT_STMT(~(STRLEN)0 > (U32)I32_MAX);
2400 72567 50         if (kw_len > (STRLEN)I32_MAX) {
2401 0           return FALSE;
2402             }
2403              
2404 72567 50         if (!(hints = GvHV(PL_hintgv))) {
2405 0           return FALSE;
2406             }
2407              
2408             {
2409             SV **psv, *sv, *sv2;
2410 72567           I32 kw_xlen = kw_len;
2411              
2412 72567 100         if (!(psv = hv_fetchs(hints, HINTK_CONFIG, 0))) {
2413 68346           return FALSE;
2414             }
2415 4221           sv = *psv;
2416 4221 100         if (!SvROK(sv)) {
2417             /* something is wrong: $^H{'Function::Parameters/config'} has turned into a string */
2418 2           dSP;
2419              
2420 2 50         PUSHMARK(SP);
2421 2           call_pv(MY_PKG "::_warn_config_not_a_reference", G_VOID);
2422              
2423             /* don't warn twice within the same scope */
2424 2           hv_delete(hints, HINTK_CONFIG, sizeof HINTK_CONFIG - 1, G_DISCARD);
2425              
2426 2           return FALSE;
2427             }
2428 4219           sv2 = SvRV(sv);
2429 4219 50         if (SvTYPE(sv2) != SVt_PVHV) {
2430 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'} not a hashref: %"SVf, MY_PKG, HINTK_CONFIG, SVfARG(sv));
2431             }
2432 4219 100         if (lex_bufutf8()) {
2433 132           kw_xlen = -kw_xlen;
2434             }
2435 4219 100         if (!(psv = hv_fetch((HV *)sv2, kw_ptr, kw_xlen, 0))) {
2436 3601           return FALSE;
2437             }
2438 618           sv = *psv;
2439 618 50         if (!(SvROK(sv) && (sv2 = SvRV(sv), SvTYPE(sv2) == SVt_PVHV))) {
    50          
2440 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'} not a hashref: %"SVf, MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, SVfARG(sv));
2441             }
2442 618           config = (HV *)sv2;
2443             }
2444              
2445 618           ENTER;
2446 618           SAVETMPS;
2447              
2448 618           Newx(*ppsen, 1, Sentinel);
2449 618           ***ppsen = NULL;
2450 618           SAVEDESTRUCTOR_X(sentinel_clear_void, *ppsen);
2451              
2452 618           Newx(*ppspec, 1, KWSpec);
2453 618           (*ppspec)->flags = 0;
2454 618           (*ppspec)->reify_type = NULL;
2455 618           spv_init(&(*ppspec)->shift);
2456 618           (*ppspec)->attrs = sentinel_mortalize(**ppsen, newSVpvs(""));
2457 618           (*ppspec)->install_sub = NULL;
2458 618           sentinel_register(**ppsen, *ppspec, kws_free_void);
2459              
2460             #define FETCH_HINTSK_INTO(NAME, PSV) STMT_START { \
2461             SV **hsk_psv_; \
2462             if (!(hsk_psv_ = hv_fetchs(config, HINTSK_ ## NAME, 0))) { \
2463             Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'}{'%s'} not set", MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, HINTSK_ ## NAME); \
2464             } \
2465             *(PSV) = *hsk_psv_; \
2466             } STMT_END
2467              
2468             {
2469             SV *sv;
2470              
2471 618 50         FETCH_HINTSK_INTO(FLAGS, &sv);
2472 618 50         (*ppspec)->flags = SvIV(sv);
2473              
2474 618 50         FETCH_HINTSK_INTO(REIFY, &sv);
2475 618 50         if (!sv || !SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVCV) {
    50          
    50          
2476 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'}{'%s'} not a coderef: %"SVf, MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, HINTSK_REIFY, SVfARG(sv));
2477             }
2478 618           (*ppspec)->reify_type = sv;
2479              
2480 618 50         FETCH_HINTSK_INTO(SHIFT, &sv);
2481             {
2482             STRLEN sv_len;
2483 618 100         const char *const sv_p = SvPVutf8(sv, sv_len);
2484 618           const char *const sv_p_end = sv_p + sv_len;
2485 618           const char *p = sv_p;
2486 618           AV *shift_types = NULL;
2487 618           SV *type = NULL;
2488              
2489 814 100         while (p < sv_p_end) {
2490 196           const char *const v_start = p, *v_end;
2491 196 50         if (*p != '$') {
2492 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'}{'%s'}: expected '$', found '%.*s'", MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, HINTSK_SHIFT, (int)(sv_p_end - p), p);
2493             }
2494 196           p++;
2495 196 50         if (p >= sv_p_end || !MY_UNI_IDFIRST_utf8(p, sv_p_end)) {
    50          
    50          
    0          
    0          
    0          
    0          
    0          
2496 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'}{'%s'}: expected idfirst, found '%.*s'", MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, HINTSK_SHIFT, (int)(sv_p_end - p), p);
2497             }
2498 196           p += UTF8SKIP(p);
2499 812 50         while (p < sv_p_end && MY_UNI_IDCONT_utf8(p, sv_p_end)) {
    50          
    100          
    0          
    0          
    0          
    0          
    0          
2500 616           p += UTF8SKIP(p);
2501             }
2502 196           v_end = p;
2503 196 50         if (v_end == v_start + 2 && v_start[1] == '_') {
    0          
2504 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'}{'%s'}: can't use global $_ as a parameter", MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, HINTSK_SHIFT);
2505             }
2506             {
2507 196           size_t i, lim = (*ppspec)->shift.used;
2508 207 100         for (i = 0; i < lim; i++) {
2509 11 50         if (my_sv_eq_pvn(aTHX_ (*ppspec)->shift.data[i].name, v_start, v_end - v_start)) {
2510 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'}{'%s'}: %"SVf" can't appear twice", MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, HINTSK_SHIFT, SVfARG((*ppspec)->shift.data[i].name));
2511             }
2512             }
2513             }
2514 196 50         if (p < sv_p_end && *p == '/') {
    100          
2515 2           SSize_t tix = 0;
2516             SV **ptype;
2517 2           p++;
2518 4 50         while (p < sv_p_end && isDIGIT(*p)) {
    100          
2519 2           tix = tix * 10 + (*p - '0');
2520 2           p++;
2521             }
2522              
2523 2 50         if (!shift_types) {
2524             SV *sv2;
2525 2 50         FETCH_HINTSK_INTO(SHIF2, &sv);
2526 2 50         if (!(SvROK(sv) && (sv2 = SvRV(sv), SvTYPE(sv2) == SVt_PVAV))) {
    50          
2527 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'}{'%s'} not an arrayref: %"SVf, MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, HINTSK_SHIF2, SVfARG(sv));
2528             }
2529 2           shift_types = (AV *)sv2;
2530             }
2531 2 50         if (tix < 0 || tix > av_len(shift_types)) {
    50          
2532 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'}{'%s'}: tix [%ld] out of range [%ld]", MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, HINTSK_SHIFT, (long)tix, (long)(av_len(shift_types) + 1));
2533             }
2534 2           ptype = av_fetch(shift_types, tix, 0);
2535 2 50         if (!ptype) {
2536 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'}{'%s'}: tix [%ld] doesn't exist", MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, HINTSK_SHIFT, (long)tix);
2537             }
2538 2           type = *ptype;
2539 2 50         if (!sv_isobject(type)) {
2540 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'}{'%s'}: tix [%ld] is not an object (%"SVf")", MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, HINTSK_SHIFT, (long)tix, SVfARG(type));
2541             }
2542             }
2543              
2544 196           spv_push(&(*ppspec)->shift, sentinel_mortalize(**ppsen, newSVpvn_utf8(v_start, v_end - v_start, TRUE)), type);
2545 196 50         if (p < sv_p_end) {
2546 196 50         if (*p != ' ') {
2547 0           Perl_croak(aTHX_ "%s: internal error: $^H{'%s'}{'%.*s'}{'%s'}: expected ' ', found '%.*s'", MY_PKG, HINTK_CONFIG, (int)kw_len, kw_ptr, HINTSK_SHIFT, (int)(sv_p_end - p), p);
2548             }
2549 196           p++;
2550             }
2551             }
2552             }
2553              
2554 618 50         FETCH_HINTSK_INTO(ATTRS, &sv);
2555 618 50         SvSetSV((*ppspec)->attrs, sv);
2556              
2557 618 50         FETCH_HINTSK_INTO(INSTL, &sv);
2558 618 50         if (SvTRUE(sv)) {
    50          
    50          
    0          
    0          
    100          
    50          
    100          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    100          
2559             assert(SvROK(sv) || !(isDIGIT(*SvPV_nolen(sv))));
2560 12           (*ppspec)->install_sub = sv;
2561             }
2562             }
2563             #undef FETCH_HINTSK_INTO
2564              
2565 618           return TRUE;
2566             }
2567              
2568             static int (*next_keyword_plugin)(pTHX_ char *, STRLEN, OP **);
2569              
2570 72570           static int my_keyword_plugin(pTHX_ char *keyword_ptr, STRLEN keyword_len, OP **op_ptr) {
2571             Sentinel *psen;
2572             KWSpec *pspec;
2573             int ret;
2574              
2575 72570 100         if (kw_flags_enter(aTHX_ &psen, keyword_ptr, keyword_len, &pspec)) {
2576             /* scope was entered, 'psen' and 'pspec' are initialized */
2577 618           ret = parse_fun(aTHX_ *psen, op_ptr, keyword_ptr, keyword_len, pspec);
2578 551 100         FREETMPS;
2579 551           LEAVE;
2580             } else {
2581             /* not one of our keywords, no allocation done */
2582 71952           ret = next_keyword_plugin(aTHX_ keyword_ptr, keyword_len, op_ptr);
2583             }
2584              
2585 72503           return ret;
2586             }
2587              
2588             /* https://rt.perl.org/Public/Bug/Display.html?id=132413 */
2589             #ifndef wrap_keyword_plugin
2590             #define wrap_keyword_plugin(A, B) S_wrap_keyword_plugin(aTHX_ A, B)
2591 48           static void S_wrap_keyword_plugin(pTHX_ Perl_keyword_plugin_t new_plugin, Perl_keyword_plugin_t *old_plugin_p) {
2592             PERL_UNUSED_CONTEXT;
2593 48 50         if (*old_plugin_p) {
2594 0           return;
2595             }
2596             MUTEX_LOCK(&PL_op_mutex);
2597 48 50         if (!*old_plugin_p) {
2598 48           *old_plugin_p = PL_keyword_plugin;
2599 48           PL_keyword_plugin = new_plugin;
2600             }
2601             MUTEX_UNLOCK(&PL_op_mutex);
2602             }
2603             #endif
2604              
2605 48           static void my_boot(pTHX) {
2606 48           HV *const stash = gv_stashpvs(MY_PKG, GV_ADD);
2607              
2608 48           newCONSTSUB(stash, "FLAG_NAME_OK", newSViv(FLAG_NAME_OK));
2609 48           newCONSTSUB(stash, "FLAG_ANON_OK", newSViv(FLAG_ANON_OK));
2610 48           newCONSTSUB(stash, "FLAG_DEFAULT_ARGS", newSViv(FLAG_DEFAULT_ARGS));
2611 48           newCONSTSUB(stash, "FLAG_CHECK_NARGS", newSViv(FLAG_CHECK_NARGS));
2612 48           newCONSTSUB(stash, "FLAG_INVOCANT", newSViv(FLAG_INVOCANT));
2613 48           newCONSTSUB(stash, "FLAG_NAMED_PARAMS", newSViv(FLAG_NAMED_PARAMS));
2614 48           newCONSTSUB(stash, "FLAG_TYPES_OK", newSViv(FLAG_TYPES_OK));
2615 48           newCONSTSUB(stash, "FLAG_CHECK_TARGS", newSViv(FLAG_CHECK_TARGS));
2616 48           newCONSTSUB(stash, "FLAG_RUNTIME", newSViv(FLAG_RUNTIME));
2617 48           newCONSTSUB(stash, "HINTK_CONFIG", newSVpvs(HINTK_CONFIG));
2618 48           newCONSTSUB(stash, "HINTSK_FLAGS", newSVpvs(HINTSK_FLAGS));
2619 48           newCONSTSUB(stash, "HINTSK_SHIFT", newSVpvs(HINTSK_SHIFT));
2620 48           newCONSTSUB(stash, "HINTSK_SHIF2", newSVpvs(HINTSK_SHIF2));
2621 48           newCONSTSUB(stash, "HINTSK_ATTRS", newSVpvs(HINTSK_ATTRS));
2622 48           newCONSTSUB(stash, "HINTSK_REIFY", newSVpvs(HINTSK_REIFY));
2623 48           newCONSTSUB(stash, "HINTSK_INSTL", newSVpvs(HINTSK_INSTL));
2624              
2625 48           wrap_keyword_plugin(my_keyword_plugin, &next_keyword_plugin);
2626 48           }
2627              
2628             #ifndef assert_
2629             #ifdef DEBUGGING
2630             #define assert_(X) assert(X),
2631             #else
2632             #define assert_(X)
2633             #endif
2634             #endif
2635              
2636             #ifndef gv_method_changed
2637             #define gv_method_changed(GV) ( \
2638             assert_(isGV_with_GP(GV)) \
2639             GvREFCNT(GV) > 1 \
2640             ? (void)PL_sub_generation++ \
2641             : mro_method_changed_in(GvSTASH(GV)) \
2642             )
2643             #endif
2644              
2645             WARNINGS_RESET
2646              
2647             MODULE = Function::Parameters PACKAGE = Function::Parameters PREFIX = fp_
2648             PROTOTYPES: ENABLE
2649              
2650             UV
2651             fp__cv_root(sv)
2652             SV *sv
2653             PREINIT:
2654             CV *xcv;
2655             HV *hv;
2656             GV *gv;
2657             CODE:
2658 18           xcv = sv_2cv(sv, &hv, &gv, 0);
2659 18 50         RETVAL = PTR2UV(xcv ? CvROOT(xcv) : NULL);
2660             OUTPUT:
2661             RETVAL
2662              
2663             void
2664             fp__defun(name, body)
2665             SV *name
2666             CV *body
2667             PREINIT:
2668             GV *gv;
2669             CV *xcv;
2670             CODE:
2671             assert(SvTYPE(body) == SVt_PVCV);
2672 12           gv = gv_fetchsv(name, GV_ADDMULTI, SVt_PVCV);
2673 12           xcv = GvCV(gv);
2674 12 100         if (xcv) {
2675 1 50         if (!GvCVGEN(gv) && (CvROOT(xcv) || CvXSUB(xcv)) && ckWARN(WARN_REDEFINE)) {
    50          
    0          
    50          
2676 0           warner(packWARN(WARN_REDEFINE), "Subroutine %"SVf" redefined", SVfARG(name));
2677             }
2678 1           SvREFCNT_dec_NN(xcv);
2679             }
2680 12           GvCVGEN(gv) = 0;
2681 12           GvASSUMECV_on(gv);
2682 12 50         if (GvSTASH(gv)) {
2683 12 100         gv_method_changed(gv);
2684             }
2685 12           GvCV_set(gv, (CV *)SvREFCNT_inc_simple_NN(body));
2686 12           CvGV_set(body, gv);
2687 12           CvANON_off(body);
2688              
2689             BOOT:
2690 48           my_boot(aTHX);