1. my class Pair { ... }
  2. my class Range { ... }
  3. my class X::Adverb { ... }
  4. my class X::Bind { ... }
  5. my class X::Bind::Slice { ... }
  6. my class X::Bind::ZenSlice { ... }
  7. my class X::Item { ... }
  8. my class X::Match::Bool { ... }
  9. my class X::Pairup::OddNumber { ... }
  10. my class X::Subscript::Negative { ... }
  11. my role Numeric { ... }
  12. my class Any { # declared in BOOTSTRAP
  13. # my class Any is Mu
  14. multi method ACCEPTS(Any:D: Mu:D \a) { self === a }
  15. multi method ACCEPTS(Any:D: Mu:U $ --> False) { }
  16. multi method ACCEPTS(Any:U: Any \topic) { # use of Any on topic to force autothreading
  17. nqp::p6bool(nqp::istype(topic, self)) # so that all(@foo) ~~ Type works as expected
  18. }
  19. proto method EXISTS-KEY(|) is nodal { * }
  20. multi method EXISTS-KEY(Any:U: $ --> False) { }
  21. multi method EXISTS-KEY(Any:D: $ --> False) { }
  22. proto method DELETE-KEY(|) is nodal { * }
  23. multi method DELETE-KEY(Any:U: $ --> Nil) { }
  24. multi method DELETE-KEY(Any:D: $) {
  25. Failure.new("Can not remove values from a {self.^name}")
  26. }
  27. proto method DELETE-POS(|) is nodal { * }
  28. multi method DELETE-POS(Any:U: $pos --> Nil) { }
  29. multi method DELETE-POS(Any:D: $pos) {
  30. Failure.new("Can not remove elements from a {self.^name}")
  31. }
  32. multi method DELETE-POS(Any:D: \one, \two) is raw {
  33. self.AT-POS(one).DELETE-POS(two)
  34. }
  35. multi method DELETE-POS(Any:D: \one, \two, \three) is raw {
  36. self.AT-POS(one).AT-POS(two).DELETE-POS(three)
  37. }
  38. multi method DELETE-POS(Any:D: **@indices) {
  39. my $final := @indices.pop;
  40. Rakudo::Internals.WALK-AT-POS(self,@indices).DELETE-POS($final)
  41. }
  42. method cache() { self.list }
  43. proto method list(|) is nodal { * }
  44. multi method list(Any:U:) { infix:<,>(self) }
  45. multi method list(Any:D \SELF:) { infix:<,>(SELF) }
  46. proto method flat(|) is nodal { * }
  47. multi method flat() { self.list.flat }
  48. proto method eager(|) is nodal { * }
  49. multi method eager() { self.list.eager }
  50. # derived from .list
  51. proto method List(|) is nodal { * }
  52. multi method List() { self.list }
  53. proto method Slip(|) is nodal { * }
  54. multi method Slip() { self.list.Slip }
  55. proto method Array(|) is nodal { * }
  56. multi method Array() { self.list.Array }
  57. proto method hash(|) is nodal { * }
  58. multi method hash(Any:U:) { my % = () }
  59. multi method hash(Any:D:) { my % = self }
  60. # derived from .hash
  61. proto method Hash(|) is nodal { * }
  62. multi method Hash() { self.hash.Hash }
  63. proto method Map(|) is nodal { * }
  64. multi method Map() { self.hash.Map }
  65. proto method elems(|) is nodal { * }
  66. multi method elems(Any:U: --> 1) { }
  67. multi method elems(Any:D:) { self.list.elems }
  68. proto method end(|) is nodal { * }
  69. multi method end(Any:U: --> 0) { }
  70. multi method end(Any:D:) { self.list.end }
  71. proto method keys(|) is nodal { * }
  72. multi method keys(Any:U:) { () }
  73. multi method keys(Any:D:) { self.list.keys }
  74. proto method kv(|) is nodal { * }
  75. multi method kv(Any:U:) { () }
  76. multi method kv(Any:D:) { self.list.kv }
  77. proto method values(|) is nodal { * }
  78. multi method values(Any:U:) { () }
  79. multi method values(Any:D:) { self.list }
  80. proto method pairs(|) is nodal { * }
  81. multi method pairs(Any:U:) { () }
  82. multi method pairs(Any:D:) { self.list.pairs }
  83. proto method antipairs(|) is nodal { * }
  84. multi method antipairs(Any:U:) { () }
  85. multi method antipairs(Any:D:) { self.list.antipairs }
  86. proto method invert(|) is nodal { * }
  87. multi method invert(Any:U:) { () }
  88. multi method invert(Any:D:) { self.list.invert }
  89. proto method pick(|) is nodal { * }
  90. multi method pick() { self.list.pick }
  91. multi method pick($n) { self.list.pick($n) }
  92. proto method roll(|) is nodal { * }
  93. multi method roll() { self.list.roll }
  94. multi method roll($n) { self.list.roll($n) }
  95. multi method iterator(Any:) { self.list.iterator }
  96. proto method match(|) { $/ := nqp::getlexcaller('$/'); {*} }
  97. multi method match(Any:U: |) { self.Str; nqp::getlexcaller('$/') = Nil }
  98. proto method classify(|) is nodal { * }
  99. multi method classify() {
  100. die "Must specify something to classify with, a Callable, Hash or List";
  101. }
  102. multi method classify(Whatever) {
  103. die "Doesn't make sense to classify with itself";
  104. }
  105. multi method classify($test, :$into!, :&as) {
  106. ( $into // $into.new ).classify-list( $test, self, :&as);
  107. }
  108. multi method classify($test, :&as) {
  109. Hash.^parameterize(Any,Any).new.classify-list( $test, self, :&as );
  110. }
  111. proto method categorize(|) is nodal { * }
  112. multi method categorize() {
  113. die "Must specify something to categorize with, a Callable, Hash or List";
  114. }
  115. multi method categorize(Whatever) {
  116. die "Doesn't make sense to categorize with itself";
  117. }
  118. multi method categorize($test, :$into!, :&as) {
  119. ( $into // $into.new ).categorize-list( $test, self.list, :&as );
  120. }
  121. multi method categorize($test, :&as) {
  122. Hash.^parameterize(Any,Any).new.categorize-list($test, self.list, :&as);
  123. }
  124. method reverse() is nodal { self.list.reverse }
  125. method combinations(|c) is nodal { self.list.combinations(|c) }
  126. method permutations(|c) is nodal { self.list.permutations(|c) }
  127. method join($separator = '') is nodal { self.list.join($separator) }
  128. # XXX GLR should move these
  129. method nodemap(&block) is nodal { nodemap(&block, self) }
  130. method duckmap(&block) is nodal { duckmap(&block, self) }
  131. method deepmap(&block) is nodal { deepmap(&block, self) }
  132. # XXX GLR Do we need tree post-GLR?
  133. proto method tree(|) is nodal { * }
  134. multi method tree(Any:U:) { self }
  135. multi method tree(Any:D:) {
  136. nqp::istype(self, Iterable)
  137. ?? self.map({ .tree }).item
  138. !! self
  139. }
  140. multi method tree(Any:D: Whatever ) { self.tree }
  141. multi method tree(Any:D: Int(Cool) $count) {
  142. nqp::istype(self, Iterable) && $count > 0
  143. ?? self.map({ .tree($count - 1) }).item
  144. !! self
  145. }
  146. multi method tree(Any:D: @ [&first, *@rest]) { self.tree(&first, |@rest); }
  147. multi method tree(Any:D: &first, *@rest) {
  148. nqp::istype(self, Iterable)
  149. ?? @rest ?? first(self.map({ .tree(|@rest) }))
  150. !! first(self)
  151. !! self
  152. }
  153. # auto-vivifying
  154. proto method push(|) is nodal {*}
  155. multi method push(Any:U \SELF: |values) {
  156. SELF = nqp::istype(SELF,Positional) ?? SELF.new !! Array.new;
  157. SELF.push(|values);
  158. }
  159. proto method append(|) is nodal { * }
  160. multi method append(Any:U \SELF: |values) {
  161. SELF = nqp::istype(SELF,Positional) ?? SELF.new !! Array.new;
  162. SELF.append(|values);
  163. }
  164. proto method unshift(|) is nodal { * }
  165. multi method unshift(Any:U \SELF: |values) {
  166. SELF = Array.new;
  167. SELF.unshift(|values);
  168. }
  169. proto method prepend(|) is nodal { * }
  170. multi method prepend(Any:U \SELF: |values) {
  171. SELF = Array.new;
  172. SELF.prepend(|values);
  173. }
  174. proto method EXISTS-POS(|) is nodal { * }
  175. multi method EXISTS-POS(Any:U: Any:D $ --> False) { }
  176. multi method EXISTS-POS(Any:U: Any:U $pos) {
  177. die "Cannot use '{$pos.^name}' as an index";
  178. }
  179. multi method EXISTS-POS(Any:D: int \pos) {
  180. nqp::p6bool(nqp::iseq_i(pos,0));
  181. }
  182. multi method EXISTS-POS(Any:D: Int:D \pos) {
  183. pos == 0;
  184. }
  185. multi method EXISTS-POS(Any:D: Num:D \pos) {
  186. X::Item.new(aggregate => self, index => pos).throw
  187. if nqp::isnanorinf(pos);
  188. self.AT-POS(nqp::unbox_i(pos.Int));
  189. pos == 0;
  190. }
  191. multi method EXISTS-POS(Any:D: Any:D \pos) {
  192. pos.Int == 0;
  193. }
  194. multi method EXISTS-POS(Any:D: Any:U \pos) {
  195. die "Cannot use '{pos.^name}' as an index";
  196. }
  197. multi method EXISTS-POS(Any:D: \one, \two) is raw {
  198. self.AT-POS(one).EXISTS-POS(two)
  199. }
  200. multi method EXISTS-POS(Any:D: \one, \two,\three) is raw {
  201. self.AT-POS(one).AT-POS(two).EXISTS-POS(three)
  202. }
  203. multi method EXISTS-POS(Any:D: **@indices) {
  204. my $final := @indices.pop;
  205. Rakudo::Internals.WALK-AT-POS(self,@indices).EXISTS-POS($final)
  206. }
  207. proto method AT-POS(|) is nodal {*}
  208. multi method AT-POS(Any:U \SELF: int \pos) is raw {
  209. nqp::p6bindattrinvres(
  210. my $scalar,
  211. Scalar,
  212. '$!whence',
  213. -> { nqp::if(
  214. nqp::isconcrete(SELF),
  215. SELF,
  216. (SELF = Array.new)
  217. ).BIND-POS(pos, $scalar)
  218. }
  219. )
  220. }
  221. multi method AT-POS(Any:U \SELF: Int:D \pos) is raw {
  222. nqp::p6bindattrinvres(
  223. my $scalar,
  224. Scalar,
  225. '$!whence',
  226. -> { nqp::if(
  227. nqp::isconcrete(SELF),
  228. SELF,
  229. (SELF = Array.new)
  230. ).BIND-POS(pos, $scalar)
  231. }
  232. )
  233. }
  234. multi method AT-POS(Any:U: Num:D \pos) is raw {
  235. nqp::isnanorinf(pos)
  236. ?? Failure.new(X::Item.new(aggregate => self, index => pos))
  237. !! self.AT-POS(nqp::unbox_i(pos.Int))
  238. }
  239. multi method AT-POS(Any:U: Any:D \pos) is raw {
  240. self.AT-POS(nqp::unbox_i(pos.Int));
  241. }
  242. multi method AT-POS(Any:D: int \pos) is raw {
  243. pos
  244. ?? Failure.new(X::OutOfRange.new(
  245. :what($*INDEX // 'Index'), :got(pos), :range<0..0>))
  246. !! self
  247. }
  248. multi method AT-POS(Any:D: Int:D \pos) is raw {
  249. pos
  250. ?? Failure.new(X::OutOfRange.new(
  251. :what($*INDEX // 'Index'), :got(pos), :range<0..0>))
  252. !! self
  253. }
  254. multi method AT-POS(Any:D: Num:D \pos) is raw {
  255. nqp::isnanorinf(pos)
  256. ?? Failure.new(X::Item.new(aggregate => self, index => pos))
  257. !! self.AT-POS(nqp::unbox_i(pos.Int))
  258. }
  259. multi method AT-POS(Any:D: Any:D \pos) is raw {
  260. self.AT-POS(nqp::unbox_i(pos.Int));
  261. }
  262. multi method AT-POS(Any: Any:U \pos) is raw {
  263. die "Cannot use '{pos.^name}' as an index";
  264. }
  265. multi method AT-POS(Any:D: \one, \two) is raw {
  266. self.AT-POS(one).AT-POS(two)
  267. }
  268. multi method AT-POS(Any:D: \one, \two, \three) is raw {
  269. self.AT-POS(one).AT-POS(two).AT-POS(three)
  270. }
  271. multi method AT-POS(Any:D: **@indices) is raw {
  272. my $final := @indices.pop;
  273. Rakudo::Internals.WALK-AT-POS(self,@indices).AT-POS($final)
  274. }
  275. proto method ZEN-POS(|) { * }
  276. multi method ZEN-POS(*%unexpected) {
  277. %unexpected
  278. ?? Failure.new(X::Adverb.new(
  279. :what('[] slice'),
  280. :source(try { self.VAR.name } // self.WHAT.perl),
  281. :unexpected(%unexpected.keys)))
  282. !! self
  283. }
  284. proto method ZEN-KEY(|) { * }
  285. multi method ZEN-KEY(*%unexpected) {
  286. %unexpected
  287. ?? Failure.new(X::Adverb.new(
  288. :what('{} slice'),
  289. :source(try { self.VAR.name } // self.WHAT.perl),
  290. :unexpected(%unexpected.keys)))
  291. !! self
  292. }
  293. proto method ASSIGN-POS(|) is nodal { * }
  294. multi method ASSIGN-POS(Any:U \SELF: \pos, Mu \assignee) {
  295. SELF.AT-POS(pos) = assignee; # defer < 0 check
  296. }
  297. multi method ASSIGN-POS(Any:D: int \pos, Mu \assignee) {
  298. self.AT-POS(pos) = assignee; # defer < 0 check
  299. }
  300. multi method ASSIGN-POS(Any:D: Int:D \pos, Mu \assignee) {
  301. self.AT-POS(pos) = assignee; # defer < 0 check
  302. }
  303. multi method ASSIGN-POS(Any:D: Num:D \pos, Mu \assignee) {
  304. nqp::isnanorinf(pos)
  305. ?? Failure.new(X::Item.new(aggregate => self, index => pos))
  306. !! self.AT-POS(nqp::unbox_i(pos.Int)) = assignee; # defer < 0 check
  307. }
  308. multi method ASSIGN-POS(Any:D: Any:D \pos, Mu \assignee) {
  309. self.AT-POS(nqp::unbox_i(pos.Int)) = assignee; # defer < 0 check
  310. }
  311. multi method ASSIGN-POS(Any:D: Any:U \pos, Mu \assignee) {
  312. die "Cannot use '{pos.^name}' as an index";
  313. }
  314. multi method ASSIGN-POS(Any:D: \one, \two, Mu \assignee) is raw {
  315. self.AT-POS(one).ASSIGN-POS(two, assignee)
  316. }
  317. multi method ASSIGN-POS(Any:D: \one, \two, \three, Mu \assignee) is raw {
  318. self.AT-POS(one).AT-POS(two).ASSIGN-POS(three, assignee)
  319. }
  320. multi method ASSIGN-POS(Any:D: **@indices) {
  321. my \value := @indices.pop;
  322. my $final := @indices.pop;
  323. Rakudo::Internals.WALK-AT-POS(self,@indices).ASSIGN-POS($final,value)
  324. }
  325. proto method BIND-POS(|) { * }
  326. multi method BIND-POS(Any:D: **@indices is raw) is raw {
  327. # looks like Array.pop doesn't really return a bindable container
  328. # my \value := @indices.pop;
  329. # my $final := @indices.pop;
  330. # Rakudo::Internals.WALK-AT-POS(self,@indices).BIND-POS($final,value)
  331. my int $elems = @indices.elems; # reifies
  332. my \value := @indices.AT-POS(--$elems);
  333. my $final := @indices.AT-POS(--$elems);
  334. my $target := self;
  335. my int $i = -1;
  336. $target := $target.AT-POS(@indices.AT-POS($i))
  337. while nqp::islt_i(++$i,$elems);
  338. X::Bind.new.throw if $target =:= self;
  339. $target.BIND-POS($final, value)
  340. }
  341. method all() is nodal { Junction.new("all", self) }
  342. method any() is nodal { Junction.new("any", self) }
  343. method one() is nodal { Junction.new("one", self) }
  344. method none() is nodal { Junction.new("none",self) }
  345. # internals
  346. proto method AT-KEY(|) is nodal { * }
  347. multi method AT-KEY(Any:D: $key) is raw {
  348. Failure.new( self ~~ Associative
  349. ?? "Associative indexing implementation missing from type {self.WHAT.perl}"
  350. !! "Type {self.WHAT.perl} does not support associative indexing."
  351. )
  352. }
  353. multi method AT-KEY(Any:U \SELF: \key) is raw {
  354. nqp::p6bindattrinvres(
  355. my $scalar,
  356. Scalar,
  357. '$!whence',
  358. -> { nqp::if(
  359. nqp::isconcrete(SELF),
  360. SELF,
  361. (SELF = Hash.new)
  362. ).BIND-KEY(key, $scalar)
  363. }
  364. )
  365. }
  366. proto method BIND-KEY(|) is nodal { * }
  367. multi method BIND-KEY(Any:D: \k, \v) is raw {
  368. Failure.new(X::Bind.new(target => self.^name))
  369. }
  370. multi method BIND-KEY(Any:U \SELF: $key, $BIND ) is raw {
  371. SELF = Hash.new;
  372. SELF.BIND-KEY($key, $BIND);
  373. $BIND
  374. }
  375. proto method ASSIGN-KEY(|) is nodal { * }
  376. multi method ASSIGN-KEY(\SELF: \key, Mu \assignee) is raw {
  377. SELF.AT-KEY(key) = assignee;
  378. }
  379. # XXX GLR review these
  380. method FLATTENABLE_LIST() is nodal {
  381. my $list := self.list;
  382. nqp::findmethod($list, 'FLATTENABLE_LIST')($list);
  383. }
  384. method FLATTENABLE_HASH() is nodal { nqp::hash() }
  385. # XXX GLR do these really need to force a list?
  386. method Set() is nodal { Set.new-from-pairs(self.list) }
  387. method SetHash() is nodal { SetHash.new-from-pairs(self.list) }
  388. method Bag() is nodal { Bag.new-from-pairs(self.list) }
  389. method BagHash() is nodal { BagHash.new-from-pairs(self.list) }
  390. method Mix() is nodal { Mix.new-from-pairs(self.list) }
  391. method MixHash() is nodal { MixHash.new-from-pairs(self.list) }
  392. method Supply() is nodal { self.list.Supply }
  393. method nl-out() { "\n" }
  394. method print-nl() { self.print(self.nl-out) }
  395. method lazy-if($flag) { self } # no-op on non-Iterables
  396. method sum() is nodal {
  397. my \iter = self.iterator;
  398. my $sum = 0;
  399. my Mu $value;
  400. nqp::until(
  401. nqp::eqaddr(($value := iter.pull-one),IterationEnd),
  402. ($sum = $sum + $value)
  403. );
  404. $sum;
  405. }
  406. }
  407. Metamodel::ClassHOW.exclude_parent(Any);
  408. # builtin ops
  409. proto sub infix:<===>(Mu $?, Mu $?) is pure { * }
  410. multi sub infix:<===>($?) { Bool::True }
  411. multi sub infix:<===>(\a, \b) {
  412. nqp::p6bool(
  413. nqp::eqaddr(a,b)
  414. || (nqp::eqaddr(a.WHAT,b.WHAT)
  415. && nqp::iseq_s(nqp::unbox_s(a.WHICH), nqp::unbox_s(b.WHICH)))
  416. )
  417. }
  418. proto sub infix:<before>(Mu $?, Mu $?) is pure { * }
  419. multi sub infix:<before>($?) { Bool::True }
  420. multi sub infix:<before>(\a, \b) { (a cmp b) < 0 }
  421. proto sub infix:<after>(Mu $?, Mu $?) is pure { * }
  422. multi sub infix:<after>($x?) { Bool::True }
  423. multi sub infix:<after>(\a, \b) { (a cmp b) > 0 }
  424. proto prefix:<++>(Mu) { * }
  425. multi prefix:<++>(Mu:D $a is rw) { $a = $a.succ }
  426. multi prefix:<++>(Mu:U $a is rw) { $a = 1 }
  427. proto prefix:<-->(Mu) { * }
  428. multi prefix:<-->(Mu:D $a is rw) { $a = $a.pred }
  429. multi prefix:<-->(Mu:U $a is rw) { $a = -1 }
  430. proto postfix:<++>(Mu) { * }
  431. multi postfix:<++>(Mu:D $a is rw) { my $b = $a; $a = $a.succ; $b }
  432. multi postfix:<++>(Mu:U $a is rw) { $a = 1; 0 }
  433. proto postfix:<-->(Mu) { * }
  434. multi postfix:<-->(Mu:D $a is rw) { my $b = $a; $a = $a.pred; $b }
  435. multi postfix:<-->(Mu:U $a is rw) { $a = -1; 0 }
  436. proto sub pick(|) { * }
  437. multi sub pick($n, +values) { values.pick($n) }
  438. proto sub roll(|) { * }
  439. multi sub roll($n, +values) { values.roll($n) }
  440. proto sub keys(|) { * }
  441. multi sub keys($x) { $x.keys }
  442. proto sub values(|) { * }
  443. multi sub values($x) { $x.values }
  444. proto sub pairs(|) { * }
  445. multi sub pairs($x) { $x.pairs }
  446. proto sub kv(|) { * }
  447. multi sub kv($x) { $x.kv }
  448. proto sub elems(|) is nodal { * }
  449. multi sub elems($a) { $a.elems }
  450. proto sub end(|) { * }
  451. multi sub end($a) { $a.end }
  452. proto sub sum(|) {*}
  453. multi sub sum() { 0 }
  454. multi sub sum(\SELF) { SELF.sum }
  455. multi sub sum(+SELF) { SELF.sum }
  456. sub classify( $test, +items, *%named ) {
  457. if %named.EXISTS-KEY("into") {
  458. my $into := %named.DELETE-KEY("into");
  459. ( $into // $into.new).classify-list($test, items, |%named);
  460. }
  461. else {
  462. Hash.^parameterize(Any,Any).new.classify-list($test, items, |%named);
  463. }
  464. }
  465. sub categorize( $test, +items, *%named ) {
  466. if %named.EXISTS-KEY("into") {
  467. my $into := %named.DELETE-KEY("into");
  468. ( $into // $into.new).categorize-list($test, items, |%named);
  469. }
  470. else {
  471. Hash.^parameterize(Any,Any).new.categorize-list($test, items, |%named);
  472. }
  473. }
  474. proto sub item(|) is pure { * }
  475. multi sub item(\x) { my $ = x }
  476. multi sub item(|c) { my $ = c.list }
  477. multi sub item(Mu $a) { $a }
  478. sub SLICE_HUH(\SELF, @nogo, %d, %adv) {
  479. @nogo.unshift('delete') # recover any :delete if necessary
  480. if @nogo && @nogo[0] ne 'delete' && %adv.EXISTS-KEY('delete');
  481. for <delete exists kv p k v> -> $valid { # check all valid params
  482. if nqp::existskey(%d,nqp::unbox_s($valid)) {
  483. nqp::deletekey(%d,nqp::unbox_s($valid));
  484. @nogo.push($valid);
  485. }
  486. }
  487. Failure.new(X::Adverb.new(
  488. :what<slice>,
  489. :source(try { SELF.VAR.name } // SELF.WHAT.perl),
  490. :unexpected(%d.keys),
  491. :nogo(@nogo),
  492. ))
  493. } #SLICE_HUH
  494. sub DELETEKEY(Mu \d, str $key) {
  495. nqp::if(
  496. nqp::existskey(d,$key),
  497. nqp::stmts(
  498. (my Mu $value := nqp::atkey(d,$key)),
  499. (nqp::deletekey(d,$key)),
  500. $value
  501. ),
  502. Nil
  503. )
  504. } #DELETEKEY
  505. sub dd(|) {
  506. my Mu $args := nqp::p6argvmarray();
  507. if nqp::elems($args) {
  508. while $args {
  509. my $var := nqp::shift($args);
  510. my $name := try $var.VAR.?name;
  511. my $type := $var.WHAT.^name;
  512. my $what := $var.?is-lazy
  513. ?? $var[^10].perl.chop ~ "... lazy list)"
  514. !! $var.perl;
  515. note $name ?? "$type $name = $what" !! $what;
  516. }
  517. }
  518. else { # tell where we are
  519. note .name ?? "{lc .^name} {.name}" !! "({lc .^name})"
  520. with callframe(1).code;
  521. }
  522. return
  523. }