File Coverage

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