11// @ts -nocheck So many errors that the suppressions hamper readability.
22// TODO parameterize MatchHelper which will solve most of them
3+ /* eslint-disable no-continue */
34import harden from '@endo/harden' ;
45import {
56 q ,
@@ -1321,12 +1322,13 @@ const makePatternKit = () => {
13211322 } ) ;
13221323
13231324 /**
1324- * @param {CopyArray } elements
1325+ * @template {Passable} [T=Passable]
1326+ * @param {CopyArray<T> } elements
13251327 * @param {Pattern } elementPatt
13261328 * @param {bigint } bound Must be >= 1n
13271329 * @param {Rejector } reject
1328- * @param {CopyArray } [inResults]
1329- * @param {CopyArray } [outResults]
1330+ * @param {T[] } [inResults]
1331+ * @param {T[] } [outResults]
13301332 * @returns {boolean }
13311333 */
13321334 const confirmElementsHasSplit = (
@@ -1337,7 +1339,7 @@ const makePatternKit = () => {
13371339 inResults = undefined ,
13381340 outResults = undefined ,
13391341 ) => {
1340- let count = 0n ;
1342+ let inCount = 0n ;
13411343 // Since this feature is motivated by ERTP's use on
13421344 // non-fungible (`set`, `copySet`) amounts,
13431345 // their arrays store their elements in decending lexicographic order.
@@ -1347,22 +1349,19 @@ const makePatternKit = () => {
13471349 // decending. Thus we iterate `elements` in reverse order.
13481350 for ( let i = elements . length - 1 ; i >= 0 ; i -= 1 ) {
13491351 const element = elements [ i ] ;
1350- if ( count < bound ) {
1351- if ( matches ( element , elementPatt ) ) {
1352- count += 1n ;
1353- if ( inResults ) inResults . push ( element ) ;
1354- } else if ( outResults ) {
1355- outResults . push ( element ) ;
1356- }
1357- } else if ( outResults === undefined ) {
1358- break ;
1359- } else {
1352+ if ( inCount >= bound ) {
1353+ if ( ! outResults ) break ;
1354+ outResults . push ( element ) ;
1355+ } else if ( matches ( element , elementPatt ) ) {
1356+ inCount += 1n ;
1357+ if ( inResults ) inResults . push ( element ) ;
1358+ } else if ( outResults ) {
13601359 outResults . push ( element ) ;
13611360 }
13621361 }
13631362 return (
1364- count >= bound ||
1365- ( reject && reject `Has only ${ q ( count ) } matches, but needs ${ q ( bound ) } ` )
1363+ inCount >= bound ||
1364+ ( reject && reject `Has only ${ q ( inCount ) } matches, but needs ${ q ( bound ) } ` )
13661365 ) ;
13671366 } ;
13681367
@@ -1371,8 +1370,8 @@ const makePatternKit = () => {
13711370 * @param {Pattern } elementPatt
13721371 * @param {bigint } bound Must be >= 1n
13731372 * @param {Rejector } reject
1374- * @param {CopyArray< [Key, bigint]> } [inResults]
1375- * @param {CopyArray< [Key, bigint]> } [outResults]
1373+ * @param {[Key, bigint][] } [inResults]
1374+ * @param {[Key, bigint][] } [outResults]
13761375 * @returns {boolean }
13771376 */
13781377 const pairsHasSplit = (
@@ -1383,7 +1382,7 @@ const makePatternKit = () => {
13831382 inResults = undefined ,
13841383 outResults = undefined ,
13851384 ) => {
1386- let count = 0n ;
1385+ let inCount = 0n ;
13871386 // Since this feature is motivated by ERTP's use on
13881387 // semi-fungible (`copyBag`) amounts,
13891388 // their arrays store their elements in decending lexicographic order.
@@ -1393,44 +1392,49 @@ const makePatternKit = () => {
13931392 // decending. Thus we iterate `pairs` in reverse order.
13941393 for ( let i = pairs . length - 1 ; i >= 0 ; i -= 1 ) {
13951394 const [ element , num ] = pairs [ i ] ;
1396- const numRest = bound - count ;
1397- if ( numRest >= 1n ) {
1398- if ( matches ( element , elementPatt ) ) {
1399- if ( num <= numRest ) {
1400- count += num ;
1401- if ( inResults ) inResults . push ( [ element , num ] ) ;
1402- } else {
1403- const numIn = numRest ;
1404- count += numIn ;
1405- if ( inResults ) inResults . push ( [ element , numRest ] ) ;
1406- if ( outResults ) outResults . push ( [ element , num - numRest ] ) ;
1407- }
1408- } else if ( outResults ) {
1409- outResults . push ( [ element , num ] ) ;
1410- }
1411- } else if ( outResults === undefined ) {
1412- break ;
1413- } else {
1395+ const stillNeeds = bound - inCount ;
1396+ if ( stillNeeds <= 0n ) {
1397+ if ( ! outResults ) break ;
1398+ outResults . push ( [ element , num ] ) ;
1399+ } else if ( matches ( element , elementPatt ) ) {
1400+ const isPartial = num > stillNeeds ;
1401+ const numTake = isPartial ? stillNeeds : num ;
1402+ inCount += numTake ;
1403+ if ( inResults ) inResults . push ( [ element , numTake ] ) ;
1404+ if ( isPartial && outResults ) outResults . push ( [ element , num - numTake ] ) ;
1405+ } else if ( outResults ) {
14141406 outResults . push ( [ element , num ] ) ;
14151407 }
14161408 }
14171409 return (
1418- count >= bound ||
1419- ( reject && reject `Has only ${ q ( count ) } matches, but needs ${ q ( bound ) } ` )
1410+ inCount >= bound ||
1411+ ( reject && reject `Has only ${ q ( inCount ) } matches, but needs ${ q ( bound ) } ` )
14201412 ) ;
14211413 } ;
14221414
14231415 /**
1416+ * Confirms that `specimen` contains at least `bound` instances of an element
1417+ * matched by `elementPatt`, optionally returning those bounded matches and/or
1418+ * their complement as specified by `needInResults` and `needOutResults`
1419+ * (ensuring for CopyBags that at most one Key is split across both, but
1420+ * otherwise making no guarantee regarding the order in which elements are
1421+ * considered beyond a best-effort attempt to align with intuition).
1422+ * If the specimen does not contain enough matching instances, this function
1423+ * terminates as directed by `reject` (i.e., either returning `false` or
1424+ * throwing an error).
1425+ *
14241426 * @typedef {CopyArray | CopySet | CopyBag } Container
14251427 * @param {Container } specimen
14261428 * @param {Pattern } elementPatt
14271429 * @param {bigint } bound Must be >= 1n
14281430 * @param {Rejector } reject
1429- * @param {boolean } [needInResults]
1430- * @param {boolean } [needOutResults]
1431- * @returns {[Container | undefined, Container | undefined] | false }
1431+ * @param {boolean } [needInResults] collect and return matches inside a
1432+ * container of the same shape as `specimen`
1433+ * @param {boolean } [needOutResults] collect and return rejects inside a
1434+ * container of the same shape as `specimen`
1435+ * @returns {[matches: Container | undefined, discards: Container | undefined] | false }
14321436 */
1433- const confirmContainerHasSplit = (
1437+ const containerHasSplit = (
14341438 specimen ,
14351439 elementPatt ,
14361440 bound ,
@@ -1443,56 +1447,48 @@ const makePatternKit = () => {
14431447 const kind = kindOf ( specimen ) ;
14441448 switch ( kind ) {
14451449 case 'copyArray' : {
1446- if (
1447- ! confirmElementsHasSplit (
1450+ return (
1451+ confirmElementsHasSplit (
14481452 specimen ,
14491453 elementPatt ,
14501454 bound ,
14511455 reject ,
14521456 inResults ,
14531457 outResults ,
1454- )
1455- ) {
1456- // check logic already performed by confirmContainerHasSplit
1457- return false ;
1458- }
1459- return [ inResults , outResults ] ;
1458+ ) && harden ( [ inResults , outResults ] )
1459+ ) ;
14601460 }
14611461 case 'copySet' : {
1462- if (
1463- ! confirmElementsHasSplit (
1462+ return (
1463+ confirmElementsHasSplit (
14641464 specimen . payload ,
14651465 elementPatt ,
14661466 bound ,
14671467 reject ,
14681468 inResults ,
14691469 outResults ,
1470- )
1471- ) {
1472- return false ;
1473- }
1474- return [
1475- inResults && makeCopySet ( inResults ) ,
1476- outResults && makeCopySet ( outResults ) ,
1477- ] ;
1470+ ) &&
1471+ harden ( [
1472+ inResults && makeCopySet ( inResults ) ,
1473+ outResults && makeCopySet ( outResults ) ,
1474+ ] )
1475+ ) ;
14781476 }
14791477 case 'copyBag' : {
1480- if (
1481- ! pairsHasSplit (
1478+ return (
1479+ pairsHasSplit (
14821480 specimen . payload ,
14831481 elementPatt ,
14841482 bound ,
14851483 reject ,
14861484 inResults ,
14871485 outResults ,
1488- )
1489- ) {
1490- return false ;
1491- }
1492- return [
1493- inResults && makeCopyBag ( inResults ) ,
1494- outResults && makeCopyBag ( outResults ) ,
1495- ] ;
1486+ ) &&
1487+ harden ( [
1488+ inResults && makeCopyBag ( inResults ) ,
1489+ outResults && makeCopyBag ( outResults ) ,
1490+ ] )
1491+ ) ;
14961492 }
14971493 default : {
14981494 return reject && reject `unexpected ${ q ( kind ) } ` ;
@@ -1523,14 +1519,7 @@ const makePatternKit = () => {
15231519 ) {
15241520 return false ;
15251521 }
1526- return ! ! confirmContainerHasSplit (
1527- specimen ,
1528- elementPatt ,
1529- bound ,
1530- reject ,
1531- false ,
1532- false ,
1533- ) ;
1522+ return ! ! containerHasSplit ( specimen , elementPatt , bound , reject ) ;
15341523 } ,
15351524
15361525 confirmIsWellFormed : ( payload , reject ) =>
@@ -2064,7 +2053,7 @@ const makePatternKit = () => {
20642053 getRankCover,
20652054 M,
20662055 kindOf,
2067- containerHasSplit : confirmContainerHasSplit ,
2056+ containerHasSplit,
20682057 } ) ;
20692058} ;
20702059
0 commit comments