# This is the meta-object for an enumeration (declared with enum). # It keeps hold of the enumeration values in an Map, which is # created at composition time. It supports having roles composed in, # one or two of which presumably provide the core enum-ish methods. class Perl6::Metamodel::EnumHOW does Perl6::Metamodel::Naming does Perl6::Metamodel::Documenting does Perl6::Metamodel::LanguageRevision does Perl6::Metamodel::Stashing does Perl6::Metamodel::AttributeContainer does Perl6::Metamodel::MethodContainer does Perl6::Metamodel::PrivateMethodContainer does Perl6::Metamodel::MultiMethodContainer does Perl6::Metamodel::RoleContainer does Perl6::Metamodel::BaseType does Perl6::Metamodel::MROBasedMethodDispatch does Perl6::Metamodel::MROBasedTypeChecking does Perl6::Metamodel::BUILDPLAN does Perl6::Metamodel::BoolificationProtocol does Perl6::Metamodel::REPRComposeProtocol does Perl6::Metamodel::InvocationProtocol does Perl6::Metamodel::Mixins { # Hash representing enumeration keys to values. has %!values; # Reverse mapping hash. has $!value_to_enum; # List of enum values (actual enum objects). has @!enum_value_list; # Roles that we do. has @!role_typecheck_list; # Role'd version of the enum. has $!role; has int $!roled; # Are we composed yet? has $!composed; # Exportation callback for enum symbols, if any. has $!export_callback; my $archetypes := Perl6::Metamodel::Archetypes.new( :nominal(1), :composalizable(1), :augmentable(1) ); method archetypes($obj?) { $archetypes } method new(*%named) { nqp::findmethod(NQPMu, 'BUILDALL')(nqp::create(self), %named) } method new_type(:$name!, :$base_type?, :$repr = 'P6opaque', :$is_mixin) { my $meta := self.new(); my $obj := nqp::settypehll(nqp::newmixintype($meta, $repr), 'Raku'); $meta.set_name($obj, $name); $meta.set_base_type($meta, $base_type) unless $base_type =:= NQPMu; $meta.setup_mixin_cache($obj); self.add_stash($obj); } # We only have add_parent to support mixins, which expect this method. method add_parent($obj, $parent) { self.set_base_type($obj, $parent); } method add_enum_value($obj, $value) { %!values{nqp::unbox_s($value.key)} := $value.value; @!enum_value_list[+@!enum_value_list] := $value; nqp::scwbdisable(); $!value_to_enum := NQPMu; nqp::scwbenable(); } method set_export_callback($obj, $callback) { $!export_callback := $callback } method enum_values($obj) { %!values } method elems($obj) { nqp::elems(%!values) } method enum_from_value($obj, $value) { my $value_to_enum := $!value_to_enum; unless $value_to_enum { $value_to_enum := nqp::hash; for @!enum_value_list { $value_to_enum{$_.value} := $_; } nqp::scwbdisable(); $!value_to_enum := $value_to_enum; nqp::scwbenable(); } nqp::existskey($value_to_enum, $value) ?? $value_to_enum{$value} !! nqp::null() } method enum_value_list($obj) { @!enum_value_list } method compose($the-obj, :$compiler_services) { my $obj := nqp::decont($the-obj); self.set_language_version($obj); # Instantiate all of the roles we have (need to do this since # all roles are generic on ::?CLASS) and pass them to the # composer. my @roles_to_compose := self.roles_to_compose($obj); my $rtca; if @roles_to_compose { my @ins_roles; while @roles_to_compose { my $r := @roles_to_compose.pop(); @!role_typecheck_list[+@!role_typecheck_list] := $r; my $ins := $r.HOW.specialize($r, $obj); self.check-type-compat($obj, $ins, [3]) if nqp::istype($ins.HOW, Perl6::Metamodel::LanguageRevision); @ins_roles.push($ins); } $rtca := Perl6::Metamodel::Configuration.role_to_class_applier_type.new; $rtca.prepare($obj, @ins_roles); # Add them to the typecheck list, and pull in their # own type check lists also. for @ins_roles { @!role_typecheck_list[+@!role_typecheck_list] := $_; for $_.HOW.role_typecheck_list($_) { @!role_typecheck_list[+@!role_typecheck_list] := $_; } } } # Compose own attributes first. for self.attributes($obj, :local) { $_.compose($obj); } if $rtca { $rtca.apply(); } # Incorporate any new multi candidates (needs MRO built). self.incorporate_multi_candidates($obj); # Compose remaining attributes. for self.attributes($obj, :local) { $_.compose($obj); } # Publish type and method caches. self.publish_type_cache($obj); self.publish_method_cache($obj); # Publish boolification spec. self.publish_boolification_spec($obj); # Create BUILDPLAN. self.create_BUILDPLAN($obj); # Compose the representation. unless $!composed { self.compose_repr($obj); $!composed := 1; } #?if !moar # Compose invocation protocol. self.compose_invocation($obj); #?endif $obj } # Called by the compiler when all enum values have been added, to trigger # any needed actions. method compose_values($obj) { if $!export_callback { $!export_callback(); $!export_callback := Mu; } } my $composalizer; method set_composalizer($c) { $composalizer := $c } method composalize($obj) { unless $!roled { $!role := $composalizer($obj, self.name($obj), @!enum_value_list); $!roled := 1; } $!role } method is_composed($obj) { $!composed } method role_typecheck_list($obj) { @!role_typecheck_list } } # vim: expandtab sw=4