]> git.vpit.fr Git - perl/modules/Scope-Upper.git/blob - Upper.xs
Add more level words. Rename TOPLEVEL to TOP
[perl/modules/Scope-Upper.git] / Upper.xs
1 /* This file is part of the Scope::Upper Perl module.
2  * See http://search.cpan.org/dist/Scope-Upper/ */
3
4 #define PERL_NO_GET_CONTEXT
5 #include "EXTERN.h"
6 #include "perl.h" 
7 #include "XSUB.h"
8
9 #define __PACKAGE__ "Scope::Upper"
10
11 #ifndef SU_DEBUG
12 # define SU_DEBUG 0
13 #endif
14
15 /* --- Compatibility ------------------------------------------------------- */
16
17 #ifndef STMT_START
18 # define STMT_START do
19 #endif
20
21 #ifndef STMT_END
22 # define STMT_END while (0)
23 #endif
24
25 #if SU_DEBUG
26 # define SU_D(X) STMT_START X STMT_END
27 #else
28 # define SU_D(X)
29 #endif
30
31 #ifndef Newx
32 # define Newx(v, n, c) New(0, v, n, c)
33 #endif
34
35 #ifndef SvPV_const
36 # define SvPV_const(S, L) SvPV(S, L)
37 #endif
38
39 #ifndef SvPV_nolen_const
40 # define SvPV_nolen_const(S) SvPV_nolen(S)
41 #endif
42
43 #ifndef HvNAME_get
44 # define HvNAME_get(H) HvNAME(H)
45 #endif
46
47 #ifndef gv_fetchpvn_flags
48 # define gv_fetchpvn_flags(A, B, C, D) gv_fetchpv((A), (C), (D))
49 #endif
50
51 #ifndef PERL_MAGIC_tied
52 # define PERL_MAGIC_tied 'P'
53 #endif
54
55 #ifndef PERL_MAGIC_env
56 # define PERL_MAGIC_env 'E'
57 #endif
58
59 #ifndef NEGATIVE_INDICES_VAR
60 # define NEGATIVE_INDICES_VAR "NEGATIVE_INDICES"
61 #endif
62
63 #define SU_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
64
65 /* --- Stack manipulations ------------------------------------------------- */
66
67 #ifndef SvCANEXISTDELETE
68 # define SvCANEXISTDELETE(sv) \
69   (!SvRMAGICAL(sv)            \
70    || ((mg = mg_find((SV *) sv, PERL_MAGIC_tied))            \
71        && (stash = SvSTASH(SvRV(SvTIED_obj((SV *) sv, mg)))) \
72        && gv_fetchmethod_autoload(stash, "EXISTS", TRUE)     \
73        && gv_fetchmethod_autoload(stash, "DELETE", TRUE)     \
74       )                       \
75    )
76 #endif
77
78 /* ... Saving array elements ............................................... */
79
80 STATIC I32 su_av_key2idx(pTHX_ AV *av, I32 key) {
81 #define su_av_key2idx(A, K) su_av_key2idx(aTHX_ (A), (K))
82  I32 idx;
83
84  if (key >= 0)
85   return key;
86
87 /* Added by MJD in perl-5.8.1 with 6f12eb6d2a1dfaf441504d869b27d2e40ef4966a */
88 #if SU_HAS_PERL(5, 8, 1)
89  if (SvRMAGICAL(av)) {
90   const MAGIC * const tied_magic = mg_find((SV *) av, PERL_MAGIC_tied);
91   if (tied_magic) {
92    int adjust_index = 1;
93    SV * const * const negative_indices_glob =
94                     hv_fetch(SvSTASH(SvRV(SvTIED_obj((SV *) (av), tied_magic))),
95                              NEGATIVE_INDICES_VAR, 16, 0);
96    if (negative_indices_glob && SvTRUE(GvSV(*negative_indices_glob)))
97     return key;
98   }
99  }
100 #endif
101
102  idx = key + av_len(av) + 1;
103  if (idx < 0)
104   return key;
105
106  return idx;
107 }
108
109 #ifndef SAVEADELETE
110
111 typedef struct {
112  AV *av;
113  I32 idx;
114 } su_ud_adelete;
115
116 STATIC void su_adelete(pTHX_ void *ud_) {
117  su_ud_adelete *ud = ud_;
118
119  av_delete(ud->av, ud->idx, G_DISCARD);
120  SvREFCNT_dec(ud->av);
121
122  Safefree(ud);
123 }
124
125 STATIC void su_save_adelete(pTHX_ AV *av, I32 idx) {
126 #define su_save_adelete(A, K) su_save_adelete(aTHX_ (A), (K))
127  su_ud_adelete *ud;
128
129  Newx(ud, 1, su_ud_adelete);
130  ud->av  = av;
131  ud->idx = idx;
132  SvREFCNT_inc(av);
133
134  SAVEDESTRUCTOR_X(su_adelete, ud);
135 }
136
137 #define SAVEADELETE(A, K) su_save_adelete((A), (K))
138
139 #endif /* SAVEADELETE */
140
141 STATIC void su_save_aelem(pTHX_ AV *av, SV *key, SV *val) {
142 #define su_save_aelem(A, K, V) su_save_aelem(aTHX_ (A), (K), (V))
143  I32 idx;
144  I32 preeminent = 1;
145  SV **svp;
146  HV *stash;
147  MAGIC *mg;
148
149  idx = su_av_key2idx(av, SvIV(key));
150
151  if (SvCANEXISTDELETE(av))
152   preeminent = av_exists(av, idx);
153
154  svp = av_fetch(av, idx, 1);
155  if (!svp || *svp == &PL_sv_undef) croak(PL_no_aelem, idx);
156
157  if (preeminent)
158   save_aelem(av, idx, svp);
159  else
160   SAVEADELETE(av, idx);
161
162  if (val) { /* local $x[$idx] = $val; */
163   SvSetMagicSV(*svp, val);
164  } else {   /* local $x[$idx]; delete $x[$idx]; */
165   av_delete(av, idx, G_DISCARD);
166  }
167 }
168
169 /* ... Saving hash elements ................................................ */
170
171 STATIC void su_save_helem(pTHX_ HV *hv, SV *keysv, SV *val) {
172 #define su_save_helem(H, K, V) su_save_helem(aTHX_ (H), (K), (V))
173  I32 preeminent = 1;
174  HE *he;
175  SV **svp;
176  HV *stash;
177  MAGIC *mg;
178
179  if (SvCANEXISTDELETE(hv) || mg_find((SV *) hv, PERL_MAGIC_env))
180   preeminent = hv_exists_ent(hv, keysv, 0);
181
182  he  = hv_fetch_ent(hv, keysv, 1, 0);
183  svp = he ? &HeVAL(he) : NULL;
184  if (!svp || *svp == &PL_sv_undef) croak("Modification of non-creatable hash value attempted, subscript \"%s\"", SvPV_nolen_const(*svp));
185
186  if (HvNAME_get(hv) && isGV(*svp)) {
187   save_gp((GV *) *svp, 0);
188   return;
189  }
190
191  if (preeminent)
192   save_helem(hv, keysv, svp);
193  else {
194   STRLEN keylen;
195   const char * const key = SvPV_const(keysv, keylen);
196   SAVEDELETE(hv, savepvn(key, keylen),
197                  SvUTF8(keysv) ? -(I32)keylen : (I32)keylen);
198  }
199
200  if (val) { /* local $x{$keysv} = $val; */
201   SvSetMagicSV(*svp, val);
202  } else {   /* local $x{$keysv}; delete $x{$keysv}; */
203   hv_delete_ent(hv, keysv, G_DISCARD, HeHASH(he));
204  }
205 }
206
207 /* --- Actions ------------------------------------------------------------- */
208
209 typedef struct {
210  I32 depth;
211  I32 *origin;
212  void (*handler)(pTHX_ void *);
213 } su_ud_common;
214
215 #define SU_UD_DEPTH(U)   (((su_ud_common *) (U))->depth)
216 #define SU_UD_ORIGIN(U)  (((su_ud_common *) (U))->origin)
217 #define SU_UD_HANDLER(U) (((su_ud_common *) (U))->handler)
218
219 #define SU_UD_FREE(U) STMT_START { \
220  if (SU_UD_ORIGIN(U)) Safefree(SU_UD_ORIGIN(U)); \
221  Safefree(U); \
222 } STMT_END
223
224 /* ... Reap ................................................................ */
225
226 typedef struct {
227  su_ud_common ci;
228  SV *cb;
229 } su_ud_reap;
230
231 STATIC void su_call(pTHX_ void *ud_) {
232  su_ud_reap *ud = (su_ud_reap *) ud_;
233 #if SU_HAS_PERL(5, 10, 0)
234  I32 dieing = PL_op->op_type == OP_DIE;
235 #endif
236
237  dSP;
238
239  SU_D(PerlIO_printf(Perl_debug_log, "%p: @@@ call at %d (save is %d)\n",
240                                      ud, PL_scopestack_ix, PL_savestack_ix));
241  ENTER;
242  SAVETMPS;
243
244  PUSHMARK(SP);
245  PUTBACK;
246
247  /* If cxstack_ix isn't incremented there, the eval context will be overwritten
248   * when the new sub scope will be created in call_sv. */
249
250 #if SU_HAS_PERL(5, 10, 0)
251  if (dieing)
252   if (cxstack_ix < cxstack_max)
253    ++cxstack_ix;
254   else
255    cxstack_ix = Perl_cxinc(aTHX);
256 #endif
257
258  call_sv(ud->cb, G_VOID);
259
260 #if SU_HAS_PERL(5, 10, 0)
261  if (dieing && cxstack_ix > 0)
262   --cxstack_ix;
263 #endif
264
265  SPAGAIN;
266  PUTBACK;
267
268  FREETMPS;
269  LEAVE;
270
271  SvREFCNT_dec(ud->cb);
272  SU_UD_FREE(ud);
273 }
274
275 STATIC void su_reap(pTHX_ void *ud) {
276 #define su_reap(U) su_reap(aTHX_ (U))
277  SU_D(PerlIO_printf(Perl_debug_log, "%p: === reap at %d (save is %d)\n",
278                                      ud, PL_scopestack_ix, PL_savestack_ix));
279  SAVEDESTRUCTOR_X(su_call, ud);
280  SU_D(PerlIO_printf(Perl_debug_log, "%p: savestack is now at %d, base at %d\n",
281                                      ud, PL_savestack_ix,
282                                          PL_scopestack[PL_scopestack_ix]));
283 }
284
285 /* ... Localize & localize array/hash element .............................. */
286
287 typedef struct {
288  su_ud_common ci;
289  SV *sv;
290  SV *val;
291  SV *elem;
292 } su_ud_localize;
293
294 STATIC void su_localize(pTHX_ void *ud_) {
295 #define su_localize(U) su_localize(aTHX_ (U))
296  su_ud_localize *ud = (su_ud_localize *) ud_;
297  SV *sv   = ud->sv;
298  SV *val  = ud->val;
299  SV *elem = ud->elem;
300  GV *gv;
301  UV deref = 0;
302  svtype t = SVt_NULL;
303
304  if (SvTYPE(sv) >= SVt_PVGV) {
305   gv = (GV *) sv;
306   if (!val) {               /* local *x; */
307    t = SVt_PVGV;
308   } else if (!SvROK(val)) { /* local *x = $val; */
309    goto assign;
310   } else {                  /* local *x = \$val; */
311    t = SvTYPE(SvRV(val));
312    deref = 1;
313   }
314  } else {
315   STRLEN len, l;
316   const char *p = SvPV_const(sv, len), *s;
317   for (s = p, l = len; l > 0 && isSPACE(*s); ++s, --l) { }
318   if (!l) {
319    l = len;
320    s = p;
321   }
322   switch (*s) {
323    case '$': t = SVt_PV;   break;
324    case '@': t = SVt_PVAV; break;
325    case '%': t = SVt_PVHV; break;
326    case '&': t = SVt_PVCV; break;
327    case '*': t = SVt_PVGV; break;
328   }
329   if (t != SVt_NULL) {
330    ++s;
331    --l;
332   } else if (val) { /* t == SVt_NULL, type can't be inferred from the sigil */
333    if (SvROK(val) && !sv_isobject(val)) {
334     t = SvTYPE(SvRV(val));
335     deref = 1;
336    } else {
337     t = SvTYPE(val);
338    }
339   }
340   gv = gv_fetchpvn_flags(s, l, GV_ADDMULTI, SVt_PVGV);
341  }
342
343  SU_D({
344   SV *z = newSV_type(t);
345   PerlIO_printf(Perl_debug_log, "%p: === localize a %s at %d (save is %d)\n",
346                                  ud, sv_reftype(z, 0),
347                                      PL_scopestack_ix, PL_savestack_ix);
348   SvREFCNT_dec(z);
349  });
350
351  /* Inspired from Alias.pm */
352  switch (t) {
353   case SVt_PVAV:
354    if (elem) {
355     su_save_aelem(GvAV(gv), elem, val);
356     goto done;
357    } else
358     save_ary(gv);
359    break;
360   case SVt_PVHV:
361    if (elem) {
362     su_save_helem(GvHV(gv), elem, val);
363     goto done;
364    } else
365     save_hash(gv);
366    break;
367   case SVt_PVGV:
368    save_gp(gv, 1); /* hide previous entry in symtab */
369    break;
370   case SVt_PVCV:
371    SAVESPTR(GvCV(gv));
372    GvCV(gv) = NULL;
373    break;
374   default:
375    gv = (GV *) save_scalar(gv);
376 maybe_deref:
377    if (deref) /* val != NULL */
378     val = SvRV(val);
379    break;
380  }
381
382  SU_D(PerlIO_printf(Perl_debug_log, "%p: savestack is now at %d, base at %d\n",
383                                      ud, PL_savestack_ix,
384                                          PL_scopestack[PL_scopestack_ix]));
385
386 assign:
387  if (val)
388   SvSetMagicSV((SV *) gv, val);
389
390 done:
391  SvREFCNT_dec(ud->elem);
392  SvREFCNT_dec(ud->val);
393  SvREFCNT_dec(ud->sv);
394  SU_UD_FREE(ud);
395 }
396
397 /* --- Pop a context back -------------------------------------------------- */
398
399 #if SU_DEBUG
400 # ifdef DEBUGGING
401 #  define SU_CXNAME PL_block_type[CxTYPE(&cxstack[cxstack_ix])]
402 # else
403 #  define SU_CXNAME "XXX"
404 # endif
405 #endif
406
407 STATIC void su_pop(pTHX_ void *ud) {
408 #define su_pop(U) su_pop(aTHX_ (U))
409  I32 depth, base, mark, *origin;
410  depth = SU_UD_DEPTH(ud);
411
412  SU_D(PerlIO_printf(Perl_debug_log, "%p: --- pop %s at %d from %d to %d [%d]\n",
413                                      ud, SU_CXNAME,
414                                          PL_scopestack_ix, PL_savestack_ix,
415                                          PL_scopestack[PL_scopestack_ix],
416                                          depth));
417
418  origin = SU_UD_ORIGIN(ud);
419  mark   = origin[depth];
420  base   = origin[depth - 1];
421
422  SU_D(PerlIO_printf(Perl_debug_log, "%p: clean from %d down to %d\n",
423                                      ud, mark, base));
424
425  if (base < mark) {
426   PL_savestack_ix = mark;
427   leave_scope(base);
428  }
429  PL_savestack_ix = base;
430  if (--depth > 0) {
431   SU_UD_DEPTH(ud) = depth;
432   SU_D(PerlIO_printf(Perl_debug_log, "%p: save new destructor at %d [%d]\n",
433                                       ud, PL_savestack_ix, depth));
434   SAVEDESTRUCTOR_X(su_pop, ud);
435   SU_D(PerlIO_printf(Perl_debug_log, "%p: pop end at at %d [%d]\n",
436                                       ud, PL_savestack_ix, depth));
437  } else {
438   SU_UD_HANDLER(ud)(aTHX_ ud);
439  }
440 }
441
442 /* --- Initialize the stack and the action userdata ------------------------ */
443
444 STATIC I32 su_init(pTHX_ I32 level, void *ud, I32 size) {
445 #define su_init(L, U, S) su_init(aTHX_ (L), (U), (S))
446  I32 i, depth = 0, *origin;
447  I32 cur, last, step;
448
449  LEAVE;
450
451  if (level <= 0) {
452   SU_UD_HANDLER(ud)(aTHX_ ud);
453   goto done;
454  }
455
456  SU_D(PerlIO_printf(Perl_debug_log, "%p: ### init for level %d\n", ud, level));
457
458  for (i = 0; i < level; ++i) {
459   PERL_CONTEXT *cx = &cxstack[cxstack_ix - i];
460   switch (CxTYPE(cx)) {
461 #if SU_HAS_PERL(5, 11, 0)
462    case CXt_LOOP_FOR:
463    case CXt_LOOP_PLAIN:
464    case CXt_LOOP_LAZYSV:
465    case CXt_LOOP_LAZYIV:
466 #else
467    case CXt_LOOP:
468 #endif
469     SU_D(PerlIO_printf(Perl_debug_log, "%p: cx %d is loop\n", ud, i));
470     depth += 2;
471     break;
472    default:
473     SU_D(PerlIO_printf(Perl_debug_log, "%p: cx %d is normal\n", ud, i));
474     depth++;
475     break;
476   }
477  }
478  SU_D(PerlIO_printf(Perl_debug_log, "%p: depth is %d\n", ud, depth));
479
480  Newx(origin, depth + 1, I32);
481  origin[0] = PL_scopestack[PL_scopestack_ix - depth];
482  PL_scopestack[PL_scopestack_ix - depth] += size;
483  for (i = depth - 1; i >= 1; --i) {
484   I32 j = PL_scopestack_ix - i;
485   origin[depth - i] = PL_scopestack[j];
486   PL_scopestack[j] += 3;
487  }
488  origin[depth] = PL_savestack_ix;
489
490  SU_D({
491   PerlIO_printf(Perl_debug_log, "%p: d=%d s=%d x=%d c=%d o=%d\n", ud,
492                 depth, 0, PL_scopestack_ix - 1, PL_savestack_ix, origin[depth]);
493   for (i = depth - 1; i >= 0; --i) {
494    I32 x = PL_scopestack_ix  - depth + i;
495    PerlIO_printf(Perl_debug_log, "%p: d=%d s=%d x=%d c=%d o=%d\n", ud,
496                                   i, depth - i, x, PL_scopestack[x], origin[i]);
497   }
498  });
499
500  SU_UD_ORIGIN(ud) = origin;
501  SU_UD_DEPTH(ud)  = depth;
502
503  SU_D(PerlIO_printf(Perl_debug_log, "%p: set original destructor at %d [%d]\n",
504                                      ud, PL_savestack_ix, depth));
505
506  SAVEDESTRUCTOR_X(su_pop, ud);
507
508 done:
509  ENTER;
510
511  return depth;
512 }
513
514 #define SU_GET_LEVEL(A)  \
515  if (items > A) {        \
516   SV *lsv = ST(A);       \
517   if (SvOK(lsv))         \
518    level = SvUV(lsv);    \
519   if (level < 0)         \
520    XSRETURN(0);          \
521  }                       \
522  if (level > cxstack_ix) \
523   level = cxstack_ix;
524
525 #define SU_DOPOPTOCX(t)                    \
526  STMT_START {                              \
527   I32 i, cxix = cxstack_ix, from = 0;      \
528   if (items)                               \
529    from = SvIV(ST(0));                     \
530   for (i = cxix - from; i >= 0; --i) {     \
531    if (CxTYPE(&cxstack[i]) == t) {         \
532     ST(0) = sv_2mortal(newSViv(cxix - i)); \
533     XSRETURN(1);                           \
534    }                                       \
535   }                                        \
536   XSRETURN_UNDEF;                          \
537  } STMT_END
538
539 /* --- XS ------------------------------------------------------------------ */
540
541 MODULE = Scope::Upper            PACKAGE = Scope::Upper
542
543 PROTOTYPES: ENABLE
544
545 BOOT:
546 {
547  HV *stash = gv_stashpv(__PACKAGE__, 1);
548  newCONSTSUB(stash, "CURRENT", newSViv(0));
549 }
550
551 SV *
552 TOP()
553 PROTOTYPE:
554 CODE:
555  RETVAL = newSViv(cxstack_ix);
556 OUTPUT:
557  RETVAL
558
559 SV *
560 UP(...)
561 PROTOTYPE: ;$
562 PREINIT:
563  I32 i = 0;
564  I32 cxix = cxstack_ix;
565 CODE:
566  if (items)
567   i = SvIV(ST(0));
568  if (++i > cxix)
569   i = cxix;
570  RETVAL = newSViv(i);
571 OUTPUT:
572  RETVAL
573
574 SV *
575 DOWN(...)
576 PROTOTYPE: ;$
577 PREINIT:
578  I32 i = 0;
579 CODE:
580  if (items)
581   i = SvIV(ST(0));
582  if (--i < 0)
583   i = 0;
584  RETVAL = newSViv(i);
585 OUTPUT:
586  RETVAL
587
588 void
589 SUB(...)
590 PROTOTYPE: ;$
591 PPCODE:
592  SU_DOPOPTOCX(CXt_SUB);
593
594 void
595 EVAL(...)
596 PROTOTYPE: ;$
597 PPCODE:
598  SU_DOPOPTOCX(CXt_EVAL);
599
600 void
601 reap(SV *hook, ...)
602 PROTOTYPE: &;$
603 PREINIT:
604  I32 level = 0;
605  su_ud_reap *ud;
606 CODE:
607  SU_GET_LEVEL(1);
608  Newx(ud, 1, su_ud_reap);
609  SU_UD_ORIGIN(ud)  = NULL;
610  SU_UD_HANDLER(ud) = su_reap;
611  ud->cb = newSVsv(hook);
612  su_init(level, ud, 3);
613
614 void
615 localize(SV *sv, SV *val, ...)
616 PROTOTYPE: $$;$
617 PREINIT:
618  I32 level = 0;
619  su_ud_localize *ud;
620 CODE:
621  SU_GET_LEVEL(2);
622  Newx(ud, 1, su_ud_localize);
623  SU_UD_ORIGIN(ud)  = NULL;
624  SU_UD_HANDLER(ud) = su_localize;
625  SvREFCNT_inc(sv);
626  ud->sv   = sv;
627  ud->val  = newSVsv(val);
628  ud->elem = NULL;
629  su_init(level, ud, 3);
630
631 void
632 localize_elem(SV *sv, SV *elem, SV *val, ...)
633 PROTOTYPE: $$$;$
634 PREINIT:
635  I32 level = 0;
636  su_ud_localize *ud;
637 CODE:
638  SU_GET_LEVEL(3);
639  Newx(ud, 1, su_ud_localize);
640  SU_UD_ORIGIN(ud)  = NULL;
641  SU_UD_HANDLER(ud) = su_localize;
642  SvREFCNT_inc(sv);
643  ud->sv   = sv;
644  ud->val  = newSVsv(val);
645  SvREFCNT_inc(elem);
646  ud->elem = elem;
647  su_init(level, ud, 4);
648
649 void
650 localize_delete(SV *sv, SV *elem, ...)
651 PROTOTYPE: $$;$
652 PREINIT:
653  I32 level = 0;
654  su_ud_localize *ud;
655 CODE:
656  SU_GET_LEVEL(2);
657  Newx(ud, 1, su_ud_localize);
658  SU_UD_ORIGIN(ud)  = NULL;
659  SU_UD_HANDLER(ud) = su_localize;
660  SvREFCNT_inc(sv);
661  ud->sv   = sv;
662  ud->val  = NULL;
663  SvREFCNT_inc(elem);
664  ud->elem = elem;
665  su_init(level, ud, 4);