File Coverage

Declare.xs
Criterion Covered Total %
statement 438 460 95.2
branch 286 356 80.3
condition n/a
subroutine n/a
pod n/a
total 724 816 88.7


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