Skip to content

Commit

Permalink
RakuAST: move role body tweaking logic to RakuAST::Package class
Browse files Browse the repository at this point in the history
The reason for this is simple: we can not expect a developer that
creates a new RakuAST::Package(:declarator<role>) object to know
that the body of the role should really be a sub, and that it should
have a signature matching the intended parameterization of the role.

This commit:
- moves the body tweaking logic to the "replace-body" method
- and adds an argument for the Signature to be used for parameterization
- adds a :parameterization argument to .new
- let's the .new method call the "replace-body" method to set the body

This now allows a role to be created using RakuAST:: classes *without*
needing to know the required internal tweaking.  Rakufication and
deparsing have already earlier been adapted to hide this internal
tweaking, so that we now can roundtrip the RakuAST code for a role.
  • Loading branch information
lizmat committed Mar 13, 2023
1 parent 98cc71c commit 1d7bf1c
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 22 deletions.
12 changes: 1 addition & 11 deletions src/Raku/Actions.nqp
Expand Up @@ -1475,17 +1475,7 @@ class Raku::Actions is HLL::Actions does Raku::CommonActions {
return self.attach: $/, $package;
}

if $*PKGDECL eq 'role' {
my $signature := $<signature> ?? $<signature>.ast !! self.r('Signature').new;
$signature.set-is-on-role-body(1);
# upgrade body to a sub with a signature
$body := self.r('Sub').new(
:name($package.name),
:$signature,
:body($body.body)
);
}
$package.replace-body: $body;
$package.replace-body($body, $<signature> ?? $<signature>.ast !! Mu);
$package.IMPL-CHECK($*R, $*CU.context, 1);
$package.IMPL-COMPOSE();
self.attach: $/, $package;
Expand Down
50 changes: 39 additions & 11 deletions src/Raku/ast/package.rakumod
Expand Up @@ -27,31 +27,59 @@ class RakuAST::Package
has Mu $!attached-attributes;
has Mu $!attached-attribute-usages;

method new(Str :$declarator!, Mu :$how, Mu :$attribute-type,
RakuAST::Name :$name, Str :$repr, RakuAST::Code :$body,
str :$scope, List :$traits) {
method new( str :$scope,
Str :$declarator!,
RakuAST::Name :$name,
RakuAST::Signature :$parameterization,
List :$traits,
RakuAST::Code :$body,
Mu :$attribute-type,
Mu :$how,
Str :$repr
) {
my $obj := nqp::create(self);
nqp::bindattr_s($obj, RakuAST::Declaration, '$!scope', $scope);
nqp::bindattr($obj, RakuAST::Package, '$!declarator', $declarator);
nqp::bindattr($obj, RakuAST::Package, '$!name', $name // RakuAST::Name);
$obj.set-traits($traits) if $traits;
$obj.replace-body($body, $parameterization);

nqp::bindattr($obj, RakuAST::Package, '$!attribute-type',
nqp::eqaddr($attribute-type, NQPMu) ?? Attribute !! $attribute-type);
nqp::bindattr($obj, RakuAST::Package, '$!how',
nqp::eqaddr($how,NQPMu) ?? $obj.default-how !! $how
);
nqp::bindattr($obj, RakuAST::Package, '$!attribute-type',
nqp::eqaddr($attribute-type, NQPMu) ?? Attribute !! $attribute-type);
nqp::bindattr($obj, RakuAST::Package, '$!name', $name // RakuAST::Name);
nqp::bindattr($obj, RakuAST::Package, '$!repr', $repr // Str);
nqp::bindattr($obj, RakuAST::Package, '$!body', $body // RakuAST::Block.new);

# Set up internal defaults
nqp::bindattr($obj, RakuAST::Package, '$!attached-methods', []);
nqp::bindattr($obj, RakuAST::Package, '$!attached-attributes', []);
nqp::bindattr($obj, RakuAST::Package, '$!attached-attribute-usages', []);
nqp::bindattr($obj, RakuAST::Package, '$!attached-attribute-usages',[]);
nqp::bindattr($obj, RakuAST::Package, '$!role-group', Mu);
nqp::bindattr($obj, RakuAST::Package, '$!is-stub', False);
$obj.set-traits($traits) if $traits;

$obj
}

method replace-body(RakuAST::Code $new-body) {
nqp::bindattr(self, RakuAST::Package, '$!body', $new-body);
method replace-body(RakuAST::Code $body, RakuAST::Signature $signature) {
$body := RakuAST::Block.new unless $body;

# The body of a role is internally a Sub that has the parameterization
# of the role as the signature. This allows a role to be selected
# using ordinary dispatch semantics. Later on, the statement list
# will get a return value added, so that the role's meta-object and
# lexpad are returned.
if $!declarator eq 'role' {
$signature := RakuAST::Signature.new unless $signature;
$signature.set-is-on-role-body(1);
$body := RakuAST::Sub.new(
name => $!name,
signature => $signature,
body => $body.body
)
}

nqp::bindattr(self, RakuAST::Package, '$!body', $body);
Nil
}

Expand Down

0 comments on commit 1d7bf1c

Please sign in to comment.