]> git.vpit.fr Git - perl/modules/autovivification.git/blobdiff - autovivification.xs
Handle array and hash slices
[perl/modules/autovivification.git] / autovivification.xs
index 82fb2e680463a5039b798e4d129fca8424d3c3cc..ae8db121e2527d6c57bfdc0b0511111068ecb857 100644 (file)
@@ -409,7 +409,7 @@ STATIC OP *a_pp_rv2av(pTHX) {
 
 /* ... pp_rv2hv ............................................................ */
 
-STATIC OP *a_pp_rv2hv(pTHX) {
+STATIC OP *a_pp_rv2hv_simple(pTHX) {
  a_op_info oi;
  UV flags;
  dSP;
@@ -427,6 +427,29 @@ STATIC OP *a_pp_rv2hv(pTHX) {
  return CALL_FPTR(oi.old_pp)(aTHX);
 }
 
+STATIC OP *a_pp_rv2hv(pTHX) {
+ a_op_info oi;
+ UV flags;
+ dSP;
+
+ a_map_fetch(PL_op, &oi);
+ flags = oi.flags;
+
+ if (flags & A_HINT_DEREF) {
+  if (!SvOK(TOPs)) {
+   SV *hv;
+   POPs;
+   hv = sv_2mortal((SV *) newHV());
+   PUSHs(hv);
+   RETURN;
+  }
+ } else {
+  PL_op->op_ppaddr = oi.old_pp;
+ }
+
+ return CALL_FPTR(oi.old_pp)(aTHX);
+}
+
 /* ... pp_deref (aelem,helem,rv2sv,padsv) .................................. */
 
 STATIC OP *a_pp_deref(pTHX) {
@@ -519,6 +542,20 @@ STATIC OP *a_pp_root_binop(pTHX) {
 
 /* --- Check functions ----------------------------------------------------- */
 
+STATIC void a_recheck_rv2xv(pTHX_ OP *o, OPCODE type, OP *(*new_pp)(pTHX)) {
+#define a_recheck_rv2xv(O, T, PP) a_recheck_rv2xv(aTHX_ (O), (T), (PP))
+ a_op_info oi;
+
+ if (o->op_type == type && o->op_ppaddr != new_pp
+                        && cUNOPo->op_first->op_type != OP_GV
+                        && a_map_fetch(o, &oi)) {
+  a_map_store(o, o->op_ppaddr, oi.next, oi.flags);
+  o->op_ppaddr = new_pp;
+ }
+
+ return;
+}
+
 /* ... ck_pad{any,sv} ...................................................... */
 
 /* Sadly, the PADSV OPs we are interested in don't trigger the padsv check
@@ -606,29 +643,13 @@ STATIC OP *a_ck_deref(pTHX_ OP *o) {
  switch (o->op_type) {
   case OP_AELEM:
    old_ck = a_old_ck_aelem;
-   if ((hint & A_HINT_DO) && !(hint & A_HINT_STRICT)) {
-    OP *kid = cUNOPo->op_first;
-    a_op_info oi;
-    if (kid->op_type == OP_RV2AV && kid->op_ppaddr != a_pp_rv2av
-                                 && kUNOP->op_first->op_type != OP_GV
-                                 && a_map_fetch(kid, &oi)) {
-     a_map_store(kid, kid->op_ppaddr, o, hint);
-     kid->op_ppaddr = a_pp_rv2av;
-    }
-   }
+   if ((hint & A_HINT_DO) && !(hint & A_HINT_STRICT))
+    a_recheck_rv2xv(cUNOPo->op_first, OP_RV2AV, a_pp_rv2av);
    break;
   case OP_HELEM:
    old_ck = a_old_ck_helem;
-   if ((hint & A_HINT_DO) && !(hint & A_HINT_STRICT)) {
-    OP *kid = cUNOPo->op_first;
-    a_op_info oi;
-    if (kid->op_type == OP_RV2HV && kid->op_ppaddr != a_pp_rv2hv
-                                 && kUNOP->op_first->op_type != OP_GV
-                                 && a_map_fetch(kid, &oi)) {
-     a_map_store(kid, kid->op_ppaddr, o, hint);
-     kid->op_ppaddr = a_pp_rv2hv;
-    }
-   }
+   if ((hint & A_HINT_DO) && !(hint & A_HINT_STRICT))
+    a_recheck_rv2xv(cUNOPo->op_first, OP_RV2HV, a_pp_rv2hv_simple);
    break;
   case OP_RV2SV:
    old_ck = a_old_ck_rv2sv;
@@ -662,7 +683,7 @@ STATIC OP *a_ck_rv2xv(pTHX_ OP *o) {
 
  switch (o->op_type) {
   case OP_RV2AV: old_ck = a_old_ck_rv2av; new_pp = a_pp_rv2av; break;
-  case OP_RV2HV: old_ck = a_old_ck_rv2hv; new_pp = a_pp_rv2hv; break;
+  case OP_RV2HV: old_ck = a_old_ck_rv2hv; new_pp = a_pp_rv2hv_simple; break;
  }
  o = CALL_FPTR(old_ck)(aTHX_ o);
 
@@ -679,6 +700,40 @@ STATIC OP *a_ck_rv2xv(pTHX_ OP *o) {
  return o;
 }
 
+/* ... ck_xslice (aslice,hslice) ........................................... */
+
+/* I think those are only found at the root, but there's nothing that really
+ * prevent them to be inside the expression too. We only need to update the
+ * root so that the rest of the expression will see the right context when
+ * resolving. That's why we don't replace the ppaddr. */
+
+STATIC OP *(*a_old_ck_aslice)(pTHX_ OP *) = 0;
+STATIC OP *(*a_old_ck_hslice)(pTHX_ OP *) = 0;
+
+STATIC OP *a_ck_xslice(pTHX_ OP *o) {
+ OP * (*old_ck)(pTHX_ OP *o) = 0;
+ UV hint = a_hint();
+
+ switch (o->op_type) {
+  case OP_ASLICE:
+   old_ck = a_old_ck_aslice;
+   break;
+  case OP_HSLICE:
+   old_ck = a_old_ck_hslice;
+   if (hint & A_HINT_DO)
+    a_recheck_rv2xv(cUNOPo->op_first->op_sibling, OP_RV2HV, a_pp_rv2hv);
+   break;
+ }
+ o = CALL_FPTR(old_ck)(aTHX_ o);
+
+ if (hint & A_HINT_DO) {
+  a_map_store_root(o, 0, hint);
+ } else
+  a_map_delete(o);
+
+ return o;
+}
+
 /* ... ck_root (exists,delete,keys,values) ................................. */
 
 /* Those ops are only found at the root of a dereferencing expression. We can
@@ -770,6 +825,11 @@ BOOT:
   a_old_ck_rv2hv      = PL_check[OP_RV2HV];
   PL_check[OP_RV2HV]  = MEMBER_TO_FPTR(a_ck_rv2xv);
 
+  a_old_ck_aslice     = PL_check[OP_ASLICE];
+  PL_check[OP_ASLICE] = MEMBER_TO_FPTR(a_ck_xslice);
+  a_old_ck_hslice     = PL_check[OP_HSLICE];
+  PL_check[OP_HSLICE] = MEMBER_TO_FPTR(a_ck_xslice);
+
   a_old_ck_exists     = PL_check[OP_EXISTS];
   PL_check[OP_EXISTS] = MEMBER_TO_FPTR(a_ck_root);
   a_old_ck_delete     = PL_check[OP_DELETE];