@@ -16190,6 +16190,225 @@ Perl_rcpv_copy(pTHX_ char *pv) {
16190
16190
return pv;
16191
16191
}
16192
16192
16193
+ /* Subroutine signature parsing */
16194
+
16195
+ struct yy_parser_signature {
16196
+ UV elems; /* number of signature elements seen so far */
16197
+ UV optelems; /* number of optional signature elems seen */
16198
+ char slurpy; /* the sigil of the slurpy var (or null) */
16199
+ OP *elemops; /* NULL, or an OP_LINESEQ of individual element ops */
16200
+ };
16201
+
16202
+ static void
16203
+ destroy_subsignature_context(pTHX_ void *p)
16204
+ {
16205
+ yy_parser_signature *signature = (yy_parser_signature *)p;
16206
+
16207
+ if(signature->elemops)
16208
+ op_free(signature->elemops);
16209
+
16210
+ Safefree(signature);
16211
+ }
16212
+
16213
+ /* Called from perly.y on encountering the '(' of a subroutine signature.
16214
+ * Does not return anything useful, but sets up the memory structure in
16215
+ * `PL_parser->signature` that the following functions make use of.
16216
+ */
16217
+
16218
+ void
16219
+ Perl_subsignature_start(pTHX)
16220
+ {
16221
+ PERL_ARGS_ASSERT_SUBSIGNATURE_START;
16222
+ assert(PL_parser);
16223
+
16224
+ yy_parser_signature *signature;
16225
+ Newx(signature, 1, yy_parser_signature);
16226
+ SAVEDESTRUCTOR_X(&destroy_subsignature_context, signature);
16227
+
16228
+ signature->elems = 0;
16229
+ signature->optelems = 0;
16230
+ signature->slurpy = 0;
16231
+
16232
+ signature->elemops = NULL;
16233
+
16234
+ SAVEVPTR(PL_parser->signature);
16235
+ PL_parser->signature = signature;
16236
+ }
16237
+
16238
+ /* Appends another positional scalar parameter to the accumulated set of
16239
+ * subroutine params. `varop` may be NULL, but if not it must be an OP_ARGELEM
16240
+ * whose op_targ refers to an already-declared pad lexical. That lexical must
16241
+ * be a scalar. It is not necessary to set the argument index in the op_aux
16242
+ * field; that will be filled in by this function.
16243
+ * If `defexpr` is not NULL, it gives a defaulting expression to be evaluated
16244
+ * if required, according to `defmode` - one of zero, `OP_DORASSIGN` or
16245
+ * `OP_ORASSIGN`.
16246
+ */
16247
+
16248
+ void
16249
+ Perl_subsignature_append_positional(pTHX_ OP *varop, OPCODE defmode, OP *defexpr)
16250
+ {
16251
+ PERL_ARGS_ASSERT_SUBSIGNATURE_APPEND_POSITIONAL;
16252
+ assert(PL_parser);
16253
+ yy_parser_signature *signature = PL_parser->signature;
16254
+ assert(signature);
16255
+
16256
+ if(signature->slurpy)
16257
+ yyerror("Slurpy parameter not last");
16258
+
16259
+ UV argix = signature->elems;
16260
+
16261
+ if(varop) {
16262
+ assert(varop->op_type == OP_ARGELEM);
16263
+ assert((varop->op_private & OPpARGELEM_MASK) == OPpARGELEM_SV);
16264
+ assert(varop->op_targ);
16265
+ assert(PadnamePV(PadnamelistARRAY(PL_comppad_name)[varop->op_targ])[0] == '$');
16266
+
16267
+ /* Now fill in the argix */
16268
+ cUNOP_AUXx(varop)->op_aux = INT2PTR(UNOP_AUX_item *, argix);
16269
+ }
16270
+
16271
+ signature->elems++;
16272
+
16273
+ if(defexpr) {
16274
+ signature->optelems++;
16275
+
16276
+ I32 flags = 0;
16277
+ if(defmode == OP_DORASSIGN)
16278
+ flags |= OPpARG_IF_UNDEF << 8;
16279
+ if(defmode == OP_ORASSIGN)
16280
+ flags |= OPpARG_IF_FALSE << 8;
16281
+
16282
+ if(defexpr->op_type == OP_NULL && !(defexpr->op_flags & OPf_KIDS))
16283
+ {
16284
+ /* handle '$=' special case */
16285
+ if(varop)
16286
+ yyerror("Optional parameter lacks default expression");
16287
+ }
16288
+ else {
16289
+ /* a normal '=default' expression */
16290
+ OP *defop = newARGDEFELEMOP(flags, defexpr, argix);
16291
+
16292
+ if(varop) {
16293
+ varop->op_flags |= OPf_STACKED;
16294
+ (void)op_sibling_splice(varop, NULL, 0, defop);
16295
+ scalar(defop);
16296
+ }
16297
+ else
16298
+ varop = newUNOP(OP_NULL, 0, defop);
16299
+
16300
+ LINKLIST(varop);
16301
+ /* NB: normally the first child of a logop is executed before the
16302
+ * logop, and it pushes a boolean result ready for the logop. For
16303
+ * ARGDEFELEM, the op itself does the boolean calculation, so set
16304
+ * the first op to it instead.
16305
+ */
16306
+ varop->op_next = defop;
16307
+ defexpr->op_next = varop;
16308
+ }
16309
+ }
16310
+ else
16311
+ if(signature->optelems)
16312
+ yyerror("Mandatory parameter follows optional parameter");
16313
+
16314
+ if(varop) {
16315
+ signature->elemops = op_append_list(OP_LINESEQ, signature->elemops,
16316
+ newSTATEOP(0, NULL, varop));
16317
+ }
16318
+ }
16319
+
16320
+ /* Appends a final slurpy parameter to the accumulated set of subroutine
16321
+ * params. `varop` may be NULL, but if not it must be an OP_ARGELEM whose
16322
+ * op_targ refers to an already-declared pad lexical. That lexical must match
16323
+ * the `sigil` parameter. It is not necessary to set the argument index in the
16324
+ * op_aux field; that will be filled in by this function.
16325
+ */
16326
+
16327
+ void
16328
+ Perl_subsignature_append_slurpy(pTHX_ I32 sigil, OP *varop)
16329
+ {
16330
+ PERL_ARGS_ASSERT_SUBSIGNATURE_APPEND_SLURPY;
16331
+ assert(PL_parser);
16332
+ yy_parser_signature *signature = PL_parser->signature;
16333
+ assert(signature);
16334
+ assert(sigil == '@' || sigil == '%');
16335
+
16336
+ if(signature->slurpy)
16337
+ yyerror("Multiple slurpy parameters not allowed");
16338
+
16339
+ UV argix = signature->elems;
16340
+
16341
+ if(varop) {
16342
+ assert(varop->op_type == OP_ARGELEM);
16343
+ assert((varop->op_private & OPpARGELEM_MASK) ==
16344
+ ((sigil == '@') ? OPpARGELEM_AV : OPpARGELEM_HV));
16345
+ assert(varop->op_targ);
16346
+ assert(PadnamePV(PadnamelistARRAY(PL_comppad_name)[varop->op_targ])[0] == sigil);
16347
+
16348
+ /* Now fill in the argix */
16349
+ cUNOP_AUXx(varop)->op_aux = INT2PTR(UNOP_AUX_item *, argix);
16350
+ }
16351
+
16352
+ signature->slurpy = (char)sigil;
16353
+
16354
+ if(varop) {
16355
+ /* TODO: assert() the sigil of the pad variable matches */
16356
+ signature->elemops = op_append_list(OP_LINESEQ, signature->elemops,
16357
+ newSTATEOP(0, NULL, varop));
16358
+ }
16359
+ }
16360
+
16361
+ /* Called from perly.y on encountering the closing `)` of a subroutine
16362
+ * signature. This creates the optree fragment responsible for processing all
16363
+ * the accumulated subroutine params, to be inserted at the start of the
16364
+ * subroutine's optree.
16365
+ */
16366
+
16367
+ OP *
16368
+ Perl_subsignature_finish(pTHX)
16369
+ {
16370
+ PERL_ARGS_ASSERT_SUBSIGNATURE_FINISH;
16371
+ assert(PL_parser);
16372
+ yy_parser_signature *signature = PL_parser->signature;
16373
+ assert(signature);
16374
+
16375
+ OP *sigops = signature->elemops;
16376
+ signature->elemops = NULL;
16377
+
16378
+ struct op_argcheck_aux *aux = (struct op_argcheck_aux *)
16379
+ PerlMemShared_malloc( sizeof(struct op_argcheck_aux));
16380
+
16381
+ aux->params = signature->elems;
16382
+ aux->opt_params = signature->optelems;
16383
+ aux->slurpy = signature->slurpy;
16384
+
16385
+ OP *check = newUNOP_AUX(OP_ARGCHECK, 0, NULL, (UNOP_AUX_item *)aux);
16386
+
16387
+ sigops = op_prepend_elem(OP_LINESEQ,
16388
+ check,
16389
+ sigops);
16390
+
16391
+ /* a nextstate right at the beginning */
16392
+ sigops = op_prepend_elem(OP_LINESEQ,
16393
+ newSTATEOP(0, NULL, NULL),
16394
+ sigops);
16395
+
16396
+ /* a nextstate at the end handles context correctly for an empty sub body */
16397
+ sigops = op_append_elem(OP_LINESEQ, sigops,
16398
+ newSTATEOP(0, NULL, NULL));
16399
+
16400
+ /* wrap the list of arg ops in a NULL aux op.
16401
+ This serves two purposes. First, it makes the arg list a separate
16402
+ subtree from the body of the sub, and secondly the null op may in future
16403
+ be upgraded to an OP_SIGNATURE when implemented. For now leave it as
16404
+ ex-argcheck */
16405
+
16406
+ OP *ret = newUNOP_AUX(OP_ARGCHECK, 0, sigops, NULL);
16407
+ op_null(ret);
16408
+
16409
+ return ret;
16410
+ }
16411
+
16193
16412
/*
16194
16413
* ex: set ts=8 sts=4 sw=4 et:
16195
16414
*/
0 commit comments