@@ -1055,6 +1055,104 @@ apply_field_attribute_reader(pTHX_ PADNAME *pn, SV *value)
10551055 CvIsMETHOD_on (cv );
10561056}
10571057
1058+ /* If '@_' is called "snail", then elements of it can be called "slugs"; i.e.
1059+ * snails out of their container. */
1060+ #define newSLUGOP (idx ) S_newSLUGOP(aTHX_ idx)
1061+ static OP *
1062+ S_newSLUGOP (pTHX_ IV idx )
1063+ {
1064+ assert (idx >= 0 && idx <= 255 );
1065+ OP * op = newGVOP (OP_AELEMFAST , 0 , PL_defgv );
1066+ op -> op_private = idx ;
1067+ return op ;
1068+ }
1069+
1070+ static void
1071+ apply_field_attribute_writer (pTHX_ PADNAME * pn , SV * value )
1072+ {
1073+ char sigil = PadnamePV (pn )[0 ];
1074+ if (sigil != '$' )
1075+ croak ("Cannot apply a :writer attribute to a non-scalar field" );
1076+
1077+ if (value )
1078+ SvREFCNT_inc (value );
1079+ else {
1080+ /* Default to "set_" . name minus the sigil */
1081+ value = newSVpvs ("set_" );
1082+ sv_catpvn_flags (value , PadnamePV (pn ) + 1 , PadnameLEN (pn ) - 1 ,
1083+ PadnameUTF8 (pn ) ? SV_CATUTF8 : 0 );
1084+ }
1085+
1086+ if (!valid_identifier_sv (value ))
1087+ croak ("%" SVf_QUOTEDPREFIX " is not a valid name for a generated method" , value );
1088+
1089+ PADOFFSET fieldix = PadnameFIELDINFO (pn )-> fieldix ;
1090+
1091+ I32 floor_ix = start_subparse (FALSE, 0 );
1092+ SAVEFREESV (PL_compcv );
1093+
1094+ I32 save_ix = block_start (TRUE);
1095+
1096+ PADOFFSET padix ;
1097+
1098+ padix = pad_add_name_pvs ("$self" , 0 , NULL , NULL );
1099+ assert (padix == PADIX_SELF );
1100+
1101+ padix = pad_add_name_pvn (PadnamePV (pn ), PadnameLEN (pn ), 0 , NULL , NULL );
1102+ intro_my ();
1103+
1104+ OP * methstartop ;
1105+ {
1106+ UNOP_AUX_item * aux ;
1107+ aux = (UNOP_AUX_item * )PerlMemShared_malloc (
1108+ sizeof (UNOP_AUX_item ) * (2 + 2 ));
1109+
1110+ UNOP_AUX_item * ap = aux ;
1111+ (ap ++ )-> uv = 1 ; /* fieldcount */
1112+ (ap ++ )-> uv = fieldix ; /* max_fieldix */
1113+
1114+ (ap ++ )-> uv = padix ;
1115+ (ap ++ )-> uv = fieldix ;
1116+
1117+ methstartop = newUNOP_AUX (OP_METHSTART , 0 , NULL , aux );
1118+ }
1119+
1120+ OP * argcheckop ;
1121+ {
1122+ struct op_argcheck_aux * aux = (struct op_argcheck_aux * )
1123+ PerlMemShared_malloc (sizeof (* aux ));
1124+
1125+ aux -> params = 1 ;
1126+ aux -> opt_params = 0 ;
1127+ aux -> slurpy = 0 ;
1128+
1129+ argcheckop = newUNOP_AUX (OP_ARGCHECK , 0 , NULL , (UNOP_AUX_item * )aux );
1130+ }
1131+
1132+ OP * assignop = newBINOP (OP_SASSIGN , 0 ,
1133+ newSLUGOP (0 ),
1134+ newPADxVOP (OP_PADSV , OPf_MOD |OPf_REF , padix ));
1135+
1136+ OP * retop = newLISTOP (OP_RETURN , 0 ,
1137+ newOP (OP_PUSHMARK , 0 ),
1138+ newPADxVOP (OP_PADSV , 0 , PADIX_SELF ));
1139+
1140+ OP * ops = newLISTOPn (OP_LINESEQ , 0 ,
1141+ methstartop ,
1142+ argcheckop ,
1143+ assignop ,
1144+ retop ,
1145+ NULL );
1146+
1147+ SvREFCNT_inc (PL_compcv );
1148+ ops = block_end (save_ix , ops );
1149+
1150+ OP * nameop = newSVOP (OP_CONST , 0 , value );
1151+
1152+ CV * cv = newATTRSUB (floor_ix , nameop , NULL , NULL , ops );
1153+ CvIsMETHOD_on (cv );
1154+ }
1155+
10581156static struct {
10591157 const char * name ;
10601158 bool requires_value ;
@@ -1068,6 +1166,10 @@ static struct {
10681166 .requires_value = false,
10691167 .apply = & apply_field_attribute_reader ,
10701168 },
1169+ { .name = "writer" ,
1170+ .requires_value = false,
1171+ .apply = & apply_field_attribute_writer ,
1172+ },
10711173 { NULL , false, NULL }
10721174};
10731175
0 commit comments