I've published a second version of a patch to add a method keyword to Perl 5. The main difference in this patch is building up the optree to perform my $self = shift; instead of stuffing that code into the lexer at the appropriate place:
methbody : '{' remember addimplicitshift stmtseq '}'
{
if (PL_parser->copline > (line_t)IVAL($1))
PL_parser->copline = (line_t)IVAL($1);
$$ = block_end($3, op_append_list(OP_LINESEQ, $3, $4));
TOKEN_GETMAD($2,$$,'{');
TOKEN_GETMAD($4,$$,'}');
}
;
addimplicitshift :
{ OP *selfsv = newOP(OP_PADSV, 0);
OP *rv2av = newUNOP(OP_RV2AV, 0, newGVOP(OP_GV, 0, PL_defgv));
OP *shift = newUNOP(OP_SHIFT, 0, rv2av);
selfsv->op_targ = (I32)Perl_allocmy(aTHX_ STR_WITH_LEN("$self"), 0);
$$ = newSTATEOP(0, NULL,
newASSIGNOP(OPf_STACKED, selfsv, 0, shift));
}
;
The second production is most interesting. It does the work of creating the Perl 5 optree you can see from running:
$ perl -MO=Concise,meth -e 'sub meth { my $self = shift; }'
main::meth:
7 <1> leavesub[1 ref] K/REFC,1 ->(end)
- <@> lineseq KP ->7
1 <;> nextstate(main 1 -e:1) v ->2
6 <2> sassign sKS/2 ->7
4 <1> shift sK/1 ->5
3 <1> rv2av[t2] sKRM/1 ->4
2 <$> gv(*_) s ->3
5 <0> padsv[$self:1,2] sRM*/LVINTRO ->6
You don't have to understand all of that, but you can see that this is
obviously a tree structure. addimplicitshift creates the branch
staring at nextstate (op 1) with a sibling sassign
(op 6). Other productions have already set up the body of the sub and its
lexical scope, so the call to Perl_allocmy only has to give the
name of a new lexical ($self). Its return value is the location of
the created variable in the lexical storage pad, so that the opcode to access
the value of $self can retrieve it correctly.
With that lexical created before the parser parses the literal body of the method from the source code, any other references to $self refer to the lexical implicitly created thanks to the method keyword such that:
use feature 'method';
method oops
{
my $self = shift;
}
... produces a warning:
"my" variable $self masks earlier declaration in same scope
I suspect there's a reasonably easy way to make the method keyword work nicely with projects such as MooseX::Declare in code such as:
use 5.014;
use MooseX::Declare;
method register(Str $name, Int $age) { ... }
... but despite the
advantages of a method keyword in Perl 5, I've done about as
much coding on this as I want to do without more support that it might
eventually go into Perl 5.
