File Coverage

Declare.xs
Criterion Covered Total %
statement 576 601 95.8
branch 340 426 79.8
condition n/a
subroutine n/a
pod n/a
total 916 1027 89.1


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4             #include "ppport.h" /* backports the OpSIBLING / OpLASTSIB_set op-tree macros to
5             perl 5.14-5.20 (added to core in 5.22) */
6              
7             /* pad_add_name_pvn was a 5.15.1 rename of pad_add_name; the 5.14 function has the
8             * identical (name, len, flags, typestash, ourstash) */
9             #if PERL_VERSION < 16
10             # define pad_add_name_pvn(name, len, flags, typestash, ourstash) \
11             Perl_pad_add_name(aTHX_ (name), (len), (flags), (typestash), (ourstash))
12             /* pad_findmy_pvn is the 5.15.1 rename of pad_findmy; the 5.14 function takes the
13             * identical (name, len, flags) arguments. */
14             # define pad_findmy_pvn(name, len, flags) \
15             Perl_pad_findmy(aTHX_ (name), (len), (flags))
16             #endif
17              
18             #define MAX_ARMS 4096
19              
20             /* Shared compile-time destructuring engine (dd_pat / dd_parse_pattern / dd_emit
21             * and the dd_tail / dd_hrest custom ops). Powers the `case PAT -> [..]` binding
22             * bridge below. Must come after the pad_add_name_pvn shim above. */
23             #include "destructure.h"
24              
25             /* Previous keyword plugin in the chain. */
26             static int (*sd_next_keyword_plugin)(pTHX_ char *, STRLEN, OP **);
27              
28             /* Read a bareword identifier from the lexer (or NULL if none). */
29 499           static SV *sd_lex_read_ident(pTHX) {
30 499           SV *buf = newSVpvs("");
31             I32 c;
32             while (1) {
33 3095           c = lex_peek_unichar(0);
34 3095 50         if (c == -1) break;
35 3095 50         if (!isALNUM(c) && c != '_') break;
    100          
    50          
36 2596           sv_catpvf(buf, "%c", (int)c);
37 2596           lex_read_unichar(0);
38             }
39 499 50         if (SvCUR(buf) == 0) {
40 0           SvREFCNT_dec(buf);
41 0           return NULL;
42             }
43 499           return buf;
44             }
45              
46             /* Read a possibly package-qualified sub name (Foo::bar, Foo'bar). */
47 154           static SV *sd_lex_subname(pTHX) {
48 154           SV *buf = newSVpvs("");
49             I32 c;
50             while (1) {
51 765           c = lex_peek_unichar(0);
52 765 50         if (c == -1) break;
53 765 50         if (isALNUM(c) || c == '_') {
    100          
    50          
54 609           sv_catpvf(buf, "%c", (int)c);
55 609           lex_read_unichar(0);
56 156 100         } else if (c == ':' && PL_parser->bufptr[0] == ':'
    50          
57 2 50         && PL_parser->bufptr[1] == ':') {
58 2           sv_catpvs(buf, "::");
59 2           lex_read_unichar(0);
60 2           lex_read_unichar(0);
61             } else break;
62             }
63 154 100         if (SvCUR(buf) == 0) {
64 1           SvREFCNT_dec(buf);
65 1           return NULL;
66             }
67 153           return buf;
68             }
69              
70             /* Hand-lex a numeric literal (optional sign, integer/float/exponent). */
71 114           static SV *sd_lex_number(pTHX) {
72 114           SV *buf = newSVpvs("");
73 114           I32 c = lex_peek_unichar(0);
74 114           int seen_dot = 0, seen_digit = 0;
75 114 100         if (c == '-' || c == '+') {
    100          
76 5           sv_catpvf(buf, "%c", (int)c);
77 5           lex_read_unichar(0);
78             }
79             while (1) {
80 257           c = lex_peek_unichar(0);
81 257 100         if (c >= '0' && c <= '9') { seen_digit = 1; }
    100          
82 119 100         else if (c == '.' && !seen_dot) {
    50          
83             /* Only a decimal point if followed by a digit; otherwise it is
84             * the '..' range operator (or a terminator) - leave it alone. */
85 5 50         char next = (PL_parser->bufptr[0] == '.') ? PL_parser->bufptr[1] : '\0';
86 5 100         if (next < '0' || next > '9') break;
    50          
87 4           seen_dot = 1;
88             }
89 114 100         else if ((c == 'e' || c == 'E') && seen_digit) {
    50          
    50          
90 1           sv_catpvf(buf, "%c", (int)c);
91 1           lex_read_unichar(0);
92 1           c = lex_peek_unichar(0);
93 1 50         if (c == '-' || c == '+') {
    50          
94 0           sv_catpvf(buf, "%c", (int)c);
95 0           lex_read_unichar(0);
96             }
97 1           continue;
98             }
99             else break;
100 142           sv_catpvf(buf, "%c", (int)c);
101 142           lex_read_unichar(0);
102             }
103 114 50         if (!seen_digit) {
104 0           SvREFCNT_dec(buf);
105 0           croak("switch: malformed numeric case pattern");
106             }
107 114           return buf;
108             }
109              
110             /* Hand-lex a quoted string literal ('...' or "..."), basic backslash escapes. */
111 93           static SV *sd_lex_string(pTHX) {
112 93           I32 quote = lex_read_unichar(0);
113 93           SV *sv = newSVpvs("");
114             I32 c;
115             while (1) {
116 238           c = lex_read_unichar(0);
117 238 100         if (c == -1) croak("switch: unterminated string in case pattern");
118 237 100         if (c == '\\') {
119 2           I32 next = lex_read_unichar(0);
120 2 50         if (next == -1) croak("switch: unterminated string in case pattern");
121 2 100         if (quote == '"') {
122 1           switch (next) {
123 0           case 'n': sv_catpvs(sv, "\n"); break;
124 1           case 't': sv_catpvs(sv, "\t"); break;
125 0           case 'r': sv_catpvs(sv, "\r"); break;
126 0           case '0': sv_catpvs(sv, "\0"); break;
127 0           default: sv_catpvf(sv, "%c", (int)next); break;
128             }
129             } else {
130             /* single quotes: only \\ and \' are special */
131 1 50         if (next != '\\' && next != '\'')
    50          
132 1           sv_catpvf(sv, "%c", '\\');
133 1           sv_catpvf(sv, "%c", (int)next);
134             }
135 235 100         } else if (c == quote) {
136 92           break;
137             } else {
138 143           sv_catpvf(sv, "%c", (int)c);
139             }
140             }
141 92           return sv;
142             }
143              
144             /* Describes where the matched topic comes from. When the scrutinee is already
145             * a plain lexical or a constant, each case test re-reads it directly (just like
146             * a hand-written if/elsif chain) and no temp / do-block is needed. Otherwise
147             * the scrutinee is stored once in a pad temp. */
148             #define SDT_TEMP 0 /* stored once in pad temp `off` (do-block) */
149             #define SDT_PAD 1 /* re-read scrutinee's own lexical at `off` */
150             #define SDT_CONST 2 /* re-read a constant value */
151              
152             /* How the numeric looks_like_number($topic) guard is sourced. For a defined
153             * constant scrutinee it folds to a compile-time boolean; otherwise it is
154             * computed once into a pad temp and each numeric arm just reads that temp. */
155             #define LLN_CONST 0 /* compile-time constant in `lln_const` */
156             #define LLN_PAD 1 /* computed once into pad temp `lln_off` */
157              
158             typedef struct {
159             int kind;
160             PADOFFSET off;
161             SV *sv;
162             int lln_mode; /* LLN_CONST or LLN_PAD */
163             int lln_const; /* folded looks_like_number value (LLN_CONST) */
164             PADOFFSET lln_off; /* pad temp holding the guard (LLN_PAD) */
165             int lln_used; /* a numeric arm referenced the LLN_PAD temp */
166             } SDTopic;
167              
168             /* A fresh op yielding the topic value. */
169 417           static OP *sd_topic(pTHX_ SDTopic *t) {
170 417 100         if (t->kind == SDT_CONST)
171 201           return newSVOP(OP_CONST, 0, newSVsv(t->sv));
172             {
173 216           OP *o = newOP(OP_PADSV, 0);
174 216           o->op_targ = t->off;
175 216           return o;
176             }
177             }
178              
179             /* ---- looks_like_number($topic) as a fast custom op ---------------------
180             * A numeric pattern (==, range, list) must only fire for a topic that really
181             * is a number. Without this, `switch("one") { case 1 {...} }` would warn
182             * ("Argument isn't numeric in numeric eq") and - worse - "one" == 0 would
183             * *match* a `case 0`. Guarding each numeric compare with looks_like_number()
184             * makes a non-numeric topic simply not match (and not warn), mirroring how an
185             * undef topic is handled. It compiles to a single custom op: no sub call, no
186             * module dependency. */
187 216           static OP *sd_pp_looks_number(pTHX) {
188 216           dSP;
189 216           SV *sv = TOPs;
190 216 50         SETs(boolSV(sv && SvOK(sv) && looks_like_number(sv)));
    100          
    100          
191 216           RETURN;
192             }
193              
194             static XOP sd_looks_number_xop;
195              
196             /* The raw looks_like_number($topic) custom op (one pp call, no sub call).
197             * Built as an OP_NULL unop (always accepted by newUNOP on every perl) then
198             * retyped to our registered custom op; newUNOP sets OPf_KIDS so op_free still
199             * reclaims the child topic op. */
200 19           static OP *sd_looks_number_op(pTHX_ SDTopic *t) {
201 19           OP *o = newUNOP(OP_NULL, 0, sd_topic(aTHX_ t));
202 19           o->op_type = OP_CUSTOM;
203 19           o->op_ppaddr = sd_pp_looks_number;
204 19           return o;
205             }
206              
207             /* looks_like_number(OPERAND) over an arbitrary operand op (not just the topic).
208             * Used to guard a `case num $var` operand so a non-numeric $var neither matches
209             * nor warns - mirroring the topic guard. */
210 11           static OP *sd_lln_raw(pTHX_ OP *operand) {
211 11           OP *o = newUNOP(OP_NULL, 0, operand);
212 11           o->op_type = OP_CUSTOM;
213 11           o->op_ppaddr = sd_pp_looks_number;
214 11           return o;
215             }
216              
217             /* The numeric guard expression used by each numeric arm. For a defined constant
218             * topic it folds to a compile-time boolean; otherwise the guard is computed once
219             * per switch (see the LLN_PAD prelude in sd_parse_switch) and each arm just reads
220             * that pad temp - so a switch with N numeric arms calls looks_like_number once,
221             * not N times. */
222 128           static OP *sd_looks_number(pTHX_ SDTopic *t) {
223 128 100         if (t->lln_mode == LLN_CONST)
224 97 100         return newSVOP(OP_CONST, 0, boolSV(t->lln_const));
225 31           t->lln_used = 1;
226             {
227 31           OP *o = newOP(OP_PADSV, 0);
228 31           o->op_targ = t->lln_off;
229 31           return o;
230             }
231             }
232              
233             /* ---- reftype($topic) as a fast custom op -------------------------------
234             * Like ref(), but reports the underlying type ("ARRAY"/"HASH"/...) even for a
235             * blessed reference, and undef for a non-reference. Used by the reftype(TYPE)
236             * pattern. Same OP_NULL->OP_CUSTOM construction as the looks_number op. */
237 11           static OP *sd_pp_reftype(pTHX) {
238 11           dSP;
239 11           SV *sv = TOPs;
240             /* Like ref(), a non-reference yields a defined empty/false value (not
241             * undef) so `reftype(TYPE)` compares as `"" eq "TYPE"` without warning and
242             * bare `reftype` is simply false. */
243 11 100         SETs(SvROK(sv) ? sv_2mortal(newSVpv(sv_reftype(SvRV(sv), 0), 0))
244             : &PL_sv_no);
245 11           RETURN;
246             }
247              
248             static XOP sd_reftype_xop;
249              
250 11           static OP *sd_reftype_op(pTHX_ SDTopic *t) {
251 11           OP *o = newUNOP(OP_NULL, 0, sd_topic(aTHX_ t));
252 11           o->op_type = OP_CUSTOM;
253 11           o->op_ppaddr = sd_pp_reftype;
254 11           return o;
255             }
256              
257             /* When every arm maps a distinct string-literal key to a constant value (a
258             * lookup table) and there are at least this many of them, the whole switch is
259             * lowered to a single O(1) hash lookup against a compile-time constant hash
260             * instead of an O(n) chain of eq tests. */
261             #define SD_DISPATCH_MIN 4
262              
263             /* What a case pattern was, for dispatch eligibility. */
264             typedef struct {
265             int str_key; /* 1 if an exact string-literal pattern (eq) */
266             SV *key; /* the literal (owned) when str_key */
267             int is_undef; /* 1 if the pattern was the `undef` keyword */
268             int undef_safe; /* 1 if the pattern can't match/warn on an undef topic */
269             } SDPat;
270              
271             /* A fresh $PKGHASH{ topic } element op, where the hash is the package
272             * variable named by `gv`. Referencing the hash through a GV (rather than an
273             * op-constant hashref) keeps the dispatch table thread-safe: op constants are
274             * cloned per-thread, which would dangle a reference to a shared HV.
275             *
276             * When `sentinel` is non-NULL the topic may be undef, so the key is guarded as
277             * defined($topic) ? $topic : SENTINEL
278             * with SENTINEL a string known not to be in the table - an undef topic then
279             * misses cleanly (-> default) instead of warning on an undef hash key. */
280 8           static OP *sd_helem(pTHX_ GV *gv, SDTopic *t, SV *sentinel) {
281 8           OP *gvop = newGVOP(OP_GV, 0, gv);
282 8           OP *deref = newUNOP(OP_RV2HV, OPf_REF, gvop);
283             OP *key;
284 8 100         if (sentinel)
285 5           key = newCONDOP(0, newUNOP(OP_DEFINED, 0, sd_topic(aTHX_ t)),
286             sd_topic(aTHX_ t),
287             newSVOP(OP_CONST, 0, newSVsv(sentinel)));
288             else
289 3           key = sd_topic(aTHX_ t);
290 8           return newBINOP(OP_HELEM, 0, deref, key);
291             }
292              
293             /* Read a literal (number or string) into an OP_CONST, setting *is_num. */
294 205           static OP *sd_lex_literal(pTHX_ int *is_num) {
295 205           I32 c = lex_peek_unichar(0);
296 205 100         if (c == '"' || c == '\'') {
    100          
297 91           *is_num = 0;
298 91           return newSVOP(OP_CONST, 0, sd_lex_string(aTHX));
299             }
300 114 100         if ((c >= '0' && c <= '9') || c == '-' || c == '+' || c == '.') {
    50          
    100          
    50          
    0          
301 114           *is_num = 1;
302 114           return newSVOP(OP_CONST, 0, sd_lex_number(aTHX));
303             }
304 0           croak("switch: expected a number or string literal");
305             return NULL; /* not reached */
306             }
307              
308             /* topic CMP const, where CMP is numeric (==/>=/<=) or string (eq/ge/le).
309             * Numeric comparisons are guarded by looks_like_number($topic) so a non-numeric
310             * topic never matches or warns; string comparisons (eq/ge/le) never warn and
311             * need no guard. */
312 226           static OP *sd_cmp(pTHX_ SDTopic *t, int is_num, I32 numop, I32 strop, OP *konst) {
313 226 100         OP *cmp = newBINOP(is_num ? numop : strop, 0, sd_topic(aTHX_ t), konst);
314 226 100         if (is_num)
315 128           cmp = newLOGOP(OP_AND, 0, sd_looks_number(aTHX_ t), cmp);
316 226           return cmp;
317             }
318              
319             /* ---- $topic =~ PATTERN as a fast custom op ----------------------------
320             * The `=~ $var` pattern matches the topic against a *runtime* pattern held in a
321             * scalar (a qr// or a string), so it cannot be compiled once at compile time
322             * like the `/literal/` form. Rather than hand-wire an OP_REGCOMP/OP_MATCH pair
323             * (fragile to thread correctly), it is a self-contained custom op in the same
324             * family as the looks_number / reftype ops: pop the pattern and the topic, run
325             * the match, push a boolean. A qr// operand reuses its compiled program; a bare
326             * string is compiled per evaluation (and freed). Both operands are guaranteed
327             * defined here - the pattern is guarded with defined() and an undef topic is
328             * guarded by the chain - so the match itself never warns. */
329 6           static OP *sd_pp_rxmatch(pTHX) {
330 6           dSP;
331 6           SV *pat = POPs;
332 6           SV *str = TOPs;
333 6           bool matched = FALSE;
334 6 100         REGEXP *rx = SvRXOK(pat) ? SvRX(pat) : NULL;
335 6           int owned = 0;
336 6 100         if (!rx) { rx = pregcomp(pat, 0); owned = 1; }
337 6 50         if (rx) {
338             STRLEN len;
339 6           char *s = SvPV(str, len);
340 6 100         if (pregexec(rx, s, s + len, s, 0, str, 1))
341 5           matched = TRUE;
342 6 100         if (owned) ReREFCNT_dec(rx);
343             }
344 6 100         SETs(boolSV(matched));
345 6           RETURN;
346             }
347              
348             static XOP sd_rxmatch_xop;
349              
350             /* topic and pattern are pushed by the two child ops; the custom op pops both.
351             * A native OP_MATCH cannot be built here - perl's pattern builders (pmruntime)
352             * are entangled with the parser's own pattern-lexing state and crash when driven
353             * from a keyword plugin - so this is a self-contained custom op. The trade-off
354             * is that it is a pure membership test: it sets no capture variables ($1, @+).
355             * For captures from a runtime pattern, use a predicate arm: case sub { $_[0] =~ $rx }. */
356 8           static OP *sd_rxmatch_op(pTHX_ SDTopic *t, OP *patop) {
357 8           OP *o = newBINOP(OP_NULL, 0, sd_topic(aTHX_ t), patop);
358 8           o->op_type = OP_CUSTOM;
359 8           o->op_ppaddr = sd_pp_rxmatch;
360 8           return o;
361             }
362              
363             /* Build CALLEE->( topic ) as an entersub. The OP_ENTERSUB checker inserts the
364             * pushmark itself, so we must NOT add one - a second pushmark leaves a dangling
365             * mark that corrupts a surrounding list/aassign at runtime. */
366 21           static OP *sd_predicate_call(pTHX_ OP *callee, SDTopic *t) {
367 21           OP *args = op_append_elem(OP_LIST, sd_topic(aTHX_ t), callee);
368 21           return newUNOP(OP_ENTERSUB, OPf_STACKED, args);
369             }
370              
371             /* Build Switch::Declare::_isa($topic, "Class") -> true iff the topic is a
372             * blessed object derived from Class (a fast @ISA check; see the XS _isa below).
373             * An entersub rather than a custom op keeps the two-argument call portable
374             * across the supported perls. */
375 12           static OP *sd_isa_call(pTHX_ SDTopic *t, SV *klass) {
376 12           GV *gv = gv_fetchpvs("Switch::Declare::_isa", GV_ADD, SVt_PVCV);
377 12           OP *cvop = newUNOP(OP_RV2CV, 0, newGVOP(OP_GV, 0, gv));
378 12           OP *args = op_append_elem(OP_LIST, sd_topic(aTHX_ t),
379             newSVOP(OP_CONST, 0, klass));
380 12           args = op_append_elem(OP_LIST, args, cvop);
381 12           return newUNOP(OP_ENTERSUB, OPf_STACKED, args);
382             }
383              
384             /* Read an optional/required ( NAME ) argument after a pattern keyword, where
385             * NAME is a package-qualified bareword (ARRAY, Foo::Bar) or a quoted string.
386             * Returns the name SV (caller owns) or NULL when there is no '('. */
387 48           static SV *sd_lex_paren_arg(pTHX) {
388             I32 c;
389             SV *name;
390 48           lex_read_space(0);
391 48 100         if (lex_peek_unichar(0) != '(') return NULL;
392 40           lex_read_unichar(0);
393 40           lex_read_space(0);
394 40           c = lex_peek_unichar(0);
395 40 100         if (c == '"' || c == '\'')
    50          
396 2           name = sd_lex_string(aTHX);
397             else
398 38           name = sd_lex_subname(aTHX);
399 40 50         if (!name) croak("switch: expected a name inside (...)");
400 40           lex_read_space(0);
401 40 50         if (lex_peek_unichar(0) != ')') {
402 0           SvREFCNT_dec(name);
403 0           croak("switch: expected ')' after pattern argument");
404             }
405 40           lex_read_unichar(0);
406 40           return name;
407             }
408              
409             /* A parsed scalar-variable operand for `case num $x` / `case str $x`. It is
410             * either an in-scope lexical (off != NOT_IN_PAD) or a package scalar (gv), and
411             * is rebuilt fresh by sd_var_op on each use so the operand can be referenced by
412             * both the type guard and the comparison without sharing an op. */
413             typedef struct { PADOFFSET off; GV *gv; } SDVar;
414              
415             /* Hand-lex a plain scalar variable - the leading '$' is still unread. Restricted
416             * to a bare `$name` / `$Pkg::name` (no `[...]`/`{...}` element access) so the
417             * arm's opening `{` is never misparsed as a `$x{...}` hash subscript. */
418 26           static void sd_lex_scalar_var(pTHX_ SDVar *v) {
419             SV *name, *withsig;
420             PADOFFSET off;
421 26 100         if (lex_peek_unichar(0) != '$')
422 1           croak("switch: expected a scalar variable ($name) after ==, eq, or =~");
423 25           lex_read_unichar(0);
424 25           name = sd_lex_subname(aTHX);
425 25 50         if (!name) croak("switch: expected a variable name after '$'");
426 25           withsig = newSVpvs("$");
427 25           sv_catsv(withsig, name);
428 25           off = pad_findmy_pvn(SvPVX(withsig), SvCUR(withsig), 0);
429 25           SvREFCNT_dec(withsig);
430 25 100         if (off != NOT_IN_PAD) {
431             /* An `our` variable has a pad entry, but the slot aliases a GV rather
432             * than holding the value - reading it as a plain PADSV is wrong. Resolve
433             * it to the package scalar it really is, qualified by the `our`'s own
434             * stash so the lookup neither trips strict 'vars' nor guesses the wrong
435             * package. The PAD_COMPNAME_* macros take the offset directly and are
436             * stable from 5.8 through current perl, so this is one path on every
437             * version - unlike the PADNAME API, which only exists from 5.18. */
438 24 100         if (PAD_COMPNAME_FLAGS_isOUR(off)) {
439 2           HV *stash = PAD_COMPNAME_OURSTASH(off);
440 2           SV *q = newSVpvs("");
441 2 50         if (stash && HvNAME(stash))
    50          
    50          
    50          
    50          
    50          
    50          
442 2 50         sv_catpvf(q, "%s::", HvNAME(stash));
    50          
    50          
    0          
    50          
    50          
443 2           sv_catsv(q, name);
444 2           v->off = NOT_IN_PAD;
445 2           v->gv = gv_fetchpv(SvPV_nolen(q), GV_ADD, SVt_PV);
446 2           SvREFCNT_dec(q);
447 2           SvREFCNT_dec(name);
448 2           return;
449             }
450 22           v->off = off;
451 22           v->gv = NULL;
452             } else {
453             /* A plain package global: sd_lex_subname keeps any `Pkg::` qualifier, so
454             * gv_fetchpv sees a qualified name and strict 'vars' stays satisfied. */
455 1           v->off = NOT_IN_PAD;
456 1           v->gv = gv_fetchpv(SvPV_nolen(name), GV_ADD, SVt_PV);
457             }
458 23           SvREFCNT_dec(name);
459             }
460              
461             /* A fresh op yielding the variable operand's value. */
462 50           static OP *sd_var_op(pTHX_ SDVar *v) {
463 50 100         if (v->off != NOT_IN_PAD) {
464 44           OP *o = newOP(OP_PADSV, 0);
465 44           o->op_targ = v->off;
466 44           return o;
467             }
468 6           return newUNOP(OP_RV2SV, 0, newGVOP(OP_GV, 0, v->gv));
469             }
470              
471             /* Parse one case PATTERN from the lexer and return its boolean condition op,
472             * testing the topic. Fills *pat describing the pattern (for dispatch). */
473 299           static OP *sd_parse_case_cond(pTHX_ SDTopic *t, SDPat *pat) {
474 299           I32 c = lex_peek_unichar(0);
475 299           pat->str_key = 0;
476 299           pat->key = NULL;
477 299           pat->is_undef = 0;
478 299           pat->undef_safe = 0;
479              
480             /* regex: /PATTERN/flags -> native topic =~ /PATTERN/flags
481             * The pattern is compiled once, here at compile time, and bound to a
482             * standard OP_MATCH - no runtime helper, no per-match recompilation. */
483 299 100         if (c == '/') {
484 16           SV *pat = newSVpvs("");
485 16           U32 rxflags = 0;
486             REGEXP *rx;
487             PMOP *pmop;
488             OP *target;
489 16           lex_read_unichar(0);
490             while (1) {
491 92           c = lex_read_unichar(0);
492 92 100         if (c == -1) croak("switch: unterminated regex in case pattern");
493 91 100         if (c == '\\') {
494 5           I32 n = lex_read_unichar(0);
495 5 50         if (n == -1) croak("switch: unterminated regex in case pattern");
496 5           sv_catpvf(pat, "%c", '\\');
497 5           sv_catpvf(pat, "%c", (int)n);
498 5           continue;
499             }
500 86 100         if (c == '/') break;
501 71           sv_catpvf(pat, "%c", (int)c);
502             }
503 22 100         while (isALPHA((c = lex_peek_unichar(0)))) {
504 8           switch (c) {
505 3           case 'i': rxflags |= PMf_FOLD; break;
506 2           case 'm': rxflags |= PMf_MULTILINE; break;
507 1           case 's': rxflags |= PMf_SINGLELINE; break;
508 1           case 'x': rxflags |= PMf_EXTENDED; break;
509 1           default: croak("switch: unsupported regex flag '%c' in case pattern", (int)c);
510             }
511 7           lex_read_unichar(0);
512             }
513 14           rx = pregcomp(pat, rxflags);
514 14           SvREFCNT_dec(pat);
515 14           pmop = (PMOP *)newPMOP(OP_MATCH, 0);
516 14           PM_SETRE(pmop, rx);
517             /* bind the topic as the match target ($topic =~ ...) */
518 14           target = sd_topic(aTHX_ t);
519 14           ((PMOP *)pmop)->op_first = target;
520 14           ((PMOP *)pmop)->op_last = target;
521 14           OpLASTSIB_set(target, (OP *)pmop);
522 14           pmop->op_flags |= OPf_KIDS | OPf_STACKED;
523 14           return (OP *)pmop;
524             }
525              
526             /* predicate: \&name -> name($topic) */
527 283 100         if (c == '\\') {
528             SV *name;
529             GV *gv;
530             OP *cvop;
531 11           lex_read_unichar(0);
532 11 100         if (lex_peek_unichar(0) != '&')
533 1           croak("switch: expected '&' after '\\' in case predicate");
534 10           lex_read_unichar(0);
535 10           name = sd_lex_subname(aTHX);
536 10 100         if (!name) croak("switch: expected sub name after '\\&'");
537 9           gv = gv_fetchpv(SvPV_nolen(name), GV_ADD, SVt_PVCV);
538 9           SvREFCNT_dec(name);
539 9           cvop = newUNOP(OP_RV2CV, 0, newGVOP(OP_GV, 0, gv));
540 9           return sd_predicate_call(aTHX_ cvop, t);
541             }
542              
543             /* bracket: [LO .. HI] range, or [a, b, c] membership list */
544 272 100         if (c == '[') {
545             int is_num;
546             OP *first;
547 26           lex_read_unichar(0);
548 26           lex_read_space(0);
549 26           first = sd_lex_literal(aTHX_ &is_num);
550 26           lex_read_space(0);
551 26 100         if (lex_peek_unichar(0) == '.') {
552             /* range: [LO .. HI] */
553             OP *hi;
554             int hi_num;
555 14           lex_read_unichar(0);
556 14 100         if (lex_peek_unichar(0) != '.')
557 1           croak("switch: expected '..' in range case pattern");
558 13           lex_read_unichar(0);
559 13           lex_read_space(0);
560 13           hi = sd_lex_literal(aTHX_ &hi_num);
561 13           lex_read_space(0);
562 13 50         if (lex_peek_unichar(0) != ']')
563 0           croak("switch: expected ']' to close range case pattern");
564 13           lex_read_unichar(0);
565 13           return newLOGOP(OP_AND, 0,
566             sd_cmp(aTHX_ t, is_num, OP_GE, OP_SGE, first),
567             sd_cmp(aTHX_ t, hi_num, OP_LE, OP_SLE, hi));
568             }
569             /* membership list: [a, b, c] -> OR-chain of equality tests */
570             {
571 12           OP *chain = sd_cmp(aTHX_ t, is_num, OP_EQ, OP_SEQ, first);
572 22           while (1) {
573             OP *elt;
574             int en;
575 34           lex_read_space(0);
576 34 100         if (lex_peek_unichar(0) == ',') lex_read_unichar(0);
577 34           lex_read_space(0);
578 34 100         if (lex_peek_unichar(0) == ']') { lex_read_unichar(0); break; }
579 22           elt = sd_lex_literal(aTHX_ &en);
580 22           chain = newLOGOP(OP_OR, 0, chain,
581             sd_cmp(aTHX_ t, en, OP_EQ, OP_SEQ, elt));
582             }
583 12           return chain;
584             }
585             }
586              
587             /* == $var : numeric comparison against a runtime scalar.
588             * =~ $var : regex match against a runtime pattern (a qr// or string in a
589             * variable). Because a variable's type/pattern is unknown at
590             * compile time, the operator is written out - `==` for numeric,
591             * `=~` for match (here); `eq` for string is a bareword, below. */
592 246 100         if (c == '=') {
593             SDVar v;
594             I32 c2;
595 21           lex_read_unichar(0);
596 21           c2 = lex_peek_unichar(0);
597 21 100         if (c2 == '=') {
598 11           lex_read_unichar(0);
599 11           lex_read_space(0);
600 11           sd_lex_scalar_var(aTHX_ &v);
601             /* looks_like_number($var) && looks_like_number($topic)
602             * && $topic == $var - undef-safe both sides. */
603 11           pat->undef_safe = 1;
604 11           return newLOGOP(OP_AND, 0,
605             sd_lln_raw(aTHX_ sd_var_op(aTHX_ &v)),
606             sd_cmp(aTHX_ t, 1, OP_EQ, OP_SEQ, sd_var_op(aTHX_ &v)));
607             }
608 10 100         if (c2 == '~') {
609 9           lex_read_unichar(0);
610 9           lex_read_space(0);
611 9           sd_lex_scalar_var(aTHX_ &v);
612             /* defined($var) && $topic =~ $var. An undef topic is guarded by the
613             * chain (undef_safe = 0); guarding $var keeps an undef pattern from
614             * warning (it simply does not match). */
615 8           pat->undef_safe = 0;
616 8           return newLOGOP(OP_AND, 0,
617             newUNOP(OP_DEFINED, 0, sd_var_op(aTHX_ &v)),
618             sd_rxmatch_op(aTHX_ t, sd_var_op(aTHX_ &v)));
619             }
620 1           croak("switch: expected '==' or '=~' in case comparison");
621             }
622              
623             /* inline predicate: sub { ... } -> (sub { ... })->($topic)
624             * undef keyword: undef -> !defined($topic)
625             * ref / ref(TYPE): ref($topic) [eq "TYPE"]
626             * reftype / (TYPE): reftype($topic) [eq "TYPE"] (sees through blessing)
627             * isa(Class): blessed object derived from Class
628             * eq $var: $topic eq $var (string compare vs a runtime scalar) */
629 225 100         if (isALPHA(c) || c == '_') {
    50          
630             /* read a possibly package-qualified bareword (so a constant may be
631             * `Foo::BAR`); keyword names never contain '::' so they still match. */
632 81           SV *word = sd_lex_subname(aTHX);
633 81 50         const char *wp = word ? SvPV_nolen(word) : "";
634 81           int is_sub = strEQ(wp, "sub");
635 81           int is_undef = strEQ(wp, "undef");
636 81           int is_ref = strEQ(wp, "ref");
637 81           int is_reftype = strEQ(wp, "reftype");
638 81           int is_isa = strEQ(wp, "isa");
639 81           int is_eq = strEQ(wp, "eq");
640             /* Eagerly resolve the bareword as an inlinable constant while `word` is
641             * still alive. cv_const_sv returns the value owned by the (persistent)
642             * constant sub, so it stays valid after we release `word`. */
643 81 50         CV *cv = word ? get_cvn_flags(SvPVX(word), SvCUR(word), 0) : NULL;
644 81 100         SV *const_val = cv ? cv_const_sv(cv) : NULL;
645             char errbuf[128];
646 81           errbuf[0] = '\0';
647 81 50         if (word) {
648 81           my_strlcpy(errbuf, SvPV_nolen(word), sizeof(errbuf));
649 81           SvREFCNT_dec(word);
650             }
651             /* eq $var : string comparison against a runtime scalar. Honoured only
652             * when a '$' actually follows, so a bareword `eq` otherwise falls through
653             * to constant / error handling. (Its numeric sibling `== $var` is parsed
654             * above, as it does not begin with a word character.) */
655 81 100         if (is_eq) {
656 6           lex_read_space(0);
657 6 50         if (lex_peek_unichar(0) == '$') {
658             SDVar v;
659 6           sd_lex_scalar_var(aTHX_ &v);
660             /* defined($var) && $topic eq $var. An undef topic is guarded by
661             * the chain (undef_safe = 0), so a string variable matches
662             * exactly like a string literal. */
663 6           pat->undef_safe = 0;
664 6           return newLOGOP(OP_AND, 0,
665             newUNOP(OP_DEFINED, 0, sd_var_op(aTHX_ &v)),
666             sd_cmp(aTHX_ t, 0, OP_EQ, OP_SEQ, sd_var_op(aTHX_ &v)));
667             }
668             /* no '$' - fall through to constant / error handling */
669             }
670 75 100         if (is_undef) {
671 7           pat->is_undef = 1;
672 7           pat->undef_safe = 1;
673 7           return newUNOP(OP_NOT, 0,
674             newUNOP(OP_DEFINED, 0, sd_topic(aTHX_ t)));
675             }
676 68 100         if (is_ref) {
677             /* ref($topic) [eq "TYPE"] - pure ops, never warns. */
678 25           SV *type = sd_lex_paren_arg(aTHX);
679 25           pat->undef_safe = 1;
680 25 100         if (!type)
681 5           return newUNOP(OP_REF, 0, sd_topic(aTHX_ t));
682 20           return newBINOP(OP_SEQ, 0,
683             newUNOP(OP_REF, 0, sd_topic(aTHX_ t)),
684             newSVOP(OP_CONST, 0, type));
685             }
686 43 100         if (is_reftype) {
687             /* reftype($topic) [eq "TYPE"] - underlying type, blessing aside. */
688 11           SV *type = sd_lex_paren_arg(aTHX);
689 11           pat->undef_safe = 1;
690 11 100         if (!type)
691 3           return sd_reftype_op(aTHX_ t);
692 8           return newBINOP(OP_SEQ, 0, sd_reftype_op(aTHX_ t),
693             newSVOP(OP_CONST, 0, type));
694             }
695 32 100         if (is_isa) {
696 12           SV *klass = sd_lex_paren_arg(aTHX);
697 12 50         if (!klass)
698 0           croak("switch: isa requires a class: case isa(Class)");
699 12           pat->undef_safe = 1;
700 12           return sd_isa_call(aTHX_ t, klass);
701             }
702 20 100         if (is_sub) {
703             I32 floor;
704             OP *body, *anon;
705 13           lex_read_space(0);
706 13 100         if (lex_peek_unichar(0) != '{')
707 1           croak("switch: expected '{' after 'sub' in case predicate");
708 12           floor = start_subparse(FALSE, CVf_ANON);
709 12           body = parse_block(0);
710 12           anon = newANONATTRSUB(floor, NULL, NULL, body);
711 12           return sd_predicate_call(aTHX_ anon, t);
712             }
713 7 100         if (const_val) {
714             /* An inlinable constant (use constant FOO => ...) folds to its value
715             * and is classified just like the literal it holds: a number compiles
716             * to ==, anything with a string form to eq (dispatch-eligible). */
717 6 100         int cnum = (SvIOK(const_val) || SvNOK(const_val)) && !SvPOK(const_val);
    100          
    50          
718 6           OP *konst = newSVOP(OP_CONST, 0, newSVsv(const_val));
719 6 100         if (cnum) {
720 4           pat->undef_safe = 1;
721             } else {
722 2           pat->str_key = 1;
723 2           pat->key = newSVsv(const_val);
724             }
725 6           return sd_cmp(aTHX_ t, cnum, OP_EQ, OP_SEQ, konst);
726             }
727 1           croak("switch: unexpected bareword '%s' in case pattern (expected a number, "
728             "string, /regex/, [range or list], \\&name, sub {...}, a constant, "
729             "or == / eq $var)", errbuf);
730             }
731              
732             /* scalar literal: number -> ==, string -> eq */
733             {
734             int is_num;
735 144           OP *konst = sd_lex_literal(aTHX_ &is_num);
736 143 100         if (!is_num) {
737             /* exact string match: hash lookup is exactly eq semantics, so
738             * this arm is eligible for dispatch-table lowering. */
739 80           pat->str_key = 1;
740 80           pat->key = newSVsv(((SVOP *)konst)->op_sv);
741             } else {
742             /* numeric == is already looks_like_number-guarded: undef-safe. */
743 63           pat->undef_safe = 1;
744             }
745 143           return sd_cmp(aTHX_ t, is_num, OP_EQ, OP_SEQ, konst);
746             }
747             }
748              
749             /* True if any op in the tree introduces a lexical (my/our/local): such a block
750             * needs its own scope and must not be unwrapped. */
751 522           static int sd_has_intro(pTHX_ OP *o) {
752             OP *kid;
753 522 50         if (!o) return 0;
754 522 50         if (o->op_private & OPpLVAL_INTRO) return 1;
755 522 100         if (o->op_flags & OPf_KIDS) {
756 83 100         for (kid = cUNOPx(o)->op_first; kid; kid = OpSIBLING(kid))
    100          
757 56 50         if (sd_has_intro(aTHX_ kid)) return 1;
758             }
759 522           return 0;
760             }
761              
762             /* If `block` is a trivial `{ EXPR }` - a lineseq of exactly [nextstate, EXPR]
763             * with no lexical introductions - return the bare EXPR (freeing the wrapper)
764             * and set *simple. Such a branch carries no nextstate, so it is safe as a bare
765             * conditional arm and needs no enclosing scope. Otherwise return block as-is. */
766 476           static OP *sd_simplify_block(pTHX_ OP *block, int *simple) {
767 476           *simple = 0;
768 476 100         if (block->op_type == OP_LINESEQ) {
769 473           OP *first = cLISTOPx(block)->op_first;
770 473 50         if (first
771 473 50         && (first->op_type == OP_NEXTSTATE || first->op_type == OP_DBSTATE)
    0          
772 473 50         && OpSIBLING(first) && !OpSIBLING(OpSIBLING(first))
    50          
    50          
    100          
    50          
    50          
773 466 50         && !sd_has_intro(aTHX_ OpSIBLING(first))) {
    50          
774 466 50         OP *expr = OpSIBLING(first);
775             /* Lift EXPR out of the lineseq, leaving { nextstate } to be
776             * freed. Portable equivalent of
777             * op_sibling_splice(block, first, 1, NULL)
778             * which is not provided by core (or ppport.h) before 5.22.
779             * OpLASTSIB_set is backported by ppport.h to 5.14. */
780 466           OpLASTSIB_set(expr, NULL); /* detach EXPR: no parent, no sibling */
781 466           cLISTOPx(block)->op_last = first;
782 466           OpLASTSIB_set(first, block); /* nextstate is now the sole/last kid */
783 466           op_free(block);
784 466           *simple = 1;
785 466           return expr;
786             }
787             }
788 10           return block;
789             }
790              
791             /* Parse a whole `switch (EXPR) { ... }` construct (the lexer is positioned
792             * just after the `switch` keyword) and return its value-producing op tree. */
793             /* Parse -> PATTERN { BODY } for a case arm and return the block op with the
794             * destructured topic bound as lexicals visible inside BODY. The `->` has
795             * already been consumed. The bindings are prepended to BODY inside the block's
796             * own lexical scope (so each arm's bindings are private to that arm and vanish
797             * at the closing brace).
798             *
799             * A flat array pattern lowers to a single native `my (...) = @{$topic // []}`
800             * list-assignment - the same fast path the `let` keyword uses; hash, nested and
801             * default patterns capture the topic once into a hidden temp and bind per
802             * element via dd_emit(). */
803 9           static OP *sd_parse_bound_block(pTHX_ SDTopic *topic) {
804             dd_pat pat;
805             I32 floor;
806             OP *seq, *body, *blk, *lhs, *store;
807             PADOFFSET src;
808             I32 c;
809              
810 9           lex_read_space(0);
811 9           c = lex_peek_unichar(0);
812 9 100         if (c != '[' && c != '{')
    100          
813 1           croak("switch: expected '[' or '{' pattern after '->'");
814              
815 8           dd_parse_pattern(aTHX_ &pat);
816 8 50         if (pat.shape == DD_LIST) { /* not reachable via [ / { but be explicit */
817 0           dd_free_pat(aTHX_ &pat);
818 0           croak("switch: list patterns '(...)' are not allowed in a case binding");
819             }
820              
821 8           lex_read_space(0);
822 8 50         if (lex_peek_unichar(0) != '{') {
823 0           dd_free_pat(aTHX_ &pat);
824 0           croak("switch: expected '{' to open the case block after the '->' pattern");
825             }
826              
827             /* Open an outer block scope to hold the destructured lexicals so they are
828             * private to this arm (and vanish at its closing brace). The arm's own
829             * block is parsed inside it and its statements can see the bindings. */
830 8           floor = Perl_block_start(aTHX_ TRUE);
831              
832             /* The fast path derefs the topic as @{ // [] }. A constant topic
833             * would constant-fold to a symbolic deref (@{"str"}) and die at compile
834             * time under strict, so a constant scrutinee (which can never be an aref,
835             * and whose arm therefore never matches a [..] pattern) takes the general
836             * runtime-deref path instead. */
837 8 100         if (dd_is_listassign(&pat) && topic->kind != SDT_CONST) {
    100          
838             /* Fast path: my (LHS) = @{ // [] }; one native list-assignment. */
839 4           OP *llist = dd_listassign_lhs(aTHX_ &pat);
840 4           OP *rv = newUNOP(OP_RV2AV, 0,
841             newLOGOP(OP_DOR, 0, sd_topic(aTHX_ topic),
842             dd_empty_aref(aTHX)));
843 4           seq = newSTATEOP(0, NULL, newASSIGNOP(OPf_STACKED, llist, 0, rv));
844             }
845             else {
846             /* General path: my $src = ; then per-element binds. */
847 4           src = dd_temp(aTHX);
848 4           lhs = dd_padsv(aTHX_ src);
849 4           lhs->op_private |= OPpLVAL_INTRO;
850 4           store = newSTATEOP(0, NULL,
851             newASSIGNOP(OPf_STACKED, lhs, 0, sd_topic(aTHX_ topic)));
852 4           seq = store;
853 4           dd_emit(aTHX_ &pat, src, &seq);
854             }
855 8           dd_free_pat(aTHX_ &pat);
856              
857 8           body = parse_block(0); /* consumes the whole { ... } */
858 8           seq = op_append_list(OP_LINESEQ, seq, body);
859 8           blk = Perl_block_end(aTHX_ floor, seq);
860 8           return op_scope(blk);
861             }
862              
863 216           static OP *sd_parse_switch(pTHX) {
864             OP *scrutinee;
865             OP *conds[MAX_ARMS];
866             OP *blocks[MAX_ARMS];
867             SV *keys[MAX_ARMS]; /* string-literal key per arm, or NULL */
868             SV *vals[MAX_ARMS]; /* constant value per arm (borrowed), or NULL */
869 216           OP *default_block = NULL;
870 216           int narms = 0;
871             int i;
872             I32 c;
873 216           int all_simple = 1; /* every block is a bare-expression `{ EXPR }` */
874 216           int dispatchable = 1; /* every arm is (string key -> constant value) */
875             int topic_maybe_undef; /* scrutinee could be undef at run time */
876             SDTopic topic;
877             OP *assign;
878             OP *lhs;
879             OP *chain;
880             OP *seq;
881             OP *body;
882 216           OP *lln_prelude = NULL; /* `$lln = looks_like_number($topic)`, when hoisted */
883              
884             /* switch ( EXPR ) */
885 216           lex_read_space(0);
886 216 100         if (lex_peek_unichar(0) != '(')
887 1           croak("switch: expected '(' after 'switch'");
888 215           lex_read_unichar(0);
889 215           scrutinee = parse_fullexpr(0);
890 215           lex_read_space(0);
891 215 50         if (lex_peek_unichar(0) != ')')
892 0           croak("switch: expected ')' after switch expression");
893 215           lex_read_unichar(0);
894              
895             /* Decide how case tests will obtain the topic. A plain lexical or a
896             * constant scrutinee is side-effect-free to re-read, so each test reads it
897             * directly and the whole switch lowers to a bare conditional expression -
898             * no temp, no do-block - exactly like a hand-written if/elsif chain.
899             * Anything else (a call, an expression, a possibly-magical global) is
900             * stored once in a pad temp inside a value-returning block. */
901 215 100         if (scrutinee->op_type == OP_PADSV
902 45 50         && !(scrutinee->op_private & OPpLVAL_INTRO)) {
903 45           topic.kind = SDT_PAD;
904 45           topic.off = scrutinee->op_targ;
905 45           op_free(scrutinee);
906 45           scrutinee = NULL;
907             }
908 170 100         else if (scrutinee->op_type == OP_CONST) {
909 144           topic.kind = SDT_CONST;
910 144           topic.sv = newSVsv(((SVOP *)scrutinee)->op_sv);
911 144           op_free(scrutinee);
912 144           scrutinee = NULL;
913             }
914             else {
915             /* A unique pad-temp name per switch avoids "masks earlier
916             * declaration" warnings when switches share a lexical scope. */
917             static unsigned long sd_seq = 0;
918             char namebuf[64];
919 26           int n = my_snprintf(namebuf, sizeof(namebuf),
920             "$_Switch_Declare_topic_%lu", sd_seq++);
921 26           topic.kind = SDT_TEMP;
922 26           topic.off = pad_add_name_pvn(namebuf, (STRLEN)n, 0, NULL, NULL);
923             }
924              
925             /* A constant scrutinee whose value is defined can never be undef at run
926             * time, so its case tests need no undef guarding (and stay exactly as fast
927             * as before). Any other scrutinee might be undef. */
928 215 100         topic_maybe_undef = !(topic.kind == SDT_CONST && SvOK(topic.sv));
    50          
929              
930             /* Numeric guard sourcing: a defined constant topic folds looks_like_number
931             * at compile time; otherwise it is computed once into a pad temp and shared
932             * by every numeric arm (see the LLN_PAD prelude after the body is parsed). */
933 215           topic.lln_used = 0;
934 215 100         if (topic.kind == SDT_CONST && SvOK(topic.sv)) {
    50          
935 144           topic.lln_mode = LLN_CONST;
936 144           topic.lln_const = looks_like_number(topic.sv) ? 1 : 0;
937             } else {
938             static unsigned long sd_lln_seq = 0;
939             char lbuf[64];
940 71           int ln = my_snprintf(lbuf, sizeof(lbuf),
941             "$_Switch_Declare_lln_%lu", sd_lln_seq++);
942 71           topic.lln_mode = LLN_PAD;
943 71           topic.lln_off = pad_add_name_pvn(lbuf, (STRLEN)ln, 0, NULL, NULL);
944             }
945              
946             /* { ... } */
947 215           lex_read_space(0);
948 215 50         if (lex_peek_unichar(0) != '{')
949 0           croak("switch: expected '{' to open switch body");
950 215           lex_read_unichar(0);
951              
952 484           while (1) {
953             SV *kw;
954 699           lex_read_space(0);
955 699           c = lex_peek_unichar(0);
956 699 100         if (c == '}') { lex_read_unichar(0); break; }
957 499 50         if (c == -1) croak("switch: unexpected end of input in switch body");
958              
959 499           kw = sd_lex_read_ident(aTHX);
960 499 50         if (!kw) croak("switch: expected 'case' or 'default'");
961              
962 499 100         if (strEQ(SvPV_nolen(kw), "case")) {
963             OP *cond, *blk;
964             SDPat pat;
965             int simple;
966 300 100         if (default_block)
967 1           croak("switch: 'case' after 'default' is not allowed");
968 299 50         if (narms >= MAX_ARMS)
969 0           croak("switch: too many case arms");
970 299           lex_read_space(0);
971 299           cond = sd_parse_case_cond(aTHX_ &topic, &pat);
972             /* A value pattern that could match or warn on an undef topic
973             * (string eq / regex / list / range) is guarded with defined($topic)
974             * so undef can only be caught by an explicit `case undef` (or fall
975             * through to default). Patterns that are already undef-safe - numeric
976             * (looks_like_number-guarded), ref/reftype/isa, and undef itself -
977             * skip the guard. The shared default stays the single chain tail. */
978 289 100         if (topic_maybe_undef && !pat.undef_safe)
    100          
979 53           cond = newLOGOP(OP_AND, 0,
980             newUNOP(OP_DEFINED, 0, sd_topic(aTHX_ &topic)),
981             cond);
982 289           lex_read_space(0);
983             /* Optional `-> PATTERN` destructuring bind before the arm block. */
984 289 100         if (lex_peek_unichar(0) == '-' && PL_parser->bufptr[1] == '>') {
    50          
985 9           lex_read_unichar(0); /* - */
986 9           lex_read_unichar(0); /* > */
987 9           blk = sd_parse_bound_block(aTHX_ &topic);
988 8           simple = 0; /* a bound block always carries lexicals */
989             }
990             else {
991 280 100         if (lex_peek_unichar(0) != '{')
992 1           croak("switch: expected '{' after case pattern");
993 279           blk = sd_simplify_block(aTHX_ parse_block(0), &simple);
994             }
995 287           all_simple &= simple;
996 287           conds[narms] = cond;
997 287           blocks[narms] = blk;
998 287           keys[narms] = pat.key; /* NULL unless an exact string key */
999 574           vals[narms] = (blk->op_type == OP_CONST)
1000 287 100         ? ((SVOP *)blk)->op_sv : NULL;
1001             /* dispatchable iff string key AND constant-valued block */
1002 287 100         if (!pat.key || !vals[narms]) dispatchable = 0;
    100          
1003 287           narms++;
1004             }
1005 199 100         else if (strEQ(SvPV_nolen(kw), "default")) {
1006 198 100         if (default_block)
1007 1           croak("switch: multiple 'default' blocks");
1008 197           lex_read_space(0);
1009 197 50         if (lex_peek_unichar(0) != '{')
1010 0           croak("switch: expected '{' after 'default'");
1011             {
1012             int simple;
1013 197           default_block = sd_simplify_block(aTHX_ parse_block(0), &simple);
1014 197           all_simple &= simple;
1015             }
1016             }
1017             else {
1018 1           croak("switch: expected 'case' or 'default', got '%s'",
1019             SvPV_nolen(kw));
1020             }
1021 484           SvREFCNT_dec(kw);
1022             }
1023              
1024 200 100         if (narms == 0 && !default_block)
    100          
1025 1           croak("switch: empty switch body");
1026              
1027             /* Try the O(1) dispatch-table lowering: every arm maps a distinct string
1028             * literal to a constant value, and there are enough of them to beat a
1029             * linear eq chain. Build a compile-time constant hash and emit a single
1030             * lookup: exists $H{topic} ? $H{topic} : DEFAULT . */
1031 199           chain = NULL;
1032 199 100         if (dispatchable && narms >= SD_DISPATCH_MIN) {
    100          
1033             static unsigned long sd_dt_seq = 0;
1034             char hashname[64];
1035 9           int hn = my_snprintf(hashname, sizeof(hashname),
1036             "Switch::Declare::_dt%lu", sd_dt_seq++);
1037 9           GV *gv = gv_fetchpvn(hashname, (STRLEN)hn, GV_ADD, SVt_PVHV);
1038 9 50         HV *hv = GvHVn(gv);
1039 9           int dup = 0, any_undef = 0;
1040             /* If the topic could be undef, look it up under a guarded key so an
1041             * undef topic misses the table (-> default) instead of warning. The
1042             * sentinel is a binary string we treat as reserved; in the wildly
1043             * unlikely event a real key collides with it, fall back to the chain. */
1044 9           SV *sentinel = topic_maybe_undef
1045 9 100         ? newSVpvn("\1\0Switch::Declare::undef-key\0\1", 28) : NULL;
1046 44 100         for (i = 0; i < narms; i++) {
1047             STRLEN klen;
1048 36           const char *kpv = SvPV(keys[i], klen);
1049 36 100         if (hv_exists(hv, kpv, klen)) { dup = 1; break; }
1050 35 50         if (!SvOK(vals[i])) any_undef = 1;
1051 35           (void)hv_store(hv, kpv, klen, newSVsv(vals[i]), 0);
1052             }
1053 9 100         if (!dup && sentinel) {
    100          
1054             STRLEN sl;
1055 5           const char *sp = SvPV(sentinel, sl);
1056 5 50         if (hv_exists(hv, sp, sl)) dup = 1;
1057             }
1058 9 100         if (dup) {
1059 1           hv_clear(hv); /* duplicate keys: fall back to chain */
1060             } else {
1061 8           OP *deflt = default_block ? default_block
1062 8 100         : newOP(OP_UNDEF, 0);
1063 8 50         if (any_undef) {
1064             /* a value can be undef, so a miss is indistinguishable from a
1065             * hit by definedness: test membership explicitly. */
1066 0           OP *cond = newUNOP(OP_EXISTS, 0, sd_helem(aTHX_ gv, &topic, sentinel));
1067 0           chain = newCONDOP(0, cond, sd_helem(aTHX_ gv, &topic, sentinel), deflt);
1068             } else {
1069             /* all values are defined: one lookup, miss -> default via //. */
1070 8           chain = newLOGOP(OP_DOR, 0, sd_helem(aTHX_ gv, &topic, sentinel), deflt);
1071             }
1072             /* the unused per-arm condition and block ops are now dead */
1073 41 100         for (i = 0; i < narms; i++) { op_free(conds[i]); op_free(blocks[i]); }
1074             }
1075 9 100         if (sentinel) SvREFCNT_dec(sentinel);
1076             }
1077              
1078             /* Otherwise (or on fall-back), build the conditional chain right-to-left. */
1079 199 100         if (!chain) {
1080 191           chain = default_block ? default_block
1081 191 100         : newOP(OP_UNDEF, 0);
1082 444 100         for (i = narms - 1; i >= 0; i--)
1083 253           chain = newCONDOP(0, conds[i], blocks[i], chain);
1084             }
1085              
1086 485 100         for (i = 0; i < narms; i++)
1087 286 100         if (keys[i]) SvREFCNT_dec(keys[i]);
1088              
1089             /* If any numeric arm used the hoisted guard, build the one-time
1090             * `$lln = looks_like_number($topic)` that they all read. */
1091 199 100         if (topic.lln_mode == LLN_PAD && topic.lln_used) {
    100          
1092 19           OP *llhs = newOP(OP_PADSV, 0);
1093 19           llhs->op_targ = topic.lln_off;
1094 19           llhs->op_private |= OPpLVAL_INTRO; /* my */
1095 19           lln_prelude = newASSIGNOP(OPf_STACKED, llhs, 0,
1096             sd_looks_number_op(aTHX_ &topic));
1097             }
1098              
1099 199 100         if (topic.kind != SDT_TEMP) {
1100 174 100         if (topic.kind == SDT_CONST) SvREFCNT_dec(topic.sv);
1101 174 100         if (!lln_prelude && all_simple)
    100          
1102             /* Fastest path: a plain lexical/constant topic, and either a
1103             * dispatch lookup or a chain of bare `{ EXPR }` arms. The whole
1104             * switch is literally an expression - no temp, no scope, no
1105             * nextstate - as fast as hand-written code. */
1106 150           return chain;
1107 24 100         if (lln_prelude) {
1108             /* Hoisted numeric guard over a plain lexical: wrap in a block that
1109             * computes $lln once, then runs the chain (which reads $lln). */
1110 14           seq = op_append_list(OP_LINESEQ, newSTATEOP(0, NULL, lln_prelude),
1111             newSTATEOP(0, NULL, chain));
1112 14           seq->op_flags |= OPf_PARENS;
1113 14           return op_scope(seq);
1114             }
1115             /* Some arm is a multi-statement block (carries a nextstate). Wrap in a
1116             * single enter/leave (OPf_PARENS makes op_scope emit OP_LEAVE) so that
1117             * nextstate cannot reset the stack base of a surrounding expression. */
1118 10           chain->op_flags |= OPf_PARENS;
1119 10           return op_scope(chain);
1120             }
1121              
1122             /* General path: my $topic = SCRUTINEE; [my $lln = looks_like_number($topic);]
1123             * , wrapped as a value-returning block so the scrutinee is evaluated
1124             * exactly once. OPf_PARENS forces op_scope down its enter/leave path
1125             * (OP_LEAVE) for a proper stack frame; without it a bare OP_SCOPE lets the
1126             * inner nextstate reset the stack base and clobber a surrounding expression
1127             * (e.g. N + switch(...)). */
1128 25           lhs = newOP(OP_PADSV, 0);
1129 25           lhs->op_targ = topic.off;
1130 25           lhs->op_private |= OPpLVAL_INTRO; /* my */
1131 25           assign = newASSIGNOP(OPf_STACKED, lhs, 0, scrutinee);
1132 25           seq = newSTATEOP(0, NULL, assign);
1133 25 100         if (lln_prelude)
1134             /* $lln computed after $topic is stored, before the chain reads it. */
1135 5           seq = op_append_list(OP_LINESEQ, seq,
1136             newSTATEOP(0, NULL, lln_prelude));
1137 25           seq = op_append_list(OP_LINESEQ, seq, newSTATEOP(0, NULL, chain));
1138 25           seq->op_flags |= OPf_PARENS;
1139 25           body = op_scope(seq);
1140              
1141 25           return body;
1142             }
1143              
1144             /* True if the Switch::Declare lexical pragma is in scope at the current
1145             * point of compilation (set by import via $^H{'Switch::Declare'}). */
1146 219           static int sd_in_scope(pTHX) {
1147 219           HV *hints = GvHV(PL_hintgv);
1148             SV **ent;
1149 219 50         if (!hints) return 0;
1150 219           ent = hv_fetchs(hints, "Switch::Declare", 0);
1151 219 100         return ent && SvTRUE(*ent);
    50          
1152             }
1153              
1154 123690           static int sd_keyword_plugin(pTHX_ char *kw, STRLEN kwlen, OP **op_ptr) {
1155 123690 100         if (kwlen == 6 && memEQ(kw, "switch", 6) && sd_in_scope(aTHX)) {
    100          
    100          
1156 216           *op_ptr = sd_parse_switch(aTHX);
1157 199           return KEYWORD_PLUGIN_EXPR;
1158             }
1159 123474           return sd_next_keyword_plugin(aTHX_ kw, kwlen, op_ptr);
1160             }
1161              
1162             MODULE = Switch::Declare PACKAGE = Switch::Declare
1163             PROTOTYPES: DISABLE
1164              
1165             BOOT:
1166 23           sd_next_keyword_plugin = PL_keyword_plugin;
1167 23           PL_keyword_plugin = sd_keyword_plugin;
1168 23           XopENTRY_set(&sd_looks_number_xop, xop_name, "sd_looks_number");
1169 23           XopENTRY_set(&sd_looks_number_xop, xop_desc, "Switch::Declare numeric topic guard");
1170 23           XopENTRY_set(&sd_looks_number_xop, xop_class, OA_UNOP);
1171 23           Perl_custom_op_register(aTHX_ sd_pp_looks_number, &sd_looks_number_xop);
1172 23           XopENTRY_set(&sd_reftype_xop, xop_name, "sd_reftype");
1173 23           XopENTRY_set(&sd_reftype_xop, xop_desc, "Switch::Declare reftype()");
1174 23           XopENTRY_set(&sd_reftype_xop, xop_class, OA_UNOP);
1175 23           Perl_custom_op_register(aTHX_ sd_pp_reftype, &sd_reftype_xop);
1176 23           XopENTRY_set(&sd_rxmatch_xop, xop_name, "sd_rxmatch");
1177 23           XopENTRY_set(&sd_rxmatch_xop, xop_desc, "Switch::Declare =~ match");
1178 23           XopENTRY_set(&sd_rxmatch_xop, xop_class, OA_BINOP);
1179 23           Perl_custom_op_register(aTHX_ sd_pp_rxmatch, &sd_rxmatch_xop);
1180 23           XopENTRY_set(&dd_tail_xop, xop_name, "dd_tail");
1181 23           XopENTRY_set(&dd_tail_xop, xop_desc, "Switch::Declare bind slurpy tail");
1182 23           XopENTRY_set(&dd_tail_xop, xop_class, OA_BINOP);
1183 23           Perl_custom_op_register(aTHX_ dd_pp_tail, &dd_tail_xop);
1184 23           XopENTRY_set(&dd_hrest_xop, xop_name, "dd_hrest");
1185 23           XopENTRY_set(&dd_hrest_xop, xop_desc, "Switch::Declare bind hash %rest");
1186 23           XopENTRY_set(&dd_hrest_xop, xop_class, OA_LISTOP);
1187 23           Perl_custom_op_register(aTHX_ dd_pp_hrest, &dd_hrest_xop);
1188              
1189             bool
1190             _isa(obj, klass)
1191             SV *obj
1192             SV *klass
1193             CODE:
1194             /* fast @ISA check: a blessed object derived from `klass`. sv_isobject
1195             * keeps plain strings/non-objects from matching; never dies. */
1196 24 100         RETVAL = (sv_isobject(obj)
1197 12 100         && sv_derived_from(obj, SvPV_nolen(klass))) ? 1 : 0;
    100          
1198             OUTPUT:
1199             RETVAL