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