1. # Method that we have on enumeration types.
  2. my role Enumeration {
  3. has $.key;
  4. has $.value;
  5. method enums() { self.^enum_values.Map }
  6. multi method kv(::?CLASS:D:) { ($!key, $!value) }
  7. method pair(::?CLASS:D:) { $!key => $!value }
  8. multi method gist(::?CLASS:D:) { $!key }
  9. multi method perl(::?CLASS:D:) { self.^name ~ '::' ~ $!key }
  10. multi method pick(::?CLASS:U:) { self.^enum_value_list.pick }
  11. multi method pick(::?CLASS:U: \n) { self.^enum_value_list.pick(n) }
  12. multi method pick(::?CLASS:D: *@pos) { self xx +?( @pos[0] // 1 ) }
  13. multi method roll(::?CLASS:U:) { self.^enum_value_list.roll }
  14. multi method roll(::?CLASS:U: \n) { self.^enum_value_list.roll(n) }
  15. multi method roll(::?CLASS:D: *@pos) { self xx +?( @pos[0] // 1 ) }
  16. multi method Numeric(::?CLASS:D:) { $!value.Numeric }
  17. multi method Int(::?CLASS:D:) { $!value.Int }
  18. # Make sure we always accept any element of the enumeration
  19. multi method ACCEPTS(::?CLASS:D: ::?CLASS:U $ --> True) { }
  20. multi method ACCEPTS(::?CLASS:D: ::?CLASS:D \v) { self === v }
  21. method CALL-ME(|) {
  22. my $x := nqp::atpos(nqp::p6argvmarray(), 1).AT-POS(0);
  23. nqp::istype($x, ::?CLASS)
  24. ?? $x
  25. !! self.^enum_from_value($x)
  26. }
  27. }
  28. # Methods that we also have if the base type of an enumeration is
  29. # Numeric.
  30. my role NumericEnumeration {
  31. multi method Str(::?CLASS:D:) {
  32. self.key
  33. }
  34. }
  35. my role StringyEnumeration {
  36. multi method Str(::?CLASS:D:) {
  37. self.value
  38. }
  39. }
  40. sub ENUM_VALUES(*@args) {
  41. my Mu $prev = -1;
  42. my %res;
  43. for @args {
  44. if .^isa(Pair) {
  45. %res{.key} = $prev = .value;
  46. }
  47. else {
  48. %res{$_} = $prev.=succ;
  49. }
  50. }
  51. nqp::p6bindattrinvres(
  52. nqp::create(Map),Map,'$!storage',nqp::getattr(%res,Map,'$!storage')
  53. )
  54. }
  55. Metamodel::EnumHOW.set_composalizer(-> $type, $name, %enum_values {
  56. my Mu $r := Metamodel::ParametricRoleHOW.new_type(:name($name));
  57. $r.^add_attribute(Attribute.new(
  58. :name('$!' ~ $name), :type(nqp::decont($type)),
  59. :has_accessor(1), :package($r)));
  60. for %enum_values.kv -> $key, $value {
  61. my $meth = method () { self."$name"() == $value }
  62. $meth.set_name($key);
  63. $r.^add_method($key, $meth);
  64. }
  65. $r.^set_body_block( -> |c {nqp::list($r,nqp::hash('$?CLASS',c<$?CLASS>))});
  66. $r.^compose;
  67. $r
  68. });