Merge branch 'master' into metadata
[p5sagit/Function-Parameters.git] / Parameters.xs
index 542b078..f2ac0da 100644 (file)
@@ -147,39 +147,6 @@ static SV *sentinel_mortalize(Sentinel sen, SV *sv) {
        return sv;
 }
 
-static void my_safefree(void *p) {
-       Safefree(p);
-}
-
-#define SENTINEL_ALLOC(SEN, P, N, T) STMT_START { \
-       Newx(P, N, T); \
-       sentinel_register(SEN, P, my_safefree); \
-} STMT_END
-
-#define SENTINEL_MDUP(SEN, P, O, N, T) STMT_START { \
-       void *const _sentinel_mdup_tmp_ = (P); \
-       SENTINEL_ALLOC(SEN, P, N, T); \
-       memcpy(P, _sentinel_mdup_tmp_, O * sizeof (T)); \
-} STMT_END
-
-#define SENTINEL_REALLOC(SEN, P, N, T) STMT_START { \
-       assert((N) > 0); \
-       if (!(P)) { \
-               SENTINEL_ALLOC(SEN, P, N, T); \
-       } else { \
-               Resource **_sentinel_realloc_tmp_ = (SEN); \
-               for (;;) { \
-                       assert(*_sentinel_realloc_tmp_ != NULL); \
-                       if ((*_sentinel_realloc_tmp_)->data == (P)) { \
-                               Renew((*_sentinel_realloc_tmp_)->data, N, T); \
-                               (P) = (*_sentinel_realloc_tmp_)->data; \
-                               break; \
-                       } \
-                       _sentinel_realloc_tmp_ = &(*_sentinel_realloc_tmp_)->next; \
-               } \
-       } \
-} STMT_END
-
 static int kw_flags(pTHX_ Sentinel sen, const char *kw_ptr, STRLEN kw_len, KWSpec *spec) {
        HV *hints;
        SV *sv, **psv;
@@ -268,7 +235,7 @@ enum {
 
 static void my_sv_cat_c(pTHX_ SV *sv, U32 c) {
        char ds[UTF8_MAXBYTES + 1], *d;
-       d = uvchr_to_utf8(ds, c);
+       d = (char *)uvchr_to_utf8((U8 *)ds, c);
        if (d - ds > 1) {
                sv_utf8_upgrade(sv);
        }
@@ -786,6 +753,123 @@ static OP *mkconstpv(pTHX_ const char *p, size_t n) {
 
 #define mkconstpvs(S) mkconstpv(aTHX_ "" S "", sizeof S - 1)
 
+static void register_info(pTHX_ UV key, SV *declarator, const KWSpec *kws, const ParamSpec *ps) {
+       dSP;
+
+       ENTER;
+       SAVETMPS;
+
+       PUSHMARK(SP);
+       EXTEND(SP, 8);
+
+       /* 0 */ {
+               mPUSHu(key);
+       }
+       /* 1 */ {
+               size_t n;
+               char *p = SvPV(declarator, n);
+               char *q = memchr(p, ' ', n);
+               mPUSHp(p, q ? (size_t)(q - p) : n);
+       }
+       if (!ps) {
+               if (SvTRUE(kws->shift)) {
+                       PUSHs(kws->shift);
+               } else {
+                       PUSHmortal;
+               }
+               mPUSHs(newRV_noinc((SV *)newAV()));
+               mPUSHs(newRV_noinc((SV *)newAV()));
+               mPUSHs(newRV_noinc((SV *)newAV()));
+               mPUSHs(newRV_noinc((SV *)newAV()));
+               mPUSHp("@_", 2);
+       } else {
+               /* 2 */ {
+                       if (ps->invocant.name) {
+                               PUSHs(ps->invocant.name);
+                       } else {
+                               PUSHmortal;
+                       }
+               }
+               /* 3 */ {
+                       size_t i, lim;
+                       AV *av;
+
+                       lim = ps->positional_required.used;
+
+                       av = newAV();
+                       if (lim) {
+                               av_extend(av, lim - 1);
+                               for (i = 0; i < lim; i++) {
+                                       av_push(av, SvREFCNT_inc_simple_NN(ps->positional_required.data[i].name));
+                               }
+                       }
+
+                       mPUSHs(newRV_noinc((SV *)av));
+               }
+               /* 4 */ {
+                       size_t i, lim;
+                       AV *av;
+
+                       lim = ps->positional_optional.used;
+
+                       av = newAV();
+                       if (lim) {
+                               av_extend(av, lim - 1);
+                               for (i = 0; i < lim; i++) {
+                                       av_push(av, SvREFCNT_inc_simple_NN(ps->positional_optional.data[i].param.name));
+                               }
+                       }
+
+                       mPUSHs(newRV_noinc((SV *)av));
+               }
+               /* 5 */ {
+                       size_t i, lim;
+                       AV *av;
+
+                       lim = ps->named_required.used;
+
+                       av = newAV();
+                       if (lim) {
+                               av_extend(av, lim - 1);
+                               for (i = 0; i < lim; i++) {
+                                       av_push(av, SvREFCNT_inc_simple_NN(ps->named_required.data[i].name));
+                               }
+                       }
+
+                       mPUSHs(newRV_noinc((SV *)av));
+               }
+               /* 6 */ {
+                       size_t i, lim;
+                       AV *av;
+
+                       lim = ps->named_optional.used;
+
+                       av = newAV();
+                       if (lim) {
+                               av_extend(av, lim - 1);
+                               for (i = 0; i < lim; i++) {
+                                       av_push(av, SvREFCNT_inc_simple_NN(ps->named_optional.data[i].param.name));
+                               }
+                       }
+
+                       mPUSHs(newRV_noinc((SV *)av));
+               }
+               /* 7 */ {
+                       if (ps->slurpy.name) {
+                               PUSHs(ps->slurpy.name);
+                       } else {
+                               PUSHmortal;
+                       }
+               }
+       }
+       PUTBACK;
+
+       call_pv(MY_PKG "::_register_info", G_VOID);
+
+       FREETMPS;
+       LEAVE;
+}
+
 static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRLEN keyword_len, const KWSpec *spec) {
        ParamSpec *param_spec;
        SV *declarator;
@@ -945,11 +1029,13 @@ static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRL
                                        *init_sentinel = NULL;
                                        param_spec->named_optional.used++;
                                } else {
+                                       Param *p;
+
                                        if (param_spec->positional_optional.used) {
                                                croak("In %"SVf": can't combine optional positional (%"SVf") and required named (%"SVf") parameters", SVfARG(declarator), SVfARG(param_spec->positional_optional.data[0].param.name), SVfARG(name));
                                        }
 
-                                       Param *p = pv_extend(&param_spec->named_required);
+                                       p = pv_extend(&param_spec->named_required);
                                        p->name = name;
                                        p->padoff = padoff;
                                        param_spec->named_required.used++;
@@ -1110,11 +1196,10 @@ static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRL
        /* check number of arguments */
        if (spec->flags & FLAG_CHECK_NARGS) {
                int amin, amax;
-               size_t named;
 
                amin = args_min(aTHX_ param_spec, spec);
                if (amin > 0) {
-                       OP *chk, *cond, *err, *croak;
+                       OP *chk, *cond, *err, *xcroak;
 
                        err = mkconstsv(aTHX_ newSVpvf("Not enough arguments for %"SVf" (expected %d, got ", SVfARG(declarator), amin));
                        err = newBINOP(
@@ -1128,10 +1213,10 @@ static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRL
                                mkconstpvs(")")
                        );
 
-                       croak = newCVREF(OPf_WANT_SCALAR,
-                                        newGVOP(OP_GV, 0, gv_fetchpvs("Carp::croak", 0, SVt_PVCV)));
+                       xcroak = newCVREF(OPf_WANT_SCALAR,
+                                         newGVOP(OP_GV, 0, gv_fetchpvs("Carp::croak", 0, SVt_PVCV)));
                        err = newUNOP(OP_ENTERSUB, OPf_STACKED,
-                                     op_append_elem(OP_LIST, err, croak));
+                                     op_append_elem(OP_LIST, err, xcroak));
 
                        cond = newBINOP(OP_LT, 0,
                                        newAVREF(newGVOP(OP_GV, 0, PL_defgv)),
@@ -1143,7 +1228,7 @@ static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRL
 
                amax = args_max(param_spec);
                if (amax >= 0) {
-                       OP *chk, *cond, *err, *croak;
+                       OP *chk, *cond, *err, *xcroak;
 
                        err = mkconstsv(aTHX_ newSVpvf("Too many arguments for %"SVf" (expected %d, got ", SVfARG(declarator), amax));
                        err = newBINOP(
@@ -1157,12 +1242,12 @@ static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRL
                                mkconstpvs(")")
                        );
 
-                       croak = newCVREF(
+                       xcroak = newCVREF(
                                OPf_WANT_SCALAR,
                                newGVOP(OP_GV, 0, gv_fetchpvs("Carp::croak", 0, SVt_PVCV))
                        );
                        err = newUNOP(OP_ENTERSUB, OPf_STACKED,
-                       op_append_elem(OP_LIST, err, croak));
+                       op_append_elem(OP_LIST, err, xcroak));
 
                        cond = newBINOP(
                                OP_GT, 0,
@@ -1175,17 +1260,17 @@ static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRL
                }
 
                if (param_spec && (count_named_params(param_spec) || (param_spec->slurpy.name && SvPV_nolen(param_spec->slurpy.name)[0] == '%'))) {
-                       OP *chk, *cond, *err, *croak;
+                       OP *chk, *cond, *err, *xcroak;
                        const UV fixed = count_positional_params(param_spec) + !!param_spec->invocant.name;
 
                        err = mkconstsv(aTHX_ newSVpvf("Odd number of paired arguments for %"SVf"", SVfARG(declarator)));
 
-                       croak = newCVREF(
+                       xcroak = newCVREF(
                                OPf_WANT_SCALAR,
                                newGVOP(OP_GV, 0, gv_fetchpvs("Carp::croak", 0, SVt_PVCV))
                        );
                        err = newUNOP(OP_ENTERSUB, OPf_STACKED,
-                       op_append_elem(OP_LIST, err, croak));
+                       op_append_elem(OP_LIST, err, xcroak));
 
                        cond = newBINOP(OP_GT, 0,
                                        newAVREF(newGVOP(OP_GV, 0, PL_defgv)),
@@ -1383,21 +1468,21 @@ static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRL
                                cond = mkhvelem(aTHX_ param_spec->rest_hash, mkconstpv(aTHX_ p + 1, n - 1));
 
                                if (spec->flags & FLAG_CHECK_NARGS) {
-                                       OP *croak, *msg;
+                                       OP *xcroak, *msg;
 
                                        var = mkhvelem(aTHX_ param_spec->rest_hash, mkconstpv(aTHX_ p + 1, n - 1));
                                        var = newUNOP(OP_DELETE, 0, var);
 
                                        msg = mkconstsv(aTHX_ newSVpvf("In %"SVf": missing named parameter: %.*s", SVfARG(declarator), (int)(n - 1), p + 1));
-                                       croak = newCVREF(
+                                       xcroak = newCVREF(
                                                OPf_WANT_SCALAR,
                                                newGVOP(OP_GV, 0, gv_fetchpvs("Carp::croak", 0, SVt_PVCV))
                                        );
-                                       croak = newUNOP(OP_ENTERSUB, OPf_STACKED, op_append_elem(OP_LIST, msg, croak));
+                                       xcroak = newUNOP(OP_ENTERSUB, OPf_STACKED, op_append_elem(OP_LIST, msg, xcroak));
 
                                        cond = newUNOP(OP_EXISTS, 0, cond);
 
-                                       cond = newCONDOP(0, cond, var, croak);
+                                       cond = newCONDOP(0, cond, var, xcroak);
                                }
 
                                var = my_var(
@@ -1438,7 +1523,7 @@ static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRL
                        if (!param_spec->slurpy.name) {
                                if (spec->flags & FLAG_CHECK_NARGS) {
                                        /* croak if %{rest} */
-                                       OP *croak, *cond, *keys, *msg;
+                                       OP *xcroak, *cond, *keys, *msg;
 
                                        keys = newUNOP(OP_KEYS, 0, my_var_g(aTHX_ OP_PADHV, 0, param_spec->rest_hash));
                                        keys = newLISTOP(OP_SORT, 0, newOP(OP_PUSHMARK, 0), keys);
@@ -1460,16 +1545,16 @@ static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRL
                                        msg = mkconstsv(aTHX_ newSVpvf("In %"SVf": no such named parameter: ", SVfARG(declarator)));
                                        msg = newBINOP(OP_CONCAT, 0, msg, keys);
 
-                                       croak = newCVREF(
+                                       xcroak = newCVREF(
                                                OPf_WANT_SCALAR,
                                                newGVOP(OP_GV, 0, gv_fetchpvs("Carp::croak", 0, SVt_PVCV))
                                        );
-                                       croak = newUNOP(OP_ENTERSUB, OPf_STACKED, op_append_elem(OP_LIST, msg, croak));
+                                       xcroak = newUNOP(OP_ENTERSUB, OPf_STACKED, op_append_elem(OP_LIST, msg, xcroak));
 
                                        cond = newUNOP(OP_KEYS, 0, my_var_g(aTHX_ OP_PADHV, 0, param_spec->rest_hash));
-                                       croak = newCONDOP(0, cond, croak, NULL);
+                                       xcroak = newCONDOP(0, cond, xcroak, NULL);
 
-                                       *prelude_sentinel = op_append_list(OP_LINESEQ, *prelude_sentinel, newSTATEOP(0, NULL, croak));
+                                       *prelude_sentinel = op_append_list(OP_LINESEQ, *prelude_sentinel, newSTATEOP(0, NULL, xcroak));
                                } else {
                                        OP *clear;
 
@@ -1525,32 +1610,38 @@ static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRL
 
        /* it's go time. */
        {
+               CV *cv;
                OP *const attrs = *attrs_sentinel;
                *attrs_sentinel = NULL;
+
                SvREFCNT_inc_simple_void(PL_compcv);
 
                /* close outer block: '}' */
                S_block_end(aTHX_ save_ix, body);
 
-               if (!saw_name) {
-                       *pop = newANONATTRSUB(
-                               floor_ix,
-                               proto ? newSVOP(OP_CONST, 0, SvREFCNT_inc_simple_NN(proto)) : NULL,
-                               attrs,
-                               body
-                       );
-                       return KEYWORD_PLUGIN_EXPR;
-               }
-
-               newATTRSUB(
+               cv = newATTRSUB(
                        floor_ix,
-                       newSVOP(OP_CONST, 0, SvREFCNT_inc_simple_NN(saw_name)),
+                       saw_name ? newSVOP(OP_CONST, 0, SvREFCNT_inc_simple_NN(saw_name)) : NULL,
                        proto ? newSVOP(OP_CONST, 0, SvREFCNT_inc_simple_NN(proto)) : NULL,
                        attrs,
                        body
                );
-               *pop = newOP(OP_NULL, 0);
-               return KEYWORD_PLUGIN_STMT;
+
+               register_info(aTHX_ PTR2UV(CvROOT(cv)), declarator, spec, param_spec);
+
+               if (saw_name) {
+                       *pop = newOP(OP_NULL, 0);
+                       return KEYWORD_PLUGIN_STMT;
+               }
+
+               *pop = newUNOP(
+                       OP_REFGEN, 0,
+                       newSVOP(
+                               OP_ANONCODE, 0,
+                               (SV *)cv
+                       )
+               );
+               return KEYWORD_PLUGIN_EXPR;
        }
 }
 
@@ -1578,9 +1669,22 @@ static int my_keyword_plugin(pTHX_ char *keyword_ptr, STRLEN keyword_len, OP **o
 
 WARNINGS_RESET
 
-MODULE = Function::Parameters   PACKAGE = Function::Parameters
+MODULE = Function::Parameters   PACKAGE = Function::Parameters   PREFIX = fp_
 PROTOTYPES: ENABLE
 
+UV
+fp__cv_root(sv)
+       SV * sv
+       PREINIT:
+               CV *xcv;
+               HV *hv;
+               GV *gv;
+       CODE:
+               xcv = sv_2cv(sv, &hv, &gv, 0);
+               RETVAL = PTR2UV(xcv ? CvROOT(xcv) : NULL);
+       OUTPUT:
+               RETVAL
+
 BOOT:
 WARNINGS_ENABLE {
        HV *const stash = gv_stashpvs(MY_PKG, GV_ADD);