class Perl6::Metamodel::DefiniteHOW does Perl6::Metamodel::Documenting does Perl6::Metamodel::Nominalizable { # ATypeN are used as parameterization arguments to have a definite report correct archetypes. my class ArchetypeDefinite { my $type := Perl6::Metamodel::Archetypes.new(:definite, :nominalizable, :!coercive, :!generic); method archetype() { $type } } my class ArchetypeDefiniteGeneric { my $type := Perl6::Metamodel::Archetypes.new(:definite, :nominalizable, :!coercive, :generic); method archetype() { $type } } my class ArchetypeDefiniteCoercive { my $type := Perl6::Metamodel::Archetypes.new(:definite, :nominalizable, :coercive, :!generic); method archetype() { $type } } my class ArchetypeDefiniteCoerciveGeneric { my $type := Perl6::Metamodel::Archetypes.new(:definite, :nominalizable, :coercive, :generic); method archetype() { $type } } my @archetypes := nqp::list(ArchetypeDefinite, ArchetypeDefiniteGeneric, ArchetypeDefiniteCoercive, ArchetypeDefiniteCoerciveGeneric); method archetypes($definite_type = nqp::null()) { nqp::isnull($definite_type) ?? ArchetypeDefinite.archetype() !! nqp::typeparameterat(nqp::decont($definite_type), 2).archetype() } #~ has @!mro; my class Definite { } my class NotDefinite { } method new_type(:$base_type!, :$definite!) { my $base_archetypes := $base_type.HOW.archetypes($base_type); # Use generic and coercive as positional bits to form a numeric suffix for 'ATypeN' names. my $atype := @archetypes[ nqp::bitor_i( nqp::bitshiftl_i(nqp::istrue($base_archetypes.coercive), 1), nqp::istrue($base_archetypes.generic))]; my $root := nqp::parameterizetype((Perl6::Metamodel::DefiniteHOW.WHO), [$base_type, $definite ?? Definite !! NotDefinite, $atype]); nqp::setdebugtypename($root, self.name($root)); } method name($definite_type) { if nqp::isnull(nqp::typeparameterized($definite_type)) { '?:?' } else { my $base_type := nqp::typeparameterat($definite_type, 0); my $definite := nqp::typeparameterat($definite_type, 1); $base_type.HOW.name($base_type) ~ ':' ~ (nqp::eqaddr($definite, Definite) ?? 'D' !! 'U') } } method shortname($definite_type) { if nqp::isnull(nqp::typeparameterized($definite_type)) { '?:?' } else { my $base_type := nqp::typeparameterat($definite_type, 0); my $definite := nqp::typeparameterat($definite_type, 1); $base_type.HOW.shortname($base_type) ~ ':' ~ (nqp::eqaddr($definite, Definite) ?? 'D' !! 'U') } } sub check_instantiated($definite_type) { nqp::die('Cannot perform this operation on an uninstantiated definite type') if nqp::isnull(nqp::typeparameterized($definite_type)); } method base_type($definite_type) { check_instantiated($definite_type); nqp::typeparameterat($definite_type, 0) } method definite($definite_type) { check_instantiated($definite_type); nqp::eqaddr(nqp::typeparameterat($definite_type, 1), Definite) ?? 1 !! 0 } method nominalize($obj) { my $base_type := $obj.HOW.base_type($obj); $base_type.HOW.archetypes($base_type).nominalizable ?? $base_type.HOW.nominalize($base_type) !! $base_type } method instantiate_generic($definite_type, $type_env) { my $base_type := $definite_type.HOW.base_type($definite_type); return $definite_type unless $base_type.HOW.archetypes($base_type).generic; self.new_type( base_type => $base_type.HOW.instantiate_generic($base_type, $type_env), definite => $definite_type.HOW.definite($definite_type)) } #~ # Should have the same methods of the base type that we refine. #~ # (For the performance win, work out a way to steal its method cache.) method find_method($definite_type, $name, *%c) { my $base_type := self.base_type($definite_type); $base_type.HOW.find_method($base_type, $name, |%c) } method find_method_qualified($definite_type, $qtype, $name) { my $base_type := self.base_type($definite_type); $base_type.HOW.find_method_qualified($base_type, $qtype, $name) } # Do check when we're on LHS of smartmatch (e.g. Even ~~ Int). method type_check($definite_type, $checkee) { my $base_type := self.base_type($definite_type); nqp::hllboolfor(nqp::istype($base_type, $checkee), "Raku") } # Here we check the value itself (when on RHS on smartmatch). method accepts_type($definite_type, $checkee) { my $base_type := self.base_type($definite_type); my $definite := self.definite($definite_type); nqp::hllboolfor( nqp::istype($checkee, $base_type) && nqp::isconcrete($checkee) == $definite, "Raku" ) } # Methods needed by Perl6::Metamodel::Nominalizable method nominalizable_kind() { 'definite' } method !wrappee($obj) { self.base_type($obj) } } BEGIN { my $root := nqp::newtype(Perl6::Metamodel::DefiniteHOW, 'Uninstantiable'); nqp::setdebugtypename(nqp::settypehll($root, 'Raku'), 'DefiniteHOW root'); nqp::setparameterizer($root, sub ($type, $params) { # Re-use same HOW. my $thing := nqp::settypehll(nqp::newtype($type.HOW, 'Uninstantiable'), 'Raku'); nqp::settypecheckmode($thing, 2) }); (Perl6::Metamodel::DefiniteHOW.WHO) := $root; } # vim: expandtab sw=4