Skip to content

Commit

Permalink
Make claim inside of a role work.
Browse files Browse the repository at this point in the history
This doesn't make it work yet inside of a class, and private methods
will need a look (some factoring out needed, no doubt). But it should
let us explore the idea some more.
  • Loading branch information
jnthn committed Jan 21, 2015
1 parent c326906 commit 3946ec8
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 33 deletions.
6 changes: 6 additions & 0 deletions src/Perl6/Metamodel/ClaimContainer.nqp
Expand Up @@ -9,4 +9,10 @@ role Perl6::Metamodel::ClaimContainer {
method claims($obj) {
@!claims
}

method add_claims($obj, @add) {
for @add {
nqp::push(@!claims, $_);
}
}
}
1 change: 1 addition & 0 deletions src/Perl6/Metamodel/ConcreteRoleHOW.nqp
Expand Up @@ -3,6 +3,7 @@ class Perl6::Metamodel::ConcreteRoleHOW
does Perl6::Metamodel::Versioning
does Perl6::Metamodel::PrivateMethodContainer
does Perl6::Metamodel::MethodContainer
does Perl6::Metamodel::ClaimContainer
does Perl6::Metamodel::MultiMethodContainer
does Perl6::Metamodel::AttributeContainer
does Perl6::Metamodel::RoleContainer
Expand Down
1 change: 1 addition & 0 deletions src/Perl6/Metamodel/ParametricRoleHOW.nqp
Expand Up @@ -176,6 +176,7 @@ class Perl6::Metamodel::ParametricRoleHOW
for self.multi_methods_to_incorporate($obj) {
$conc.HOW.add_multi_method($conc, $_.name, $_.code.instantiate_generic($type_env))
}
$conc.HOW.add_claims($conc, self.claims($obj));

# Roles done by this role need fully specializing also; all
# they'll be missing is the target class (e.g. our first arg).
Expand Down
80 changes: 47 additions & 33 deletions src/Perl6/Metamodel/RoleToRoleApplier.nqp
Expand Up @@ -49,50 +49,64 @@ my class RoleToRoleApplier {
if nqp::can($_.HOW, 'private_method_table');
}

# Also need methods of target.
# Also need methods of target, along with those it claims.
my %target_meth_info := $target.HOW.method_table($target);
my %target_claims;
if nqp::can($target.HOW, 'claims') {
for $target.HOW.claims($target) {
%target_claims{$_} := 1;
}
}

# Process method list.
for %meth_info {
# If the role claims the method name in question, then we ignore all
# methods provided by other roles and just take it.
my $name := $_.key;
my @add_meths := %meth_info{$name};
next if nqp::existskey(%target_claims, $name);

# Do we already have a method of this name? If so, ignore all of the
# methods we have from elsewhere.
unless nqp::existskey(%target_meth_info, $name) {
# No methods in the target role. If only one, it's easy...
if +@add_meths == 1 {
$target.HOW.add_method($target, $name, @add_meths[0]);
}
else {
# Find if any of the methods are actually requirements, not
# implementations.
my @impl_meths;
for @add_meths {
my $yada := 0;
try { $yada := $_.yada; }
unless $yada {
@impl_meths.push($_);
}
}

# If there's still more than one possible - add to collisions list.
# If we got down to just one, add it. If they were all requirements,
# just choose one.
if +@impl_meths == 1 {
$target.HOW.add_method($target, $name, @impl_meths[0]);
}
elsif +@impl_meths == 0 {
$target.HOW.add_method($target, $name, @add_meths[0]);
}
else {
$target.HOW.add_collision($target, $name, %meth_providers{$name});
}
# Get methods roles want to provide and filter out requirements.
my @add_meths := %meth_info{$name};
my @impl_meths;
for @add_meths {
my $yada := 0;
try { $yada := $_.yada; }
unless $yada {
@impl_meths.push($_);
}
}

# If the target role has a method with the name...
if nqp::existskey(%target_meth_info, $name) {
# No implementations from composed roles means nothing to do,
# as there's no conflict (we maybe satisfied a requirement).
next unless @impl_meths;

# Otherwise, add the target method into the add set, so we
# can record the conflict.
nqp::push(@impl_meths, %target_meth_info{$name});
nqp::push(%meth_providers{$name}, $target.HOW.name($target));
}

# If we've only one implementation, add it.
if +@impl_meths == 1 {
$target.HOW.add_method($target, $name, @impl_meths[0]);
}

# Otherwise, we may have no implementations at all, in which case
# pick any of the stubs.
elsif +@impl_meths == 0 {
$target.HOW.add_method($target, $name, @add_meths[0]);
}

# Otherwise a collision.
else {
$target.HOW.add_collision($target, $name, %meth_providers{$name});
}
}

# Process private method list.
# XXX Needs updates for claims-based algorithm.
if nqp::can($target.HOW, 'private_method_table') {
my %target_priv_meth_info := $target.HOW.private_method_table($target);
for %priv_meth_info {
Expand Down

0 comments on commit 3946ec8

Please sign in to comment.