Skip to content

Commit

Permalink
Give nqp named anon methods
Browse files Browse the repository at this point in the history
Allows for the following pattern:

```raku
nqp::getstaticcode(
    anon method introspective() {
        nqp::die('nice callstack!')
    });
```

Which would be *very* useful in Rakudo's bootstrapping, for instance.
Many of Rakudo's core methods lack names on their code objects, which
tends to be rather confusing for newcomers introspecting methods.
  • Loading branch information
Kaiepi committed May 17, 2022
1 parent f305450 commit ef85aeb
Showing 1 changed file with 30 additions and 28 deletions.
58 changes: 30 additions & 28 deletions src/NQP/Actions.nqp
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,7 @@ class NQP::Actions is HLL::Actions {
# Otherwise, build method block QAST.
my $ast;
my int $onlystar;
my $package := $/.package;
my $package := $/.package;
if $<onlystar> {
$ast := only_star_block();
$onlystar := 1;
Expand Down Expand Up @@ -1062,40 +1062,42 @@ class NQP::Actions is HLL::Actions {
}
$name := "!!LATENAME!!" ~ ~$<latename>;
}
if $name ne "" {
if $name {
# Set name.
$ast.name($name);
}

# Insert it into the method table.
my $meta_meth := $*MULTINESS eq 'multi' ?? 'add_multi_method' !! 'add_method';
my $is_dispatcher := $*MULTINESS eq 'proto';
my $code := $*W.create_code($ast, $name, $is_dispatcher, :$onlystar);
if $*MULTINESS eq 'multi' { attach_multi_signature($code, $ast); }
# Insert it into the method table.
my $meta_meth := $*MULTINESS eq 'multi' ?? 'add_multi_method' !! 'add_method';
my $is_dispatcher := $*MULTINESS eq 'proto';
my $code := $*W.create_code($ast, $name, $is_dispatcher, :$onlystar);
if $*MULTINESS eq 'multi' { attach_multi_signature($code, $ast); }
if $*SCOPE eq 'our' {
# Install it in the package's stash.
$*W.install_package_routine($package, $name, $ast);
}
unless $*SCOPE eq 'anon' {
# Install it in the method table.
$*W.pkg_add_method($package, $meta_meth, $name, $code);
$ast.annotate('code_obj', $code);

# Install it in the package also if needed.
if $*SCOPE eq 'our' {
$*W.install_package_routine($package, $name, $ast);
}
}
$ast.annotate('code_obj', $code);

#?if !moar
# If it's a proto, also stash the current lexical dispatcher, for the {*}
# to resolve.
if $is_dispatcher {
$ast[0].push(QAST::Op.new(
:op('bind'),
QAST::Var.new( :name('CURRENT_DISPATCH_CAPTURE'), :scope('lexical'), :decl('var') ),
QAST::Op.new( :op('savecapture') )
));
$ast[0].push(QAST::Op.new(
:op('bind'),
QAST::Var.new( :name('&*CURRENT_DISPATCHER'), :scope('lexical'), :decl('var') ),
QAST::Op.new( :op('getcodeobj'), QAST::Op.new( :op('curcode') ) )
));
}
#?endif
# If it's a proto, also stash the current lexical dispatcher, for the {*}
# to resolve.
if $is_dispatcher {
$ast[0].push(QAST::Op.new(
:op('bind'),
QAST::Var.new( :name('CURRENT_DISPATCH_CAPTURE'), :scope('lexical'), :decl('var') ),
QAST::Op.new( :op('savecapture') )
));
$ast[0].push(QAST::Op.new(
:op('bind'),
QAST::Var.new( :name('&*CURRENT_DISPATCHER'), :scope('lexical'), :decl('var') ),
QAST::Op.new( :op('getcodeobj'), QAST::Op.new( :op('curcode') ) )
));
}
#?endif

# Install AST node in match object, then apply traits.
make QAST::Op.new( :op('takeclosure'), $ast ).annotate_self(
Expand Down

0 comments on commit ef85aeb

Please sign in to comment.