File Coverage

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