1. my class Capture { # declared in BOOTSTRAP
  2. # class Capture is Any
  3. # has @!list; # positional parameters
  4. # has %!hash; # named parameters
  5. method new(:@list,:%hash) { self.bless(:@list,:%hash) }
  6. method from-args(|c) { c }
  7. submethod BUILD(:@list, :%hash --> Nil) {
  8. @list.elems; # force reification of all
  9. nqp::bindattr(self, Capture, '@!list',
  10. nqp::getattr(nqp::decont(@list.list), List, '$!reified')
  11. );
  12. nqp::bindattr(self,Capture,'%!hash',
  13. nqp::getattr(nqp::decont(%hash),Map,'$!storage'))
  14. if nqp::attrinited(nqp::decont(%hash),Map,'$!storage')
  15. }
  16. multi method WHICH (Capture:D:) {
  17. my $WHICH = nqp::istype(self.WHAT,Capture) ?? 'Capture' !! self.^name;
  18. if !nqp::isnull(@!list) && @!list {
  19. $WHICH ~= '|';
  20. for nqp::hllize(@!list) -> \elem {
  21. $WHICH ~= ( '(' ~ elem.VAR.WHICH ~ ')' )
  22. }
  23. }
  24. if !nqp::isnull(%!hash) && %!hash {
  25. $WHICH ~= '|';
  26. $WHICH ~= ( $_ ~ '(' ~ nqp::atkey(%!hash, nqp::unbox_s($_)).WHICH ~ ')' )
  27. for nqp::hllize(%!hash).keys.sort;
  28. }
  29. $WHICH;
  30. }
  31. multi method AT-KEY(Capture:D: Str:D \key) is raw {
  32. nqp::ifnull(nqp::atkey(%!hash,nqp::unbox_s(key)), Nil)
  33. }
  34. multi method AT-KEY(Capture:D: \key) is raw {
  35. nqp::ifnull(nqp::atkey(%!hash,nqp::unbox_s(key.Str)), Nil)
  36. }
  37. multi method AT-POS(Capture:D: int \pos) is raw {
  38. nqp::islt_i(pos,0)
  39. ?? Failure.new(X::OutOfRange.new(
  40. :what($*INDEX // 'Index'),:got(pos),:range<0..^Inf>))
  41. !! nqp::ifnull(nqp::atpos(@!list,pos),Nil)
  42. }
  43. multi method AT-POS(Capture:D: Int:D \pos) is raw {
  44. my int $pos = nqp::unbox_i(pos);
  45. nqp::islt_i($pos,0)
  46. ?? Failure.new(X::OutOfRange.new(
  47. :what($*INDEX // 'Index'),:got(pos),:range<0..^Inf>))
  48. !! nqp::ifnull(nqp::atpos(@!list,$pos),Nil)
  49. }
  50. method hash(Capture:D:) {
  51. nqp::if(
  52. (nqp::defined(%!hash) && nqp::elems(%!hash)),
  53. nqp::p6bindattrinvres(nqp::create(Map),Map,'$!storage',%!hash),
  54. nqp::create(Map)
  55. )
  56. }
  57. multi method EXISTS-KEY(Capture:D: Str:D \key ) {
  58. nqp::p6bool(nqp::existskey(%!hash, nqp::unbox_s(key)));
  59. }
  60. multi method EXISTS-KEY(Capture:D: \key ) {
  61. nqp::p6bool(nqp::existskey(%!hash, nqp::unbox_s(key.Str)));
  62. }
  63. method list(Capture:D:) {
  64. nqp::if(
  65. (nqp::defined(@!list) && nqp::elems(@!list)),
  66. nqp::p6bindattrinvres(nqp::create(List),List,'$!reified',@!list),
  67. nqp::create(List)
  68. )
  69. }
  70. method elems(Capture:D:) {
  71. nqp::isnull(@!list) ?? 0 !! nqp::p6box_i(nqp::elems(@!list))
  72. }
  73. multi method Str(Capture:D:) {
  74. my Mu $str := nqp::list_s();
  75. if @!list {
  76. my Mu $iter := nqp::iterator(@!list);
  77. nqp::push_s($str, nqp::unbox_s(nqp::shift($iter).Str)) while $iter;
  78. }
  79. if %!hash {
  80. my Mu $iter := nqp::iterator(%!hash);
  81. while $iter {
  82. my $kv := nqp::shift($iter);
  83. nqp::push_s($str, nqp::unbox_s((nqp::p6box_s(nqp::iterkey_s($kv)) => nqp::iterval($kv).Str).Str));
  84. }
  85. }
  86. nqp::p6box_s(nqp::join(' ', $str))
  87. }
  88. multi method gist(Capture:D:) { self.perl }
  89. multi method perl(Capture:D:) {
  90. my %hash := self.hash;
  91. if self.^name eq 'Capture' {
  92. "\\({
  93. join ', ',
  94. ((nqp::atpos(@!list, $_).perl for ^nqp::elems(@!list)) if @!list),
  95. %hash.sort.map( *.perl )
  96. })";
  97. } else {
  98. self.^name
  99. ~ '.new('
  100. ~ ( 'list => (' ~ (nqp::atpos(@!list, $_).perl for ^nqp::elems(@!list)).join(', ') ~ ',)' if @!list)
  101. ~ (', ' if +@!list and +%hash)
  102. ~ ( 'hash => {' ~ %hash.sort.map( *.perl ).join(', ') ~ '}' if +%hash)
  103. ~ ')';
  104. }
  105. }
  106. multi method Bool(Capture:D:) {
  107. nqp::p6bool(
  108. nqp::elems(@!list) || nqp::elems(%!hash)
  109. )
  110. }
  111. method Capture(Capture:D:) {
  112. self
  113. }
  114. multi method Numeric(Capture:D:) {
  115. self.elems
  116. }
  117. method FLATTENABLE_LIST() { @!list ?? @!list !! nqp::list() }
  118. method FLATTENABLE_HASH() { %!hash ?? %!hash !! nqp::hash() }
  119. multi method keys(Capture:D:) {
  120. (self.list.keys, self.hash.keys).flat;
  121. }
  122. multi method kv(Capture:D:) {
  123. (self.list.kv, self.hash.kv).flat;
  124. }
  125. multi method values(Capture:D:) {
  126. (self.list.values, self.hash.values).flat;
  127. }
  128. multi method pairs(Capture:D:) {
  129. (self.list.pairs, self.hash.pairs).flat;
  130. }
  131. multi method antipairs(Capture:D:) {
  132. (self.list.antipairs, self.hash.antipairs).flat;
  133. }
  134. }
  135. multi sub infix:<eqv>(Capture:D \a, Capture:D \b) {
  136. nqp::p6bool(
  137. nqp::eqaddr(a,b)
  138. || (nqp::eqaddr(a.WHAT,b.WHAT)
  139. && a.list eqv b.list && a.hash eqv b.hash)
  140. )
  141. }