2 #define DEFSTRUCT(T) typedef struct T T; struct T
9 #define DEFVECTOR(T, B) DEFSTRUCT(T) { \
14 DEFVECTOR(ParamInitVec, ParamInit);
15 DEFVECTOR(ParamVec, SV *);
17 DEFSTRUCT(ParamSpec) {
19 ParamVec positional_required;
20 ParamInitVec positional_optional;
21 ParamVec named_required;
22 ParamInitVec named_optional;
26 #define DEFVECTOR_CLEAR(T, N, F) static void N(T *p) { \
29 F(p->data[p->used]); \
36 static void pi_clear(ParamInit pi) {
38 SvREFCNT_dec(pi.name);
45 DEFVECTOR_CLEAR(ParamVec, pv_clear, SvREFCNT_dec);
46 DEFVECTOR_CLEAR(ParamInitVec, piv_clear, pi_clear);
48 static void ps_free(ParamSpec *ps) {
50 SvREFCNT_dec(ps->invocant);
53 pv_clear(&ps->positional_required);
54 piv_clear(&ps->positional_optional);
55 pv_clear(&ps->named_required);
56 piv_clear(&ps->named_optional);
58 SvREFCNT_dec(ps->slurpy);
64 static int args_min(const ParamSpec *ps) {
69 n += ps->positional_required.used;
70 n += ps->named_required.used * 2;
74 static int args_max(const ParamSpec *ps) {
79 n += ps->positional_required.used;
80 n += ps->positional_optional.used;
81 if (ps->named_required.used || ps->named_optional.used || ps->slurpy) {
87 static size_t count_positional_params(const ParamSpec *ps) {
88 return ps->positional_required.used + ps->positional_optional.used;
91 static size_t count_named_params(const ParamSpec *ps) {
92 return ps->named_required.used + ps->named_optional.used;
95 static void gen(ParamSpec *ps) {
96 int amin = args_min(ps);
98 printf("croak 'not enough' if @_ < %d;\n", amin);
100 int amax = args_max(ps);
102 printf("croak 'too many' if @_ > %d;\n", amax);
104 size_t named_params = count_named_params(ps);
105 if (named_params || (ps->slurpy && SvPV_nolen(ps->slurpy)[0] == '%')) {
106 size_t t = named_params + !!ps->invocant;
107 printf("croak 'odd' if (@_ - %zu) > 0 && (@_ - %zu) % 2;\n", t, t);
110 printf("%s = shift @_;\n", SvPV_nolen(ps->invocant));
113 size_t positional_params = count_positional_params(ps);
114 for (size_t i = 0; i < ps->positional_optional.used; i++) {
115 printf("%*sif (@_ < %zu) {\n", (int)i * 2, "", positional_params - i);
117 for (size_t i = 0; i < ps->positional_optional.used; i++) {
118 ParamInit *pi = &ps->positional_optional.data[i];
119 printf("%*s %s = %p;\n", (int)(ps->positional_optional.used - i - 1) * 2, "", SvPV_nolen(pi->name), pi->init);
120 printf("%*s}\n", (int)(ps->positional_optional.used - i - 1) * 2, "");
123 printf("if (@_ > %zu) {\n", positional_params);
124 printf(" my $_b = '';\n");
125 printf(" my $_i = %zu;\n", positional_params);
126 printf(" while ($_i < @_) {\n");
127 printf(" my $_k = $_[$_i];\n");
128 size_t req = ps->named_required.used;
129 for (size_t i = 0; i < named_params; i++) {
134 SV *param = i >= req ? ps->named_optional.data[i - req] : ps->named_required.data[i];
135 printf("if ($_k eq '%s') {\n", SvPV_nolen(param) + 1);
136 printf(" %s = $_[$_i + 1];\n", SvPV_nolen(param));
137 printf(" vec($_b, %zu, 1) = 1;\n", i);
142 const char *slurpy = SvPV_nolen(ps->slurpy);
143 if (slurpy[0] == '%') {
144 printf(" $%s{$_k} = $_[$_i + 1];\n", slurpy + 1);
146 printf(" push %s, $_k, $_[$_i + 1];\n", slurpy);
149 printf(" croak 'no such param ' . $_k;\n");
152 printf(" $_i += 2;\n");
154 if (ps->named_required.used) {
155 printf(" if (($_b & pack('b*', '1' x %zu)) ne pack('b*', '1' x %zu)) {\n", ps->named_required.used, ps->named_required.used);
156 printf(" croak 'missing required named args';\n"); // XXX
159 for (size_t i = 0; i < ps->named_optional.used; i++) {
160 printf(" %s = %p unless vec $_k, %zu, 1;\n", SvPV_nolen(ps->named_optional[i].name), ps->named_optional[i].init, ps->named_required.used + i);