@mojir/lits 2.2.4 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +1 -0
  2. package/dist/cli/cli.js +1264 -909
  3. package/dist/cli/src/Lits/Lits.d.ts +8 -2
  4. package/dist/cli/src/builtin/bindingNode.d.ts +2 -1
  5. package/dist/cli/src/builtin/interface.d.ts +3 -2
  6. package/dist/cli/src/builtin/modules/number-theory/sequences/index.d.ts +2 -1
  7. package/dist/cli/src/evaluator/functionExecutors.d.ts +2 -1
  8. package/dist/cli/src/evaluator/index.d.ts +3 -2
  9. package/dist/cli/src/evaluator/interface.d.ts +3 -2
  10. package/dist/cli/src/utils/maybePromise.d.ts +54 -0
  11. package/dist/full.esm.js +1 -1
  12. package/dist/full.esm.js.map +1 -1
  13. package/dist/full.js +1 -1
  14. package/dist/full.js.map +1 -1
  15. package/dist/index.esm.js +1 -1
  16. package/dist/index.esm.js.map +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/lits.iife.js +1 -1
  20. package/dist/lits.iife.js.map +1 -1
  21. package/dist/modules/assert.esm.js +1 -1
  22. package/dist/modules/assert.esm.js.map +1 -1
  23. package/dist/modules/assert.js +1 -1
  24. package/dist/modules/assert.js.map +1 -1
  25. package/dist/modules/collection.esm.js +1 -1
  26. package/dist/modules/collection.esm.js.map +1 -1
  27. package/dist/modules/collection.js +1 -1
  28. package/dist/modules/collection.js.map +1 -1
  29. package/dist/modules/grid.esm.js +1 -1
  30. package/dist/modules/grid.esm.js.map +1 -1
  31. package/dist/modules/grid.js +1 -1
  32. package/dist/modules/grid.js.map +1 -1
  33. package/dist/modules/number-theory.esm.js +1 -1
  34. package/dist/modules/number-theory.esm.js.map +1 -1
  35. package/dist/modules/number-theory.js +1 -1
  36. package/dist/modules/number-theory.js.map +1 -1
  37. package/dist/modules/sequence.esm.js +1 -1
  38. package/dist/modules/sequence.esm.js.map +1 -1
  39. package/dist/modules/sequence.js +1 -1
  40. package/dist/modules/sequence.js.map +1 -1
  41. package/dist/modules/src/Lits/Lits.d.ts +8 -2
  42. package/dist/modules/src/builtin/bindingNode.d.ts +2 -1
  43. package/dist/modules/src/builtin/interface.d.ts +3 -2
  44. package/dist/modules/src/builtin/modules/number-theory/sequences/index.d.ts +2 -1
  45. package/dist/modules/src/evaluator/functionExecutors.d.ts +2 -1
  46. package/dist/modules/src/evaluator/index.d.ts +3 -2
  47. package/dist/modules/src/evaluator/interface.d.ts +3 -2
  48. package/dist/modules/src/utils/maybePromise.d.ts +54 -0
  49. package/dist/modules/vector.esm.js +1 -1
  50. package/dist/modules/vector.esm.js.map +1 -1
  51. package/dist/modules/vector.js +1 -1
  52. package/dist/modules/vector.js.map +1 -1
  53. package/dist/src/Lits/Lits.d.ts +8 -2
  54. package/dist/src/builtin/bindingNode.d.ts +2 -1
  55. package/dist/src/builtin/interface.d.ts +3 -2
  56. package/dist/src/builtin/modules/number-theory/sequences/index.d.ts +2 -1
  57. package/dist/src/evaluator/functionExecutors.d.ts +2 -1
  58. package/dist/src/evaluator/index.d.ts +3 -2
  59. package/dist/src/evaluator/interface.d.ts +3 -2
  60. package/dist/src/utils/maybePromise.d.ts +54 -0
  61. package/dist/testFramework.esm.js +1 -1
  62. package/dist/testFramework.esm.js.map +1 -1
  63. package/dist/testFramework.js +1 -1
  64. package/dist/testFramework.js.map +1 -1
  65. package/package.json +1 -1
package/dist/cli/cli.js CHANGED
@@ -7,7 +7,7 @@ var readline = require('node:readline');
7
7
  var os = require('node:os');
8
8
  var process$1 = require('node:process');
9
9
 
10
- var version = "2.2.4";
10
+ var version = "2.3.0";
11
11
 
12
12
  function getCodeMarker(sourceCodeInfo) {
13
13
  if (!sourceCodeInfo.position || !sourceCodeInfo.code)
@@ -858,6 +858,200 @@ function assertCharArray(value, sourceCodeInfo) {
858
858
  throw getAssertionError('array of strings', value, sourceCodeInfo);
859
859
  }
860
860
 
861
+ /**
862
+ * MaybePromise utilities for transparent async support.
863
+ *
864
+ * The sync path stays zero-overhead — when no async JS functions are involved,
865
+ * everything runs synchronously with only `instanceof Promise` checks as overhead.
866
+ * When an async value is detected, the evaluation chain switches to Promise-based
867
+ * execution for the remainder.
868
+ */
869
+ /**
870
+ * Chain a value that might be a Promise. If the value is sync, calls fn synchronously.
871
+ * If it's a Promise, chains with .then().
872
+ */
873
+ function chain(value, fn) {
874
+ if (value instanceof Promise) {
875
+ return value.then(fn);
876
+ }
877
+ return fn(value);
878
+ }
879
+ /**
880
+ * Like Array.map but handles MaybePromise callbacks sequentially.
881
+ * In the sync case, runs as a simple loop. Switches to async only when needed.
882
+ */
883
+ function mapSequential(arr, fn) {
884
+ const results = [];
885
+ for (let i = 0; i < arr.length; i++) {
886
+ const result = fn(arr[i], i);
887
+ if (result instanceof Promise) {
888
+ return chainRemainingMap(result, results, arr, fn, i);
889
+ }
890
+ results.push(result);
891
+ }
892
+ return results;
893
+ }
894
+ async function chainRemainingMap(currentPromise, results, arr, fn, startIndex) {
895
+ results.push(await currentPromise);
896
+ for (let i = startIndex + 1; i < arr.length; i++) {
897
+ results.push(await fn(arr[i], i));
898
+ }
899
+ return results;
900
+ }
901
+ /**
902
+ * Like Array.reduce but handles MaybePromise callbacks sequentially.
903
+ * In the sync case, runs as a simple loop. Switches to async only when needed.
904
+ */
905
+ function reduceSequential(arr, fn, initial) {
906
+ let result = initial;
907
+ for (let i = 0; i < arr.length; i++) {
908
+ const next = fn(result, arr[i], i);
909
+ if (next instanceof Promise) {
910
+ return chainRemainingReduce(next, arr, fn, i);
911
+ }
912
+ result = next;
913
+ }
914
+ return result;
915
+ }
916
+ async function chainRemainingReduce(currentPromise, arr, fn, startIndex) {
917
+ let result = await currentPromise;
918
+ for (let i = startIndex + 1; i < arr.length; i++) {
919
+ result = await fn(result, arr[i], i);
920
+ }
921
+ return result;
922
+ }
923
+ /**
924
+ * Like Array.forEach but handles MaybePromise callbacks sequentially.
925
+ * In the sync case, runs as a simple loop. Switches to async only when needed.
926
+ */
927
+ function forEachSequential(arr, fn) {
928
+ for (let i = 0; i < arr.length; i++) {
929
+ const result = fn(arr[i], i);
930
+ if (result instanceof Promise) {
931
+ return chainRemainingForEach(result, arr, fn, i);
932
+ }
933
+ }
934
+ }
935
+ async function chainRemainingForEach(currentPromise, arr, fn, startIndex) {
936
+ await currentPromise;
937
+ for (let i = startIndex + 1; i < arr.length; i++) {
938
+ await fn(arr[i], i);
939
+ }
940
+ }
941
+ /**
942
+ * Try/catch that handles MaybePromise values correctly.
943
+ * If tryFn returns a Promise, catches both sync throws and Promise rejections.
944
+ */
945
+ function tryCatch(tryFn, catchFn) {
946
+ try {
947
+ const result = tryFn();
948
+ if (result instanceof Promise) {
949
+ return result.catch(catchFn);
950
+ }
951
+ return result;
952
+ }
953
+ catch (error) {
954
+ return catchFn(error);
955
+ }
956
+ }
957
+ /**
958
+ * Like Array.some but handles MaybePromise callbacks sequentially.
959
+ * Returns the first truthy MaybePromise result, or false.
960
+ */
961
+ function someSequential(arr, fn) {
962
+ for (let i = 0; i < arr.length; i++) {
963
+ const result = fn(arr[i], i);
964
+ if (result instanceof Promise) {
965
+ return chainRemainingSome(result, arr, fn, i);
966
+ }
967
+ if (result)
968
+ return true;
969
+ }
970
+ return false;
971
+ }
972
+ async function chainRemainingSome(currentPromise, arr, fn, startIndex) {
973
+ if (await currentPromise)
974
+ return true;
975
+ for (let i = startIndex + 1; i < arr.length; i++) {
976
+ if (await fn(arr[i], i))
977
+ return true;
978
+ }
979
+ return false;
980
+ }
981
+ /**
982
+ * Like Array.every but handles MaybePromise callbacks sequentially.
983
+ * Returns false as soon as a falsy result is found.
984
+ */
985
+ function everySequential(arr, fn) {
986
+ for (let i = 0; i < arr.length; i++) {
987
+ const result = fn(arr[i], i);
988
+ if (result instanceof Promise) {
989
+ return chainRemainingEvery(result, arr, fn, i);
990
+ }
991
+ if (!result)
992
+ return false;
993
+ }
994
+ return true;
995
+ }
996
+ async function chainRemainingEvery(currentPromise, arr, fn, startIndex) {
997
+ if (!await currentPromise)
998
+ return false;
999
+ for (let i = startIndex + 1; i < arr.length; i++) {
1000
+ if (!await fn(arr[i], i))
1001
+ return false;
1002
+ }
1003
+ return true;
1004
+ }
1005
+ /**
1006
+ * Like Array.filter but handles MaybePromise callbacks sequentially.
1007
+ * Returns the filtered array.
1008
+ */
1009
+ function filterSequential(arr, fn) {
1010
+ const results = [];
1011
+ for (let i = 0; i < arr.length; i++) {
1012
+ const result = fn(arr[i], i);
1013
+ if (result instanceof Promise) {
1014
+ return chainRemainingFilter(result, results, arr, fn, i);
1015
+ }
1016
+ if (result)
1017
+ results.push(arr[i]);
1018
+ }
1019
+ return results;
1020
+ }
1021
+ async function chainRemainingFilter(currentPromise, results, arr, fn, startIndex) {
1022
+ if (await currentPromise)
1023
+ results.push(arr[startIndex]);
1024
+ for (let i = startIndex + 1; i < arr.length; i++) {
1025
+ if (await fn(arr[i], i))
1026
+ results.push(arr[i]);
1027
+ }
1028
+ return results;
1029
+ }
1030
+ /**
1031
+ * Like Array.findIndex but handles MaybePromise callbacks sequentially.
1032
+ * Returns -1 if no element matches.
1033
+ */
1034
+ function findIndexSequential(arr, fn) {
1035
+ for (let i = 0; i < arr.length; i++) {
1036
+ const result = fn(arr[i], i);
1037
+ if (result instanceof Promise) {
1038
+ return chainRemainingFindIndex(result, arr, fn, i);
1039
+ }
1040
+ if (result)
1041
+ return i;
1042
+ }
1043
+ return -1;
1044
+ }
1045
+ async function chainRemainingFindIndex(currentPromise, arr, fn, startIndex) {
1046
+ if (await currentPromise)
1047
+ return startIndex;
1048
+ for (let i = startIndex + 1; i < arr.length; i++) {
1049
+ if (await fn(arr[i], i))
1050
+ return i;
1051
+ }
1052
+ return -1;
1053
+ }
1054
+
861
1055
  function mapObjects({ colls, contextStack, executeFunction, fn, sourceCodeInfo, }) {
862
1056
  assertObj(colls[0], sourceCodeInfo);
863
1057
  const keys = Object.keys(colls[0]);
@@ -877,10 +1071,13 @@ function mapObjects({ colls, contextStack, executeFunction, fn, sourceCodeInfo,
877
1071
  params[key].push(value);
878
1072
  });
879
1073
  });
880
- return keys.reduce((result, key) => {
881
- result[key] = executeFunction(fn, params[key], contextStack, sourceCodeInfo);
882
- return result;
883
- }, {});
1074
+ const initialObj = {};
1075
+ return reduceSequential(keys, (result, key) => {
1076
+ return chain(executeFunction(fn, params[key], contextStack, sourceCodeInfo), (value) => {
1077
+ result[key] = value;
1078
+ return result;
1079
+ });
1080
+ }, initialObj);
884
1081
  }
885
1082
  function get$1(coll, key) {
886
1083
  if (isObj(coll)) {
@@ -919,21 +1116,33 @@ const collectionNormalExpression = {
919
1116
  assertColl(coll, sourceCodeInfo);
920
1117
  assertFunctionLike(fn, sourceCodeInfo);
921
1118
  if (Array.isArray(coll)) {
922
- const result = coll.filter(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
923
- return result;
1119
+ return reduceSequential(coll, (result, elem) => {
1120
+ return chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), (keep) => {
1121
+ if (keep)
1122
+ result.push(elem);
1123
+ return result;
1124
+ });
1125
+ }, []);
924
1126
  }
925
1127
  if (isString(coll)) {
926
- return coll
927
- .split('')
928
- .filter(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo))
929
- .join('');
930
- }
931
- return Object.entries(coll)
932
- .filter(([, value]) => executeFunction(fn, [value], contextStack, sourceCodeInfo))
933
- .reduce((result, [key, value]) => {
934
- result[key] = value;
935
- return result;
936
- }, {});
1128
+ const chars = coll.split('');
1129
+ return chain(reduceSequential(chars, (result, elem) => {
1130
+ return chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), (keep) => {
1131
+ if (keep)
1132
+ result.push(elem);
1133
+ return result;
1134
+ });
1135
+ }, []), filtered => filtered.join(''));
1136
+ }
1137
+ const entries = Object.entries(coll);
1138
+ const initialObj = {};
1139
+ return reduceSequential(entries, (result, [key, value]) => {
1140
+ return chain(executeFunction(fn, [value], contextStack, sourceCodeInfo), (keep) => {
1141
+ if (keep)
1142
+ result[key] = value;
1143
+ return result;
1144
+ });
1145
+ }, initialObj);
937
1146
  },
938
1147
  arity: toFixedArity(2),
939
1148
  docs: {
@@ -996,12 +1205,14 @@ filter(
996
1205
  for (let i = 0; i < len; i++) {
997
1206
  paramArray.push(seqs.map(seq => seq[i]));
998
1207
  }
999
- const mapped = paramArray.map(p => executeFunction(fn, p, contextStack, sourceCodeInfo));
1208
+ const mapped = mapSequential(paramArray, p => executeFunction(fn, p, contextStack, sourceCodeInfo));
1000
1209
  if (!isStr) {
1001
1210
  return mapped;
1002
1211
  }
1003
- mapped.forEach(char => assertString(char, sourceCodeInfo));
1004
- return mapped.join('');
1212
+ return chain(mapped, (resolvedMapped) => {
1213
+ resolvedMapped.forEach(char => assertString(char, sourceCodeInfo));
1214
+ return resolvedMapped.join('');
1215
+ });
1005
1216
  },
1006
1217
  arity: { min: 2 },
1007
1218
  docs: {
@@ -1036,21 +1247,21 @@ filter(
1036
1247
  assertString(initial, sourceCodeInfo);
1037
1248
  if (coll.length === 0)
1038
1249
  return initial;
1039
- return coll.split('').reduce((result, elem) => {
1250
+ return reduceSequential(coll.split(''), (result, elem) => {
1040
1251
  return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
1041
1252
  }, initial);
1042
1253
  }
1043
1254
  else if (Array.isArray(coll)) {
1044
1255
  if (coll.length === 0)
1045
1256
  return initial;
1046
- return coll.reduce((result, elem) => {
1257
+ return reduceSequential(coll, (result, elem) => {
1047
1258
  return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
1048
1259
  }, initial);
1049
1260
  }
1050
1261
  else {
1051
1262
  if (Object.keys(coll).length === 0)
1052
1263
  return initial;
1053
- return Object.entries(coll).reduce((result, [, elem]) => {
1264
+ return reduceSequential(Object.entries(coll), (result, [, elem]) => {
1054
1265
  return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
1055
1266
  }, initial);
1056
1267
  }
@@ -1490,7 +1701,7 @@ flatten([
1490
1701
  evaluate: ([arr, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
1491
1702
  assertArray(arr, sourceCodeInfo);
1492
1703
  assertFunctionLike(fn, sourceCodeInfo);
1493
- return arr.map(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)).flat(1);
1704
+ return chain(mapSequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)), mapped => mapped.flat(1));
1494
1705
  },
1495
1706
  arity: toFixedArity(2),
1496
1707
  docs: {
@@ -1527,13 +1738,11 @@ mapcat(
1527
1738
  assertArray(arr, sourceCodeInfo);
1528
1739
  assertNumber(windowSize, sourceCodeInfo, { integer: true, lte: arr.length });
1529
1740
  assertFunctionLike(fn, sourceCodeInfo);
1530
- const result = [];
1741
+ const windows = [];
1531
1742
  for (let i = 0; i <= arr.length - windowSize; i++) {
1532
- const window = arr.slice(i, i + windowSize);
1533
- const value = executeFunction(fn, [window], contextStack, sourceCodeInfo);
1534
- result.push(value);
1743
+ windows.push(arr.slice(i, i + windowSize));
1535
1744
  }
1536
- return result;
1745
+ return mapSequential(windows, window => executeFunction(fn, [window], contextStack, sourceCodeInfo));
1537
1746
  },
1538
1747
  arity: toFixedArity(3),
1539
1748
  docs: {
@@ -1558,12 +1767,11 @@ mapcat(
1558
1767
  evaluate: ([arr, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
1559
1768
  assertArray(arr, sourceCodeInfo);
1560
1769
  assertFunctionLike(fn, sourceCodeInfo);
1561
- const result = [];
1770
+ const subArrays = [];
1562
1771
  for (let i = 0; i < arr.length; i += 1) {
1563
- const subArr = arr.slice(0, i + 1);
1564
- result.push(executeFunction(fn, [subArr], contextStack, sourceCodeInfo));
1772
+ subArrays.push(arr.slice(0, i + 1));
1565
1773
  }
1566
- return result;
1774
+ return mapSequential(subArrays, subArr => executeFunction(fn, [subArr], contextStack, sourceCodeInfo));
1567
1775
  },
1568
1776
  arity: toFixedArity(2),
1569
1777
  docs: {
@@ -1938,9 +2146,14 @@ For string $seq returns all but the first characters in $seq.`,
1938
2146
  assertSeq(seq, sourceCodeInfo);
1939
2147
  if (seq.length === 0)
1940
2148
  return null;
1941
- if (typeof seq === 'string')
1942
- return seq.split('').find(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)) ?? null;
1943
- return toAny(seq.find(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)));
2149
+ const items = typeof seq === 'string' ? seq.split('') : seq;
2150
+ return reduceSequential(items, (found, elem) => {
2151
+ if (found !== null)
2152
+ return found;
2153
+ return chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), (result) => {
2154
+ return result ? toAny(elem) : null;
2155
+ });
2156
+ }, null);
1944
2157
  },
1945
2158
  arity: toFixedArity(2),
1946
2159
  docs: {
@@ -1985,7 +2198,7 @@ some(
1985
2198
  },
1986
2199
  },
1987
2200
  'sort': {
1988
- evaluate: (params, sourceCodeInfo, contextStack, { executeFunction }) => {
2201
+ evaluate: (params, sourceCodeInfo, _contextStack, { executeFunction: _executeFunction }) => {
1989
2202
  const [seq] = params;
1990
2203
  const defaultComparer = params.length === 1;
1991
2204
  const comparer = defaultComparer ? null : params[1];
@@ -1997,8 +2210,12 @@ some(
1997
2210
  }
1998
2211
  else {
1999
2212
  assertFunctionLike(comparer, sourceCodeInfo);
2213
+ // Note: sort comparator must be synchronous — async comparators would need a different approach
2000
2214
  result.sort((a, b) => {
2001
- const compareValue = executeFunction(comparer, [a, b], contextStack, sourceCodeInfo);
2215
+ const compareValue = _executeFunction(comparer, [a, b], _contextStack, sourceCodeInfo);
2216
+ if (compareValue instanceof Promise) {
2217
+ throw new TypeError('Async functions cannot be used as sort comparators');
2218
+ }
2002
2219
  assertNumber(compareValue, sourceCodeInfo, { finite: true });
2003
2220
  return compareValue;
2004
2221
  });
@@ -2016,7 +2233,11 @@ some(
2016
2233
  else {
2017
2234
  result.sort((a, b) => {
2018
2235
  assertFunctionLike(comparer, sourceCodeInfo);
2019
- const compareValue = executeFunction(comparer, [a, b], contextStack, sourceCodeInfo);
2236
+ // Note: sort comparator must be synchronous
2237
+ const compareValue = _executeFunction(comparer, [a, b], _contextStack, sourceCodeInfo);
2238
+ if (compareValue instanceof Promise) {
2239
+ throw new TypeError('Async functions cannot be used as sort comparators');
2240
+ }
2020
2241
  assertNumber(compareValue, sourceCodeInfo, { finite: true });
2021
2242
  return compareValue;
2022
2243
  });
@@ -3611,17 +3832,23 @@ If no arguments are provided \`null\` is returned.`,
3611
3832
  const rest = params.slice(1, -1);
3612
3833
  assertObj(first, sourceCodeInfo);
3613
3834
  assertFunctionLike(fn, sourceCodeInfo);
3614
- return rest.reduce((result, obj) => {
3835
+ return reduceSequential(rest, (result, obj) => {
3615
3836
  assertObj(obj, sourceCodeInfo);
3616
- Object.entries(obj).forEach((entry) => {
3837
+ const entries = Object.entries(obj);
3838
+ return chain(reduceSequential(entries, (res, entry) => {
3617
3839
  const key = asString(entry[0], sourceCodeInfo);
3618
3840
  const val = toAny(entry[1]);
3619
- if (collHasKey(result, key))
3620
- result[key] = executeFunction(fn, [result[key], val], contextStack, sourceCodeInfo);
3621
- else
3622
- result[key] = val;
3623
- });
3624
- return result;
3841
+ if (collHasKey(res, key)) {
3842
+ return chain(executeFunction(fn, [res[key], val], contextStack, sourceCodeInfo), (merged) => {
3843
+ res[key] = merged;
3844
+ return res;
3845
+ });
3846
+ }
3847
+ else {
3848
+ res[key] = val;
3849
+ return res;
3850
+ }
3851
+ }, result), r => r);
3625
3852
  }, { ...first });
3626
3853
  },
3627
3854
  arity: { min: 2 },
@@ -5043,13 +5270,11 @@ const andSpecialExpression = {
5043
5270
  arity: {},
5044
5271
  docs: docs$f,
5045
5272
  evaluate: (node, contextStack, { evaluateNode }) => {
5046
- let value = true;
5047
- for (const param of node[1][1]) {
5048
- value = evaluateNode(param, contextStack);
5049
- if (!value)
5050
- break;
5051
- }
5052
- return value;
5273
+ return reduceSequential(node[1][1], (acc, param) => {
5274
+ if (!acc)
5275
+ return acc;
5276
+ return evaluateNode(param, contextStack);
5277
+ }, true);
5053
5278
  },
5054
5279
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
5055
5280
  let value = true;
@@ -5095,13 +5320,17 @@ const condSpecialExpression = {
5095
5320
  docs: docs$e,
5096
5321
  evaluate: (node, contextStack, { evaluateNode }) => {
5097
5322
  const params = node[1][1];
5098
- for (const [test, form] of params) {
5099
- const value = evaluateNode(test, contextStack);
5100
- if (!value)
5101
- continue;
5102
- return evaluateNode(form, contextStack);
5323
+ function processCase(index) {
5324
+ if (index >= params.length)
5325
+ return null;
5326
+ const [test, form] = params[index];
5327
+ return chain(evaluateNode(test, contextStack), (value) => {
5328
+ if (!value)
5329
+ return processCase(index + 1);
5330
+ return evaluateNode(form, contextStack);
5331
+ });
5103
5332
  }
5104
- return null;
5333
+ return processCase(0);
5105
5334
  },
5106
5335
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => getUndefinedSymbols(node[1][1].flat(), contextStack, builtin, evaluateNode),
5107
5336
  };
@@ -5139,14 +5368,20 @@ const switchSpecialExpression = {
5139
5368
  docs: docs$d,
5140
5369
  evaluate: (node, contextStack, { evaluateNode }) => {
5141
5370
  const [, switchValueNode, cases] = node[1];
5142
- const switchValue = evaluateNode(switchValueNode, contextStack);
5143
- for (const [test, form] of cases) {
5144
- const value = evaluateNode(test, contextStack);
5145
- if (value === switchValue) {
5146
- return evaluateNode(form, contextStack);
5371
+ return chain(evaluateNode(switchValueNode, contextStack), (switchValue) => {
5372
+ function processCase(index) {
5373
+ if (index >= cases.length)
5374
+ return null;
5375
+ const [test, form] = cases[index];
5376
+ return chain(evaluateNode(test, contextStack), (value) => {
5377
+ if (value === switchValue) {
5378
+ return evaluateNode(form, contextStack);
5379
+ }
5380
+ return processCase(index + 1);
5381
+ });
5147
5382
  }
5148
- }
5149
- return null;
5383
+ return processCase(0);
5384
+ });
5150
5385
  },
5151
5386
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => getUndefinedSymbols([node[1][1], ...node[1][2].flat()], contextStack, builtin, evaluateNode),
5152
5387
  };
@@ -5226,37 +5461,47 @@ function walkDefaults(bindingTarget, onDefault) {
5226
5461
  function evaluateBindingNodeValues(target, value, evaluate) {
5227
5462
  const sourceCodeInfo = target[2];
5228
5463
  const record = {};
5229
- createRecord(target, value, evaluate, sourceCodeInfo, record);
5230
- return record;
5464
+ return chain(createRecord(target, value, evaluate, sourceCodeInfo, record), () => record);
5231
5465
  }
5232
5466
  function createRecord(bindingTarget, value, evaluate, sourceCodeInfo, record) {
5233
5467
  if (bindingTarget[0] === bindingTargetTypes.object) {
5234
5468
  assertUnknownRecord(value, sourceCodeInfo);
5235
5469
  const capturedKeys = new Set();
5236
5470
  let restElement;
5237
- Object.entries(bindingTarget[1][0]).forEach(([key, element]) => {
5471
+ const entries = Object.entries(bindingTarget[1][0]);
5472
+ return chain(forEachSequential(entries, ([key, element]) => {
5238
5473
  if (element[0] === bindingTargetTypes.rest) {
5239
5474
  restElement = element;
5240
5475
  return;
5241
5476
  }
5242
5477
  capturedKeys.add(key);
5243
- const val = (value[key] !== undefined ? value[key] : element[1][1] && evaluate(element[1][1])) ?? null;
5244
- assertAny(val, sourceCodeInfo);
5245
- createRecord(element, val, evaluate, sourceCodeInfo, record);
5478
+ const existingVal = value[key];
5479
+ const maybeVal = existingVal !== undefined
5480
+ ? existingVal
5481
+ : element[1][1]
5482
+ ? evaluate(element[1][1])
5483
+ : null;
5484
+ return chain(maybeVal, (resolvedVal) => {
5485
+ const val = resolvedVal ?? null;
5486
+ assertAny(val, sourceCodeInfo);
5487
+ return createRecord(element, val, evaluate, sourceCodeInfo, record);
5488
+ });
5489
+ }), () => {
5490
+ if (restElement) {
5491
+ const restValues = Object.entries(value)
5492
+ .filter(([key]) => !capturedKeys.has(key))
5493
+ .reduce((acc, [key, val]) => {
5494
+ acc[key] = asAny(val);
5495
+ return acc;
5496
+ }, {});
5497
+ record[restElement[1][0]] = restValues;
5498
+ }
5246
5499
  });
5247
- if (restElement) {
5248
- const restValues = Object.entries(value)
5249
- .filter(([key]) => !capturedKeys.has(key))
5250
- .reduce((acc, [key, val]) => {
5251
- acc[key] = asAny(val);
5252
- return acc;
5253
- }, {});
5254
- record[restElement[1][0]] = restValues;
5255
- }
5256
5500
  }
5257
5501
  else if (bindingTarget[0] === bindingTargetTypes.array) {
5258
5502
  let restIndex = null;
5259
5503
  assertArray(value, sourceCodeInfo);
5504
+ const elements = [];
5260
5505
  for (let index = 0; index < bindingTarget[1][0].length; index += 1) {
5261
5506
  const element = bindingTarget[1][0][index] ?? null;
5262
5507
  if (element === null) {
@@ -5266,15 +5511,27 @@ function createRecord(bindingTarget, value, evaluate, sourceCodeInfo, record) {
5266
5511
  restIndex = index;
5267
5512
  break;
5268
5513
  }
5269
- const val = (value[index] !== undefined ? value[index] : element[1][1] && evaluate(element[1][1])) ?? null;
5270
- assertAny(val, sourceCodeInfo);
5271
- createRecord(element, val, evaluate, sourceCodeInfo, record);
5272
- }
5273
- if (restIndex !== null) {
5274
- const restValues = value.slice(restIndex);
5275
- const restElement = bindingTarget[1][0][restIndex];
5276
- record[restElement[1][0]] = restValues;
5277
- }
5514
+ elements.push({ element, index });
5515
+ }
5516
+ return chain(forEachSequential(elements, ({ element, index }) => {
5517
+ const existingVal = value[index];
5518
+ const maybeVal = existingVal !== undefined
5519
+ ? existingVal
5520
+ : element[1][1]
5521
+ ? evaluate(element[1][1])
5522
+ : null;
5523
+ return chain(maybeVal, (resolvedVal) => {
5524
+ const val = resolvedVal ?? null;
5525
+ assertAny(val, sourceCodeInfo);
5526
+ return createRecord(element, val, evaluate, sourceCodeInfo, record);
5527
+ });
5528
+ }), () => {
5529
+ if (restIndex !== null) {
5530
+ const restValues = value.slice(restIndex);
5531
+ const restElement = bindingTarget[1][0][restIndex];
5532
+ record[restElement[1][0]] = restValues;
5533
+ }
5534
+ });
5278
5535
  }
5279
5536
  else if (bindingTarget[0] === bindingTargetTypes.rest) {
5280
5537
  record[bindingTarget[1][0]] = asAny(value);
@@ -5322,10 +5579,12 @@ const defSpecialExpression = {
5322
5579
  const bindingNode = node[1][1];
5323
5580
  const target = bindingNode[1][0];
5324
5581
  const value = bindingNode[1][1];
5325
- const bindingValue = evaluateNode(value, contextStack);
5326
- const values = evaluateBindingNodeValues(target, bindingValue, Node => evaluateNode(Node, contextStack));
5327
- contextStack.exportValues(values, target[2]);
5328
- return bindingValue;
5582
+ return chain(evaluateNode(value, contextStack), (bindingValue) => {
5583
+ return chain(evaluateBindingNodeValues(target, bindingValue, Node => evaluateNode(Node, contextStack)), (values) => {
5584
+ contextStack.exportValues(values, target[2]);
5585
+ return bindingValue;
5586
+ });
5587
+ });
5329
5588
  },
5330
5589
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => {
5331
5590
  const bindingNode = node[1][1];
@@ -5362,10 +5621,7 @@ const doSpecialExpression = {
5362
5621
  evaluate: (node, contextStack, { evaluateNode }) => {
5363
5622
  const newContext = {};
5364
5623
  const newContextStack = contextStack.create(newContext);
5365
- let result = null;
5366
- for (const form of node[1][1])
5367
- result = evaluateNode(form, newContextStack);
5368
- return result;
5624
+ return reduceSequential(node[1][1], (_acc, form) => evaluateNode(form, newContextStack), null);
5369
5625
  },
5370
5626
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => {
5371
5627
  return getUndefinedSymbols(node[1][1], contextStack.create({}), builtin, evaluateNode);
@@ -5460,13 +5716,15 @@ const ifSpecialExpression = {
5460
5716
  docs: docs$a,
5461
5717
  evaluate: (node, contextStack, { evaluateNode }) => {
5462
5718
  const [conditionNode, trueNode, falseNode] = node[1][1];
5463
- if (evaluateNode(conditionNode, contextStack)) {
5464
- return evaluateNode(trueNode, contextStack);
5465
- }
5466
- else if (falseNode) {
5467
- return evaluateNode(falseNode, contextStack);
5468
- }
5469
- return null;
5719
+ return chain(evaluateNode(conditionNode, contextStack), (condition) => {
5720
+ if (condition) {
5721
+ return evaluateNode(trueNode, contextStack);
5722
+ }
5723
+ else if (falseNode) {
5724
+ return evaluateNode(falseNode, contextStack);
5725
+ }
5726
+ return null;
5727
+ });
5470
5728
  },
5471
5729
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => getUndefinedSymbols(node[1][1].filter(n => !!n), contextStack, builtin, evaluateNode),
5472
5730
  };
@@ -5497,13 +5755,15 @@ const unlessSpecialExpression = {
5497
5755
  docs: docs$9,
5498
5756
  evaluate: (node, contextStack, { evaluateNode }) => {
5499
5757
  const [conditionNode, trueNode, falseNode] = node[1][1];
5500
- if (!evaluateNode(conditionNode, contextStack)) {
5501
- return evaluateNode(trueNode, contextStack);
5502
- }
5503
- else if (falseNode) {
5504
- return evaluateNode(falseNode, contextStack);
5505
- }
5506
- return null;
5758
+ return chain(evaluateNode(conditionNode, contextStack), (condition) => {
5759
+ if (!condition) {
5760
+ return evaluateNode(trueNode, contextStack);
5761
+ }
5762
+ else if (falseNode) {
5763
+ return evaluateNode(falseNode, contextStack);
5764
+ }
5765
+ return null;
5766
+ });
5507
5767
  },
5508
5768
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => getUndefinedSymbols(node[1][1].filter(n => !!n), contextStack, builtin, evaluateNode),
5509
5769
  };
@@ -5529,10 +5789,12 @@ const letSpecialExpression = {
5529
5789
  const bindingNode = node[1][1];
5530
5790
  const target = bindingNode[1][0];
5531
5791
  const value = bindingNode[1][1];
5532
- const bindingValue = evaluateNode(value, contextStack);
5533
- const values = evaluateBindingNodeValues(target, bindingValue, Node => evaluateNode(Node, contextStack));
5534
- contextStack.addValues(values, target[2]);
5535
- return bindingValue;
5792
+ return chain(evaluateNode(value, contextStack), (bindingValue) => {
5793
+ return chain(evaluateBindingNodeValues(target, bindingValue, Node => evaluateNode(Node, contextStack)), (values) => {
5794
+ contextStack.addValues(values, target[2]);
5795
+ return bindingValue;
5796
+ });
5797
+ });
5536
5798
  },
5537
5799
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => {
5538
5800
  const bindingNode = node[1][1];
@@ -5579,39 +5841,93 @@ const loopSpecialExpression = {
5579
5841
  docs: docs$7,
5580
5842
  evaluate: (node, contextStack, { evaluateNode }) => {
5581
5843
  const bindingNodes = node[1][1];
5582
- const bindingContext = bindingNodes.reduce((result, bindingNode) => {
5583
- const val = evaluateNode(bindingNode[1][1], contextStack.create(result));
5584
- const valueRecord = evaluateBindingNodeValues(bindingNode[1][0], val, Node => evaluateNode(Node, contextStack));
5585
- Object.entries(valueRecord).forEach(([name, value]) => {
5586
- result[name] = { value };
5844
+ // Set up initial binding context sequentially (bindings may depend on each other)
5845
+ const initialContext = {};
5846
+ const setupBindings = reduceSequential(bindingNodes, (result, bindingNode) => {
5847
+ return chain(evaluateNode(bindingNode[1][1], contextStack.create(result)), (val) => {
5848
+ return chain(evaluateBindingNodeValues(bindingNode[1][0], val, Node => evaluateNode(Node, contextStack)), (valueRecord) => {
5849
+ Object.entries(valueRecord).forEach(([name, value]) => {
5850
+ result[name] = { value };
5851
+ });
5852
+ return result;
5853
+ });
5587
5854
  });
5588
- return result;
5589
- }, {});
5590
- const newContextStack = contextStack.create(bindingContext);
5591
- const body = node[1][2];
5592
- for (;;) {
5593
- let result = null;
5594
- try {
5595
- result = evaluateNode(body, newContextStack);
5596
- }
5597
- catch (error) {
5598
- if (error instanceof RecurSignal) {
5599
- const params = error.params;
5600
- if (params.length !== bindingNodes.length) {
5601
- throw new LitsError(`recur expected ${bindingNodes.length} parameters, got ${valueToString(params.length)}`, node[2]);
5602
- }
5603
- bindingNodes.forEach((bindingNode, index) => {
5604
- const valueRecord = evaluateBindingNodeValues(bindingNode[1][0], asAny(params[index]), Node => evaluateNode(Node, contextStack));
5855
+ }, initialContext);
5856
+ return chain(setupBindings, (bindingContext) => {
5857
+ const newContextStack = contextStack.create(bindingContext);
5858
+ const body = node[1][2];
5859
+ function rebindAndIterate(params) {
5860
+ if (params.length !== bindingNodes.length) {
5861
+ throw new LitsError(`recur expected ${bindingNodes.length} parameters, got ${valueToString(params.length)}`, node[2]);
5862
+ }
5863
+ return chain(forEachSequential(bindingNodes, (bindingNode, index) => {
5864
+ return chain(evaluateBindingNodeValues(bindingNode[1][0], asAny(params[index]), Node => evaluateNode(Node, contextStack)), (valueRecord) => {
5605
5865
  for (const [name, value] of Object.entries(valueRecord)) {
5606
5866
  bindingContext[name].value = value;
5607
5867
  }
5608
5868
  });
5609
- continue;
5869
+ }), () => iterate());
5870
+ }
5871
+ function iterate() {
5872
+ return tryCatch(() => evaluateNode(body, newContextStack), (error) => {
5873
+ if (error instanceof RecurSignal) {
5874
+ return rebindAndIterate(error.params);
5875
+ }
5876
+ throw error;
5877
+ });
5878
+ }
5879
+ // Use sync for(;;) loop for the sync case to avoid stack overflow
5880
+ for (;;) {
5881
+ try {
5882
+ const result = evaluateNode(body, newContextStack);
5883
+ if (result instanceof Promise) {
5884
+ // Async path: handle recur via promise chain
5885
+ return result.catch((error) => {
5886
+ if (error instanceof RecurSignal) {
5887
+ return rebindAndIterate(error.params);
5888
+ }
5889
+ throw error;
5890
+ });
5891
+ }
5892
+ return result;
5893
+ }
5894
+ catch (error) {
5895
+ if (error instanceof RecurSignal) {
5896
+ const params = error.params;
5897
+ if (params.length !== bindingNodes.length) {
5898
+ throw new LitsError(`recur expected ${bindingNodes.length} parameters, got ${valueToString(params.length)}`, node[2]);
5899
+ }
5900
+ // rebindAndIterate returns MaybePromise — if any binding default is async,
5901
+ // we must switch to the async iterate path
5902
+ for (let index = 0; index < bindingNodes.length; index += 1) {
5903
+ const bindingNode = bindingNodes[index];
5904
+ const valueRecord = evaluateBindingNodeValues(bindingNode[1][0], asAny(params[index]), Node => evaluateNode(Node, contextStack));
5905
+ if (valueRecord instanceof Promise) {
5906
+ // Switch to fully async path
5907
+ return valueRecord.then((resolved) => {
5908
+ for (const [name, value] of Object.entries(resolved)) {
5909
+ bindingContext[name].value = value;
5910
+ }
5911
+ // Handle remaining bindings then iterate
5912
+ return chain(forEachSequential(bindingNodes.slice(index + 1), (bn, subIndex) => {
5913
+ return chain(evaluateBindingNodeValues(bn[1][0], asAny(params[index + 1 + subIndex]), Node => evaluateNode(Node, contextStack)), (vr) => {
5914
+ for (const [name, value] of Object.entries(vr)) {
5915
+ bindingContext[name].value = value;
5916
+ }
5917
+ });
5918
+ }), () => iterate());
5919
+ });
5920
+ }
5921
+ for (const [name, value] of Object.entries(valueRecord)) {
5922
+ bindingContext[name].value = value;
5923
+ }
5924
+ }
5925
+ continue;
5926
+ }
5927
+ throw error;
5610
5928
  }
5611
- throw error;
5612
5929
  }
5613
- return result;
5614
- }
5930
+ });
5615
5931
  },
5616
5932
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => {
5617
5933
  const bindingNodes = node[1][1];
@@ -5631,74 +5947,107 @@ const loopSpecialExpression = {
5631
5947
  };
5632
5948
 
5633
5949
  function addToContext(bindings, context, contextStack, evaluateNode) {
5950
+ let bindingChain = undefined;
5634
5951
  for (const bindingNode of bindings) {
5635
- const [target, bindingValue] = bindingNode[1];
5636
- const val = evaluateNode(bindingValue, contextStack);
5637
- const valueRecord = evaluateBindingNodeValues(target, val, Node => evaluateNode(Node, contextStack));
5638
- Object.entries(valueRecord).forEach(([name, value]) => {
5639
- context[name] = { value };
5952
+ bindingChain = chain(bindingChain, () => {
5953
+ const [target, bindingValue] = bindingNode[1];
5954
+ return chain(evaluateNode(bindingValue, contextStack), (val) => {
5955
+ return chain(evaluateBindingNodeValues(target, val, Node => evaluateNode(Node, contextStack)), (valueRecord) => {
5956
+ Object.entries(valueRecord).forEach(([name, value]) => {
5957
+ context[name] = { value };
5958
+ });
5959
+ });
5960
+ });
5640
5961
  });
5641
5962
  }
5963
+ return bindingChain;
5642
5964
  }
5643
5965
  function evaluateLoop(returnResult, loopNode, contextStack, evaluateNode) {
5644
5966
  const sourceCodeInfo = loopNode[2];
5645
5967
  const [, loopBindings, body] = loopNode[1];
5646
5968
  const result = [];
5647
5969
  const bindingIndices = loopBindings.map(() => 0);
5648
- let abort = false;
5649
- while (!abort) {
5970
+ function processIteration() {
5650
5971
  const context = {};
5651
5972
  const newContextStack = contextStack.create(context);
5652
- let skip = false;
5653
- bindingsLoop: for (let bindingIndex = 0; bindingIndex < loopBindings.length; bindingIndex += 1) {
5973
+ function processBinding(bindingIndex) {
5974
+ if (bindingIndex >= loopBindings.length)
5975
+ return 'continue';
5654
5976
  const [bindingNode, letBindings, whenNode, whileNode] = loopBindings[bindingIndex];
5655
5977
  const [targetNode, valueNode] = bindingNode[1];
5656
- const coll = asColl(evaluateNode(valueNode, newContextStack), sourceCodeInfo);
5657
- const seq = isSeq(coll) ? coll : Object.entries(coll);
5658
- if (seq.length === 0) {
5659
- skip = true;
5660
- abort = true;
5661
- break;
5662
- }
5663
- const index = asNonUndefined(bindingIndices[bindingIndex], sourceCodeInfo);
5664
- if (index >= seq.length) {
5665
- skip = true;
5666
- if (bindingIndex === 0) {
5667
- abort = true;
5668
- break;
5978
+ return chain(evaluateNode(valueNode, newContextStack), (rawColl) => {
5979
+ const coll = asColl(rawColl, sourceCodeInfo);
5980
+ const seq = isSeq(coll) ? coll : Object.entries(coll);
5981
+ if (seq.length === 0) {
5982
+ return 'abort';
5669
5983
  }
5670
- bindingIndices[bindingIndex] = 0;
5671
- bindingIndices[bindingIndex - 1] = asNonUndefined(bindingIndices[bindingIndex - 1], sourceCodeInfo) + 1;
5672
- break;
5673
- }
5674
- const val = asAny(seq[index], sourceCodeInfo);
5675
- const valueRecord = evaluateBindingNodeValues(targetNode, val, Node => evaluateNode(Node, newContextStack));
5676
- Object.entries(valueRecord).forEach(([name, value]) => {
5677
- context[name] = { value };
5984
+ const index = asNonUndefined(bindingIndices[bindingIndex], sourceCodeInfo);
5985
+ if (index >= seq.length) {
5986
+ if (bindingIndex === 0) {
5987
+ return 'abort';
5988
+ }
5989
+ bindingIndices[bindingIndex] = 0;
5990
+ bindingIndices[bindingIndex - 1] = asNonUndefined(bindingIndices[bindingIndex - 1], sourceCodeInfo) + 1;
5991
+ return 'skip';
5992
+ }
5993
+ const val = asAny(seq[index], sourceCodeInfo);
5994
+ return chain(evaluateBindingNodeValues(targetNode, val, Node => evaluateNode(Node, newContextStack)), (valueRecord) => {
5995
+ Object.entries(valueRecord).forEach(([name, value]) => {
5996
+ context[name] = { value };
5997
+ });
5998
+ return chain(letBindings.length > 0
5999
+ ? addToContext(letBindings, context, newContextStack, evaluateNode)
6000
+ : undefined, () => {
6001
+ if (whenNode) {
6002
+ return chain(evaluateNode(whenNode, newContextStack), (whenResult) => {
6003
+ if (!whenResult) {
6004
+ bindingIndices[bindingIndex] = asNonUndefined(bindingIndices[bindingIndex], sourceCodeInfo) + 1;
6005
+ return 'skip';
6006
+ }
6007
+ if (whileNode) {
6008
+ return chain(evaluateNode(whileNode, newContextStack), (whileResult) => {
6009
+ if (!whileResult) {
6010
+ bindingIndices[bindingIndex] = Number.POSITIVE_INFINITY;
6011
+ return 'skip';
6012
+ }
6013
+ return processBinding(bindingIndex + 1);
6014
+ });
6015
+ }
6016
+ return processBinding(bindingIndex + 1);
6017
+ });
6018
+ }
6019
+ if (whileNode) {
6020
+ return chain(evaluateNode(whileNode, newContextStack), (whileResult) => {
6021
+ if (!whileResult) {
6022
+ bindingIndices[bindingIndex] = Number.POSITIVE_INFINITY;
6023
+ return 'skip';
6024
+ }
6025
+ return processBinding(bindingIndex + 1);
6026
+ });
6027
+ }
6028
+ return processBinding(bindingIndex + 1);
6029
+ });
6030
+ });
5678
6031
  });
5679
- if (letBindings) {
5680
- addToContext(letBindings, context, newContextStack, evaluateNode);
5681
- }
5682
- if (whenNode && !evaluateNode(whenNode, newContextStack)) {
5683
- bindingIndices[bindingIndex] = asNonUndefined(bindingIndices[bindingIndex], sourceCodeInfo) + 1;
5684
- skip = true;
5685
- break bindingsLoop;
6032
+ }
6033
+ return chain(processBinding(0), (status) => {
6034
+ if (status === 'abort') {
6035
+ return returnResult ? result : null;
5686
6036
  }
5687
- if (whileNode && !evaluateNode(whileNode, newContextStack)) {
5688
- bindingIndices[bindingIndex] = Number.POSITIVE_INFINITY;
5689
- skip = true;
5690
- break bindingsLoop;
6037
+ if (status === 'skip') {
6038
+ return processIteration();
5691
6039
  }
5692
- }
5693
- if (!skip) {
5694
- const value = evaluateNode(body, newContextStack);
5695
- if (returnResult)
5696
- result.push(value);
5697
- if (bindingIndices.length > 0)
5698
- bindingIndices[bindingIndices.length - 1] += 1;
5699
- }
6040
+ // status === 'continue'
6041
+ return chain(evaluateNode(body, newContextStack), (value) => {
6042
+ if (returnResult)
6043
+ result.push(value);
6044
+ if (bindingIndices.length > 0)
6045
+ bindingIndices[bindingIndices.length - 1] += 1;
6046
+ return processIteration();
6047
+ });
6048
+ });
5700
6049
  }
5701
- return returnResult ? result : null;
6050
+ return processIteration();
5702
6051
  }
5703
6052
  function analyze(loopNode, contextStack, getUndefinedSymbols, builtin, evaluateNode) {
5704
6053
  const result = new Set();
@@ -5787,8 +6136,7 @@ const doseqSpecialExpression = {
5787
6136
  arity: toFixedArity(1),
5788
6137
  docs: doseqDocs,
5789
6138
  evaluate: (node, contextStack, helpers) => {
5790
- evaluateLoop(false, node, contextStack, helpers.evaluateNode);
5791
- return null;
6139
+ return chain(evaluateLoop(false, node, contextStack, helpers.evaluateNode), () => null);
5792
6140
  },
5793
6141
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => analyze(node, contextStack, getUndefinedSymbols, builtin, evaluateNode),
5794
6142
  };
@@ -5828,13 +6176,11 @@ const orSpecialExpression = {
5828
6176
  arity: {},
5829
6177
  docs: docs$6,
5830
6178
  evaluate: (node, contextStack, { evaluateNode }) => {
5831
- let value = false;
5832
- for (const param of node[1][1]) {
5833
- value = evaluateNode(param, contextStack);
5834
- if (value)
5835
- break;
5836
- }
5837
- return value;
6179
+ return reduceSequential(node[1][1], (acc, param) => {
6180
+ if (acc)
6181
+ return acc;
6182
+ return evaluateNode(param, contextStack);
6183
+ }, false);
5838
6184
  },
5839
6185
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
5840
6186
  let value = false;
@@ -5887,16 +6233,21 @@ const qqSpecialExpression = {
5887
6233
  arity: { min: 1 },
5888
6234
  docs: docs$5,
5889
6235
  evaluate: (node, contextStack, { evaluateNode }) => {
5890
- for (const param of node[1][1]) {
6236
+ // Use a sentinel to know we haven't found a non-null value yet
6237
+ const SENTINEL = Symbol('qq-sentinel');
6238
+ return chain(reduceSequential(node[1][1], (acc, param) => {
6239
+ if (acc !== SENTINEL)
6240
+ return acc;
5891
6241
  if (isUserDefinedSymbolNode(param) && contextStack.lookUp(param) === null) {
5892
- continue;
5893
- }
5894
- const result = evaluateNode(param, contextStack);
5895
- if (result !== null) {
5896
- return result;
6242
+ return SENTINEL;
5897
6243
  }
5898
- }
5899
- return null;
6244
+ return chain(evaluateNode(param, contextStack), (result) => {
6245
+ if (result !== null) {
6246
+ return result;
6247
+ }
6248
+ return SENTINEL;
6249
+ });
6250
+ }, SENTINEL), result => result === SENTINEL ? null : result);
5900
6251
  },
5901
6252
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
5902
6253
  for (const param of params) {
@@ -5944,8 +6295,9 @@ const recurSpecialExpression = {
5944
6295
  docs: docs$4,
5945
6296
  evaluate: (node, contextStack, { evaluateNode }) => {
5946
6297
  const params = node[1][1];
5947
- const evaluatedParams = params.map(paramNode => evaluateNode(paramNode, contextStack));
5948
- throw new RecurSignal(evaluatedParams);
6298
+ return chain(mapSequential(params, paramNode => evaluateNode(paramNode, contextStack)), (evaluatedParams) => {
6299
+ throw new RecurSignal(evaluatedParams);
6300
+ });
5949
6301
  },
5950
6302
  evaluateAsNormalExpression: (params) => {
5951
6303
  throw new RecurSignal(params);
@@ -5976,10 +6328,12 @@ const throwSpecialExpression = {
5976
6328
  arity: toFixedArity(1),
5977
6329
  docs: docs$3,
5978
6330
  evaluate: (node, contextStack, { evaluateNode }) => {
5979
- const message = asString(evaluateNode(node[1][1], contextStack), node[2], {
5980
- nonEmpty: true,
6331
+ return chain(evaluateNode(node[1][1], contextStack), (result) => {
6332
+ const message = asString(result, node[2], {
6333
+ nonEmpty: true,
6334
+ });
6335
+ throw new UserDefinedError(message, node[2]);
5981
6336
  });
5982
- throw new UserDefinedError(message, node[2]);
5983
6337
  },
5984
6338
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
5985
6339
  const message = asString(params[0], sourceCodeInfo, {
@@ -6025,17 +6379,14 @@ const trySpecialExpression = {
6025
6379
  docs: docs$2,
6026
6380
  evaluate: (node, contextStack, { evaluateNode }) => {
6027
6381
  const [, tryExpression, errorSymbol, catchExpression] = node[1];
6028
- try {
6029
- return evaluateNode(tryExpression, contextStack);
6030
- }
6031
- catch (error) {
6382
+ return tryCatch(() => evaluateNode(tryExpression, contextStack), (error) => {
6032
6383
  const newContext = errorSymbol
6033
6384
  ? {
6034
6385
  [errorSymbol[1]]: { value: error },
6035
6386
  }
6036
6387
  : {};
6037
6388
  return evaluateNode(catchExpression, contextStack.create(newContext));
6038
- }
6389
+ });
6039
6390
  },
6040
6391
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => {
6041
6392
  const [, tryExpression, errorSymbol, catchExpression] = node[1];
@@ -6082,19 +6433,21 @@ const arraySpecialExpression = {
6082
6433
  docs: docs$1,
6083
6434
  evaluate: (node, contextStack, { evaluateNode }) => {
6084
6435
  const result = [];
6085
- for (const param of node[1][1]) {
6436
+ return chain(forEachSequential(node[1][1], (param) => {
6086
6437
  if (isSpreadNode(param)) {
6087
- const spreadValue = evaluateNode(param[1], contextStack);
6088
- if (!Array.isArray(spreadValue)) {
6089
- throw new LitsError('Spread value is not an array', param[2]);
6090
- }
6091
- result.push(...spreadValue);
6438
+ return chain(evaluateNode(param[1], contextStack), (spreadValue) => {
6439
+ if (!Array.isArray(spreadValue)) {
6440
+ throw new LitsError('Spread value is not an array', param[2]);
6441
+ }
6442
+ result.push(...spreadValue);
6443
+ });
6092
6444
  }
6093
6445
  else {
6094
- result.push(evaluateNode(param, contextStack));
6446
+ return chain(evaluateNode(param, contextStack), (value) => {
6447
+ result.push(value);
6448
+ });
6095
6449
  }
6096
- }
6097
- return result;
6450
+ }), () => result);
6098
6451
  },
6099
6452
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
6100
6453
  const result = [];
@@ -6147,28 +6500,34 @@ const objectSpecialExpression = {
6147
6500
  evaluate: (node, contextStack, { evaluateNode }) => {
6148
6501
  const result = {};
6149
6502
  const params = node[1][1];
6150
- for (let i = 0; i < params.length; i += 2) {
6503
+ function processEntry(i) {
6504
+ if (i >= params.length)
6505
+ return result;
6151
6506
  const keyNode = params[i];
6152
6507
  if (isSpreadNode(keyNode)) {
6153
- const spreadObject = evaluateNode(keyNode[1], contextStack);
6154
- if (!isUnknownRecord(spreadObject)) {
6155
- throw new LitsError('Spread value is not an object', keyNode[2]);
6156
- }
6157
- Object.assign(result, spreadObject);
6158
- i -= 1;
6508
+ return chain(evaluateNode(keyNode[1], contextStack), (spreadObject) => {
6509
+ if (!isUnknownRecord(spreadObject)) {
6510
+ throw new LitsError('Spread value is not an object', keyNode[2]);
6511
+ }
6512
+ Object.assign(result, spreadObject);
6513
+ return processEntry(i + 1);
6514
+ });
6159
6515
  }
6160
6516
  else {
6161
- const key = evaluateNode(keyNode, contextStack);
6162
6517
  const valueNode = params[i + 1];
6163
6518
  if (valueNode === undefined) {
6164
6519
  throw new LitsError('Missing value for key', keyNode[2]);
6165
6520
  }
6166
- const value = evaluateNode(valueNode, contextStack);
6167
- assertString(key, keyNode[2]);
6168
- result[key] = value;
6521
+ return chain(evaluateNode(keyNode, contextStack), (key) => {
6522
+ return chain(evaluateNode(valueNode, contextStack), (value) => {
6523
+ assertString(key, keyNode[2]);
6524
+ result[key] = value;
6525
+ return processEntry(i + 2);
6526
+ });
6527
+ });
6169
6528
  }
6170
6529
  }
6171
- return result;
6530
+ return processEntry(0);
6172
6531
  },
6173
6532
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
6174
6533
  const result = {};
@@ -6267,7 +6626,19 @@ function isNumberReservedSymbol(symbol) {
6267
6626
  const functionExecutors = {
6268
6627
  NativeJsFunction: (fn, params, sourceCodeInfo) => {
6269
6628
  try {
6270
- return toAny(fn.nativeFn.fn(...params));
6629
+ const result = fn.nativeFn.fn(...params);
6630
+ // If the native function returns a Promise, await it transparently
6631
+ if (result instanceof Promise) {
6632
+ return result.then(resolved => toAny(resolved), (error) => {
6633
+ const message = typeof error === 'string'
6634
+ ? error
6635
+ : isUnknownRecord(error) && typeof error.message === 'string'
6636
+ ? error.message
6637
+ : '<no message>';
6638
+ throw new LitsError(`Native function threw: "${message}"`, sourceCodeInfo);
6639
+ });
6640
+ }
6641
+ return toAny(result);
6271
6642
  }
6272
6643
  catch (error) {
6273
6644
  const message = typeof error === 'string'
@@ -6279,9 +6650,9 @@ const functionExecutors = {
6279
6650
  }
6280
6651
  },
6281
6652
  UserDefined: (fn, params, sourceCodeInfo, contextStack, { evaluateNode }) => {
6282
- for (;;) {
6283
- if (!arityAcceptsMin(fn.arity, params.length)) {
6284
- throw new LitsError(`Expected ${fn.arity} arguments, got ${params.length}.`, sourceCodeInfo);
6653
+ function setupAndExecute(currentParams) {
6654
+ if (!arityAcceptsMin(fn.arity, currentParams.length)) {
6655
+ throw new LitsError(`Expected ${fn.arity} arguments, got ${currentParams.length}.`, sourceCodeInfo);
6285
6656
  }
6286
6657
  const evaluatedFunction = fn.evaluatedfunction;
6287
6658
  const args = evaluatedFunction[0];
@@ -6289,39 +6660,70 @@ const functionExecutors = {
6289
6660
  const newContextStack = contextStack.create(fn.evaluatedfunction[2]);
6290
6661
  const newContext = { self: { value: fn } };
6291
6662
  const rest = [];
6292
- for (let i = 0; i < params.length; i += 1) {
6663
+ // Process non-rest params sequentially since binding evaluation may be async
6664
+ let paramSetup = undefined;
6665
+ for (let i = 0; i < currentParams.length; i += 1) {
6293
6666
  if (i < nbrOfNonRestArgs) {
6294
- const param = toAny(params[i]);
6295
- const valueRecord = evaluateBindingNodeValues(args[i], param, node => evaluateNode(node, newContextStack.create(newContext)));
6296
- Object.entries(valueRecord).forEach(([key, value]) => {
6297
- newContext[key] = { value };
6667
+ const paramIndex = i;
6668
+ paramSetup = chain(paramSetup, () => {
6669
+ const param = toAny(currentParams[paramIndex]);
6670
+ return chain(evaluateBindingNodeValues(args[paramIndex], param, node => evaluateNode(node, newContextStack.create(newContext))), (valueRecord) => {
6671
+ Object.entries(valueRecord).forEach(([key, value]) => {
6672
+ newContext[key] = { value };
6673
+ });
6674
+ });
6298
6675
  });
6299
6676
  }
6300
6677
  else {
6301
- rest.push(toAny(params[i]));
6678
+ rest.push(toAny(currentParams[i]));
6302
6679
  }
6303
6680
  }
6304
- for (let i = params.length; i < nbrOfNonRestArgs; i++) {
6305
- const arg = args[i];
6306
- const defaultValue = evaluateNode(arg[1][1], contextStack.create(newContext));
6307
- const valueRecord = evaluateBindingNodeValues(arg, defaultValue, node => evaluateNode(node, contextStack.create(newContext)));
6308
- Object.entries(valueRecord).forEach(([key, value]) => {
6309
- newContext[key] = { value };
6681
+ // Handle default values for optional params chain sequentially since they may be async
6682
+ let defaultSetup = undefined;
6683
+ for (let i = currentParams.length; i < nbrOfNonRestArgs; i++) {
6684
+ const argIndex = i;
6685
+ defaultSetup = chain(defaultSetup, () => {
6686
+ const arg = args[argIndex];
6687
+ return chain(evaluateNode(arg[1][1], contextStack.create(newContext)), (defaultValue) => {
6688
+ return chain(evaluateBindingNodeValues(arg, defaultValue, node => evaluateNode(node, contextStack.create(newContext))), (valueRecord) => {
6689
+ Object.entries(valueRecord).forEach(([key, value]) => {
6690
+ newContext[key] = { value };
6691
+ });
6692
+ });
6693
+ });
6310
6694
  });
6311
6695
  }
6312
- const restArgument = args.find(arg => arg[0] === bindingTargetTypes.rest);
6313
- if (restArgument !== undefined) {
6314
- const valueRecord = evaluateBindingNodeValues(restArgument, rest, node => evaluateNode(node, contextStack.create(newContext)));
6315
- Object.entries(valueRecord).forEach(([key, value]) => {
6316
- newContext[key] = { value };
6696
+ return chain(paramSetup, () => chain(defaultSetup, () => {
6697
+ const restArgument = args.find(arg => arg[0] === bindingTargetTypes.rest);
6698
+ const restSetup = restArgument !== undefined
6699
+ ? chain(evaluateBindingNodeValues(restArgument, rest, node => evaluateNode(node, contextStack.create(newContext))), (valueRecord) => {
6700
+ Object.entries(valueRecord).forEach(([key, value]) => {
6701
+ newContext[key] = { value };
6702
+ });
6703
+ })
6704
+ : undefined;
6705
+ return chain(restSetup, () => {
6706
+ // Evaluate body nodes sequentially
6707
+ const newContextStack2 = newContextStack.create(newContext);
6708
+ const bodyResult = reduceSequential(evaluatedFunction[1], (_acc, node) => evaluateNode(node, newContextStack2), null);
6709
+ // Handle RecurSignal for async body results
6710
+ if (bodyResult instanceof Promise) {
6711
+ return bodyResult.catch((error) => {
6712
+ if (error instanceof RecurSignal) {
6713
+ return setupAndExecute(error.params);
6714
+ }
6715
+ throw error;
6716
+ });
6717
+ }
6718
+ return bodyResult;
6317
6719
  });
6318
- }
6720
+ }));
6721
+ }
6722
+ // Sync recur loop: use for(;;) to avoid stack overflow for sync tail recursion
6723
+ for (;;) {
6319
6724
  try {
6320
- let result = null;
6321
- const newContextStack2 = newContextStack.create(newContext);
6322
- for (const node of evaluatedFunction[1]) {
6323
- result = evaluateNode(node, newContextStack2);
6324
- }
6725
+ const result = setupAndExecute(params);
6726
+ // If result is async, the RecurSignal handling is inside the Promise chain
6325
6727
  return result;
6326
6728
  }
6327
6729
  catch (error) {
@@ -6351,38 +6753,51 @@ const functionExecutors = {
6351
6753
  throw new LitsError(`(comp) expects one argument, got ${valueToString(params.length)}.`, sourceCodeInfo);
6352
6754
  return asAny(params[0], sourceCodeInfo);
6353
6755
  }
6354
- return asAny(f.reduceRight((result, fun) => {
6355
- return [executeFunction(asFunctionLike(fun, sourceCodeInfo), result, contextStack, sourceCodeInfo)];
6356
- }, params)[0], sourceCodeInfo);
6756
+ // reduceRight with MaybePromise: each step wraps result in array, passes to next function
6757
+ let result = params;
6758
+ for (let i = f.length - 1; i >= 0; i--) {
6759
+ const fun = f[i];
6760
+ result = chain(result, (currentParams) => {
6761
+ return chain(executeFunction(asFunctionLike(fun, sourceCodeInfo), currentParams, contextStack, sourceCodeInfo), r => [r]);
6762
+ });
6763
+ }
6764
+ return chain(result, finalArr => asAny(finalArr[0], sourceCodeInfo));
6357
6765
  },
6358
6766
  Constantly: (fn) => {
6359
6767
  return fn.value;
6360
6768
  },
6361
6769
  Juxt: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
6362
- return fn.params.map(fun => executeFunction(asFunctionLike(fun, sourceCodeInfo), params, contextStack, sourceCodeInfo));
6770
+ return mapSequential(fn.params, fun => executeFunction(asFunctionLike(fun, sourceCodeInfo), params, contextStack, sourceCodeInfo));
6363
6771
  },
6364
6772
  Complement: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
6365
- return !executeFunction(fn.function, params, contextStack, sourceCodeInfo);
6773
+ return chain(executeFunction(fn.function, params, contextStack, sourceCodeInfo), result => !result);
6366
6774
  },
6367
6775
  EveryPred: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
6776
+ // Flatten to sequential checks: for each predicate, for each param
6777
+ const checks = [];
6368
6778
  for (const f of fn.params) {
6369
6779
  for (const param of params) {
6370
- const result = executeFunction(asFunctionLike(f, sourceCodeInfo), [param], contextStack, sourceCodeInfo);
6371
- if (!result)
6372
- return false;
6780
+ checks.push(() => executeFunction(asFunctionLike(f, sourceCodeInfo), [param], contextStack, sourceCodeInfo));
6373
6781
  }
6374
6782
  }
6375
- return true;
6783
+ return reduceSequential(checks, (acc, check) => {
6784
+ if (!acc)
6785
+ return false;
6786
+ return chain(check(), result => !!result);
6787
+ }, true);
6376
6788
  },
6377
6789
  SomePred: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
6790
+ const checks = [];
6378
6791
  for (const f of fn.params) {
6379
6792
  for (const param of params) {
6380
- const result = executeFunction(asFunctionLike(f, sourceCodeInfo), [param], contextStack, sourceCodeInfo);
6381
- if (result)
6382
- return true;
6793
+ checks.push(() => executeFunction(asFunctionLike(f, sourceCodeInfo), [param], contextStack, sourceCodeInfo));
6383
6794
  }
6384
6795
  }
6385
- return false;
6796
+ return reduceSequential(checks, (acc, check) => {
6797
+ if (acc)
6798
+ return true;
6799
+ return chain(check(), result => !!result);
6800
+ }, false);
6386
6801
  },
6387
6802
  Fnull: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
6388
6803
  const fnulledParams = params.map((param, index) => (param === null ? toAny(fn.params[index]) : param));
@@ -6416,11 +6831,7 @@ const functionExecutors = {
6416
6831
  };
6417
6832
 
6418
6833
  function evaluate(ast, contextStack) {
6419
- let result = null;
6420
- for (const node of ast.body) {
6421
- result = evaluateNode(node, contextStack);
6422
- }
6423
- return result;
6834
+ return reduceSequential(ast.body, (_acc, node) => evaluateNode(node, contextStack), null);
6424
6835
  }
6425
6836
  function evaluateNode(node, contextStack) {
6426
6837
  switch (node[0]) {
@@ -6436,13 +6847,15 @@ function evaluateNode(node, contextStack) {
6436
6847
  return evaluateReservedSymbol(node);
6437
6848
  case NodeTypes.NormalExpression: {
6438
6849
  const result = evaluateNormalExpression(node, contextStack);
6439
- if (typeof result === 'number' && Number.isNaN(result)) {
6440
- throw new LitsError('Number is NaN', node[2]);
6441
- }
6442
- return annotate(result);
6850
+ return chain(result, (resolved) => {
6851
+ if (typeof resolved === 'number' && Number.isNaN(resolved)) {
6852
+ throw new LitsError('Number is NaN', node[2]);
6853
+ }
6854
+ return annotate(resolved);
6855
+ });
6443
6856
  }
6444
6857
  case NodeTypes.SpecialExpression:
6445
- return annotate(evaluateSpecialExpression(node, contextStack));
6858
+ return chain(evaluateSpecialExpression(node, contextStack), resolved => annotate(resolved));
6446
6859
  /* v8 ignore next 2 */
6447
6860
  default:
6448
6861
  throw new LitsError(`${getNodeTypeName(node[0])}-node cannot be evaluated`, node[2]);
@@ -6462,73 +6875,84 @@ function evaluateReservedSymbol(node) {
6462
6875
  const value = reservedSymbolRecord[reservedName];
6463
6876
  return asNonUndefined(value, node[2]);
6464
6877
  }
6465
- function evaluateNormalExpression(node, contextStack) {
6466
- const sourceCodeInfo = node[2];
6467
- const paramNodes = node[1][1];
6878
+ function evaluateParams(paramNodes, contextStack) {
6468
6879
  const params = [];
6469
6880
  const placeholders = [];
6470
- paramNodes.forEach((paramNode, index) => {
6881
+ const result = forEachSequential(paramNodes, (paramNode, index) => {
6471
6882
  if (isSpreadNode(paramNode)) {
6472
- const spreadValue = evaluateNode(paramNode[1], contextStack);
6473
- if (Array.isArray(spreadValue)) {
6474
- params.push(...spreadValue);
6475
- }
6476
- else {
6477
- throw new LitsError(`Spread operator requires an array, got ${valueToString(paramNode)}`, paramNode[2]);
6478
- }
6883
+ return chain(evaluateNode(paramNode[1], contextStack), (spreadValue) => {
6884
+ if (Array.isArray(spreadValue)) {
6885
+ params.push(...spreadValue);
6886
+ }
6887
+ else {
6888
+ throw new LitsError(`Spread operator requires an array, got ${valueToString(paramNode)}`, paramNode[2]);
6889
+ }
6890
+ });
6479
6891
  }
6480
6892
  else if (paramNode[0] === NodeTypes.ReservedSymbol && paramNode[1] === '_') {
6481
6893
  placeholders.push(index);
6482
6894
  }
6483
6895
  else {
6484
- params.push(evaluateNode(paramNode, contextStack));
6896
+ return chain(evaluateNode(paramNode, contextStack), (value) => {
6897
+ params.push(value);
6898
+ });
6485
6899
  }
6486
6900
  });
6487
- if (isNormalExpressionNodeWithName(node)) {
6488
- const nameSymbol = node[1][0];
6489
- if (placeholders.length > 0) {
6490
- const fn = evaluateNode(nameSymbol, contextStack);
6491
- const partialFunction = {
6492
- [FUNCTION_SYMBOL]: true,
6493
- function: asFunctionLike(fn, sourceCodeInfo),
6494
- functionType: 'Partial',
6495
- params,
6496
- placeholders,
6497
- sourceCodeInfo,
6498
- arity: toFixedArity(placeholders.length),
6499
- };
6500
- return partialFunction;
6501
- }
6502
- if (isNormalBuiltinSymbolNode(nameSymbol)) {
6503
- const type = nameSymbol[1];
6504
- const normalExpression = builtin.allNormalExpressions[type];
6505
- return normalExpression.evaluate(params, node[2], contextStack, { executeFunction });
6506
- }
6507
- else {
6508
- const fn = contextStack.getValue(nameSymbol[1]);
6509
- if (fn !== undefined) {
6510
- return executeFunction(asFunctionLike(fn, sourceCodeInfo), params, contextStack, sourceCodeInfo);
6901
+ return chain(result, () => ({ params, placeholders }));
6902
+ }
6903
+ function evaluateNormalExpression(node, contextStack) {
6904
+ const sourceCodeInfo = node[2];
6905
+ return chain(evaluateParams(node[1][1], contextStack), ({ params, placeholders }) => {
6906
+ if (isNormalExpressionNodeWithName(node)) {
6907
+ const nameSymbol = node[1][0];
6908
+ if (placeholders.length > 0) {
6909
+ const fn = evaluateNode(nameSymbol, contextStack);
6910
+ return chain(fn, (resolvedFn) => {
6911
+ const partialFunction = {
6912
+ [FUNCTION_SYMBOL]: true,
6913
+ function: asFunctionLike(resolvedFn, sourceCodeInfo),
6914
+ functionType: 'Partial',
6915
+ params,
6916
+ placeholders,
6917
+ sourceCodeInfo,
6918
+ arity: toFixedArity(placeholders.length),
6919
+ };
6920
+ return partialFunction;
6921
+ });
6922
+ }
6923
+ if (isNormalBuiltinSymbolNode(nameSymbol)) {
6924
+ const type = nameSymbol[1];
6925
+ const normalExpression = builtin.allNormalExpressions[type];
6926
+ return normalExpression.evaluate(params, node[2], contextStack, { executeFunction });
6927
+ }
6928
+ else {
6929
+ const fn = contextStack.getValue(nameSymbol[1]);
6930
+ if (fn !== undefined) {
6931
+ return executeFunction(asFunctionLike(fn, sourceCodeInfo), params, contextStack, sourceCodeInfo);
6932
+ }
6933
+ throw new UndefinedSymbolError(nameSymbol[1], node[2]);
6511
6934
  }
6512
- throw new UndefinedSymbolError(nameSymbol[1], node[2]);
6513
6935
  }
6514
- }
6515
- else {
6516
- const fnNode = node[1][0];
6517
- const fn = asFunctionLike(evaluateNode(fnNode, contextStack), sourceCodeInfo);
6518
- if (placeholders.length > 0) {
6519
- const partialFunction = {
6520
- [FUNCTION_SYMBOL]: true,
6521
- function: fn,
6522
- functionType: 'Partial',
6523
- params,
6524
- placeholders,
6525
- sourceCodeInfo,
6526
- arity: toFixedArity(placeholders.length),
6527
- };
6528
- return partialFunction;
6936
+ else {
6937
+ const fnNode = node[1][0];
6938
+ return chain(evaluateNode(fnNode, contextStack), (resolvedFn) => {
6939
+ const fn = asFunctionLike(resolvedFn, sourceCodeInfo);
6940
+ if (placeholders.length > 0) {
6941
+ const partialFunction = {
6942
+ [FUNCTION_SYMBOL]: true,
6943
+ function: fn,
6944
+ functionType: 'Partial',
6945
+ params,
6946
+ placeholders,
6947
+ sourceCodeInfo,
6948
+ arity: toFixedArity(placeholders.length),
6949
+ };
6950
+ return partialFunction;
6951
+ }
6952
+ return executeFunction(fn, params, contextStack, sourceCodeInfo);
6953
+ });
6529
6954
  }
6530
- return executeFunction(fn, params, contextStack, sourceCodeInfo);
6531
- }
6955
+ });
6532
6956
  }
6533
6957
  function executeFunction(fn, params, contextStack, sourceCodeInfo) {
6534
6958
  if (isLitsFunction(fn))
@@ -7587,6 +8011,7 @@ class ParserContext {
7587
8011
  const token = this.tokens[this.position];
7588
8012
  if (!token) {
7589
8013
  const lastToken = this.tokens.at(-1);
8014
+ /* v8 ignore next */
7590
8015
  const sourceCodeInfo = lastToken ? lastToken[2] : undefined;
7591
8016
  throw new LitsError('Unexpected end of input', sourceCodeInfo);
7592
8017
  }
@@ -8863,15 +9288,36 @@ class Lits {
8863
9288
  debug: this.debug,
8864
9289
  };
8865
9290
  }
9291
+ async = {
9292
+ run: async (program, params = {}) => {
9293
+ const ast = this.generateAst(program, params);
9294
+ return this.evaluate(ast, params);
9295
+ },
9296
+ context: async (programOrAst, params = {}) => {
9297
+ const ast = typeof programOrAst === 'string' ? this.generateAst(programOrAst, params) : programOrAst;
9298
+ const contextStack = createContextStack(params, this.modules);
9299
+ await evaluate(ast, contextStack);
9300
+ return contextStack.globalContext;
9301
+ },
9302
+ apply: async (fn, fnParams, params = {}) => {
9303
+ return this.apply(fn, fnParams, params);
9304
+ },
9305
+ };
8866
9306
  run(program, params = {}) {
8867
9307
  const ast = this.generateAst(program, params);
8868
9308
  const result = this.evaluate(ast, params);
9309
+ if (result instanceof Promise) {
9310
+ throw new TypeError('Unexpected async result in synchronous run(). Use lits.async.run() for async operations.');
9311
+ }
8869
9312
  return result;
8870
9313
  }
8871
9314
  context(programOrAst, params = {}) {
8872
9315
  const ast = typeof programOrAst === 'string' ? this.generateAst(programOrAst, params) : programOrAst;
8873
9316
  const contextStack = createContextStack(params, this.modules);
8874
- evaluate(ast, contextStack);
9317
+ const result = evaluate(ast, contextStack);
9318
+ if (result instanceof Promise) {
9319
+ throw new TypeError('Unexpected async result in synchronous context(). Use lits.async.context() for async operations.');
9320
+ }
8875
9321
  return contextStack.globalContext;
8876
9322
  }
8877
9323
  getUndefinedSymbols(programOrAst, params = {}) {
@@ -10137,13 +10583,9 @@ const assertNormalExpression = {
10137
10583
  }
10138
10584
  message ??= '';
10139
10585
  assertFunctionLike(func, sourceCodeInfo);
10140
- try {
10141
- executeFunction(func, [], contextStack, sourceCodeInfo);
10142
- }
10143
- catch {
10144
- return null;
10145
- }
10146
- throw new AssertionError(`Expected function to throw.${message}`, sourceCodeInfo);
10586
+ return tryCatch(() => chain(executeFunction(func, [], contextStack, sourceCodeInfo), () => {
10587
+ throw new AssertionError(`Expected function to throw.${message}`, sourceCodeInfo);
10588
+ }), () => null);
10147
10589
  },
10148
10590
  arity: { min: 1, max: 2 },
10149
10591
  },
@@ -10156,17 +10598,15 @@ const assertNormalExpression = {
10156
10598
  message ??= '';
10157
10599
  assertString(throwMessage, sourceCodeInfo);
10158
10600
  assertFunctionLike(func, sourceCodeInfo);
10159
- try {
10160
- executeFunction(func, [], contextStack, sourceCodeInfo);
10161
- }
10162
- catch (error) {
10601
+ return tryCatch(() => chain(executeFunction(func, [], contextStack, sourceCodeInfo), () => {
10602
+ throw new AssertionError(`Expected function to throw "${throwMessage}".${message}`, sourceCodeInfo);
10603
+ }), (error) => {
10163
10604
  const errorMessage = error.shortMessage;
10164
10605
  if (errorMessage !== throwMessage) {
10165
10606
  throw new AssertionError(`Expected function to throw "${throwMessage}", but thrown "${errorMessage}".${message}`, sourceCodeInfo);
10166
10607
  }
10167
10608
  return null;
10168
- }
10169
- throw new AssertionError(`Expected function to throw "${throwMessage}".${message}`, sourceCodeInfo);
10609
+ });
10170
10610
  },
10171
10611
  arity: { min: 2, max: 3 },
10172
10612
  },
@@ -10178,13 +10618,9 @@ const assertNormalExpression = {
10178
10618
  }
10179
10619
  message ??= '';
10180
10620
  assertFunctionLike(func, sourceCodeInfo);
10181
- try {
10182
- executeFunction(func, [], contextStack, sourceCodeInfo);
10183
- }
10184
- catch {
10621
+ return tryCatch(() => chain(executeFunction(func, [], contextStack, sourceCodeInfo), () => null), () => {
10185
10622
  throw new AssertionError(`Expected function not to throw.${message}`, sourceCodeInfo);
10186
- }
10187
- return null;
10623
+ });
10188
10624
  },
10189
10625
  arity: { min: 1, max: 2 },
10190
10626
  },
@@ -11572,14 +12008,13 @@ const gridFunctions = {
11572
12008
  evaluate: ([grid, predicate], sourceCodeInfo, contextStack, { executeFunction }) => {
11573
12009
  assertGrid(grid, sourceCodeInfo);
11574
12010
  assertFunctionLike(predicate, sourceCodeInfo);
12011
+ const cells = [];
11575
12012
  for (const row of grid) {
11576
12013
  for (const cell of row) {
11577
- if (!executeFunction(predicate, [cell], contextStack, sourceCodeInfo)) {
11578
- return false;
11579
- }
12014
+ cells.push(cell);
11580
12015
  }
11581
12016
  }
11582
- return true;
12017
+ return everySequential(cells, cell => executeFunction(predicate, [cell], contextStack, sourceCodeInfo));
11583
12018
  },
11584
12019
  arity: toFixedArity(2),
11585
12020
  },
@@ -11587,14 +12022,13 @@ const gridFunctions = {
11587
12022
  evaluate: ([grid, predicate], sourceCodeInfo, contextStack, { executeFunction }) => {
11588
12023
  assertGrid(grid, sourceCodeInfo);
11589
12024
  assertFunctionLike(predicate, sourceCodeInfo);
12025
+ const cells = [];
11590
12026
  for (const row of grid) {
11591
12027
  for (const cell of row) {
11592
- if (executeFunction(predicate, [cell], contextStack, sourceCodeInfo)) {
11593
- return true;
11594
- }
12028
+ cells.push(cell);
11595
12029
  }
11596
12030
  }
11597
- return false;
12031
+ return someSequential(cells, cell => executeFunction(predicate, [cell], contextStack, sourceCodeInfo));
11598
12032
  },
11599
12033
  arity: toFixedArity(2),
11600
12034
  },
@@ -11602,12 +12036,7 @@ const gridFunctions = {
11602
12036
  evaluate: ([grid, predicate], sourceCodeInfo, contextStack, { executeFunction }) => {
11603
12037
  assertGrid(grid, sourceCodeInfo);
11604
12038
  assertFunctionLike(predicate, sourceCodeInfo);
11605
- for (const row of grid) {
11606
- if (!executeFunction(predicate, [row], contextStack, sourceCodeInfo)) {
11607
- return false;
11608
- }
11609
- }
11610
- return true;
12039
+ return everySequential(Array.from(grid), row => executeFunction(predicate, [row], contextStack, sourceCodeInfo));
11611
12040
  },
11612
12041
  arity: toFixedArity(2),
11613
12042
  },
@@ -11615,12 +12044,7 @@ const gridFunctions = {
11615
12044
  evaluate: ([grid, predicate], sourceCodeInfo, contextStack, { executeFunction }) => {
11616
12045
  assertGrid(grid, sourceCodeInfo);
11617
12046
  assertFunctionLike(predicate, sourceCodeInfo);
11618
- for (const row of grid) {
11619
- if (executeFunction(predicate, [row], contextStack, sourceCodeInfo)) {
11620
- return true;
11621
- }
11622
- }
11623
- return false;
12047
+ return someSequential(Array.from(grid), row => executeFunction(predicate, [row], contextStack, sourceCodeInfo));
11624
12048
  },
11625
12049
  arity: toFixedArity(2),
11626
12050
  },
@@ -11629,12 +12053,7 @@ const gridFunctions = {
11629
12053
  assertGrid(grid, sourceCodeInfo);
11630
12054
  assertFunctionLike(predicate, sourceCodeInfo);
11631
12055
  const transposed = transpose(grid);
11632
- for (const row of transposed) {
11633
- if (!executeFunction(predicate, [row], contextStack, sourceCodeInfo)) {
11634
- return false;
11635
- }
11636
- }
11637
- return true;
12056
+ return everySequential(Array.from(transposed), row => executeFunction(predicate, [row], contextStack, sourceCodeInfo));
11638
12057
  },
11639
12058
  arity: toFixedArity(2),
11640
12059
  },
@@ -11643,12 +12062,7 @@ const gridFunctions = {
11643
12062
  assertGrid(grid, sourceCodeInfo);
11644
12063
  assertFunctionLike(predicate, sourceCodeInfo);
11645
12064
  const transposed = transpose(grid);
11646
- for (const row of transposed) {
11647
- if (executeFunction(predicate, [row], contextStack, sourceCodeInfo)) {
11648
- return true;
11649
- }
11650
- }
11651
- return false;
12065
+ return someSequential(Array.from(transposed), row => executeFunction(predicate, [row], contextStack, sourceCodeInfo));
11652
12066
  },
11653
12067
  arity: toFixedArity(2),
11654
12068
  },
@@ -11697,17 +12111,14 @@ const gridFunctions = {
11697
12111
  assertNumber(rows, sourceCodeInfo, { integer: true, positive: true });
11698
12112
  assertNumber(cols, sourceCodeInfo, { integer: true, positive: true });
11699
12113
  assertFunctionLike(generator, sourceCodeInfo);
11700
- const result = [];
11701
- for (let i = 0; i < rows; i += 1) {
11702
- const row = [];
11703
- for (let j = 0; j < cols; j += 1) {
11704
- const value = executeFunction(generator, [i, j], contextStack, sourceCodeInfo);
11705
- assertAny(value, sourceCodeInfo);
11706
- row.push(value);
11707
- }
11708
- result.push(row);
11709
- }
11710
- return result;
12114
+ return mapSequential(Array.from({ length: rows }), (_, i) => {
12115
+ return mapSequential(Array.from({ length: cols }), (__, j) => {
12116
+ return chain(executeFunction(generator, [i, j], contextStack, sourceCodeInfo), (value) => {
12117
+ assertAny(value, sourceCodeInfo);
12118
+ return value;
12119
+ });
12120
+ });
12121
+ });
11711
12122
  },
11712
12123
  arity: toFixedArity(3),
11713
12124
  },
@@ -11994,16 +12405,12 @@ const gridFunctions = {
11994
12405
  throw new LitsError(`All grids must have the same number of columns, but got ${cols} and ${grid[0].length}`, sourceCodeInfo);
11995
12406
  }
11996
12407
  });
11997
- const result = [];
11998
- for (let i = 0; i < rows; i += 1) {
11999
- const row = [];
12000
- for (let j = 0; j < cols; j += 1) {
12408
+ return mapSequential(Array.from({ length: rows }), (_, i) => {
12409
+ return mapSequential(Array.from({ length: cols }), (__, j) => {
12001
12410
  const args = grids.map(grid => grid[i][j]);
12002
- row.push(asAny(executeFunction(fn, args, contextStack, sourceCodeInfo)));
12003
- }
12004
- result.push(row);
12005
- }
12006
- return result;
12411
+ return chain(executeFunction(fn, args, contextStack, sourceCodeInfo), val => asAny(val));
12412
+ });
12413
+ });
12007
12414
  },
12008
12415
  arity: { min: 2 },
12009
12416
  },
@@ -12013,15 +12420,11 @@ const gridFunctions = {
12013
12420
  assertFunctionLike(fn, sourceCodeInfo);
12014
12421
  const rows = grid.length;
12015
12422
  const cols = grid[0].length;
12016
- const result = [];
12017
- for (let i = 0; i < rows; i += 1) {
12018
- const row = [];
12019
- for (let j = 0; j < cols; j += 1) {
12020
- row.push(asAny(executeFunction(fn, [grid[i][j], i, j], contextStack, sourceCodeInfo)));
12021
- }
12022
- result.push(row);
12023
- }
12024
- return result;
12423
+ return mapSequential(Array.from({ length: rows }), (_, i) => {
12424
+ return mapSequential(Array.from({ length: cols }), (__, j) => {
12425
+ return chain(executeFunction(fn, [grid[i][j], i, j], contextStack, sourceCodeInfo), val => asAny(val));
12426
+ });
12427
+ });
12025
12428
  },
12026
12429
  arity: toFixedArity(2),
12027
12430
  },
@@ -12029,13 +12432,13 @@ const gridFunctions = {
12029
12432
  evaluate: ([grid, fn, initialValue], sourceCodeInfo, contextStack, { executeFunction }) => {
12030
12433
  assertGrid(grid, sourceCodeInfo);
12031
12434
  assertFunctionLike(fn, sourceCodeInfo);
12032
- let accumulator = asAny(initialValue);
12435
+ const cells = [];
12033
12436
  for (const row of grid) {
12034
12437
  for (const cell of row) {
12035
- accumulator = executeFunction(fn, [accumulator, cell], contextStack, sourceCodeInfo);
12438
+ cells.push(cell);
12036
12439
  }
12037
12440
  }
12038
- return accumulator;
12441
+ return reduceSequential(cells, (accumulator, cell) => executeFunction(fn, [accumulator, cell], contextStack, sourceCodeInfo), asAny(initialValue));
12039
12442
  },
12040
12443
  arity: toFixedArity(3),
12041
12444
  },
@@ -12043,13 +12446,13 @@ const gridFunctions = {
12043
12446
  evaluate: ([grid, fn, initialValue], sourceCodeInfo, contextStack, { executeFunction }) => {
12044
12447
  assertGrid(grid, sourceCodeInfo);
12045
12448
  assertFunctionLike(fn, sourceCodeInfo);
12046
- let accumulator = asAny(initialValue);
12449
+ const cells = [];
12047
12450
  for (let i = 0; i < grid.length; i += 1) {
12048
12451
  for (let j = 0; j < grid[i].length; j += 1) {
12049
- accumulator = executeFunction(fn, [accumulator, grid[i][j], i, j], contextStack, sourceCodeInfo);
12452
+ cells.push({ cell: grid[i][j], i, j });
12050
12453
  }
12051
12454
  }
12052
- return accumulator;
12455
+ return reduceSequential(cells, (accumulator, { cell, i, j }) => executeFunction(fn, [accumulator, cell, i, j], contextStack, sourceCodeInfo), asAny(initialValue));
12053
12456
  },
12054
12457
  arity: toFixedArity(3),
12055
12458
  },
@@ -18165,10 +18568,11 @@ const vectorFunctions = {
18165
18568
  evaluate: ([length, generator], sourceCodeInfo, contextStack, { executeFunction }) => {
18166
18569
  assertNumber(length, sourceCodeInfo, { integer: true, nonNegative: true });
18167
18570
  assertFunctionLike(generator, sourceCodeInfo);
18168
- return Array.from({ length }, (_, i) => {
18169
- const value = executeFunction(generator, [i], contextStack, sourceCodeInfo);
18170
- assertNumber(value, sourceCodeInfo, { finite: true });
18171
- return value;
18571
+ return mapSequential(Array.from({ length }), (_, i) => {
18572
+ return chain(executeFunction(generator, [i], contextStack, sourceCodeInfo), (value) => {
18573
+ assertNumber(value, sourceCodeInfo, { finite: true });
18574
+ return value;
18575
+ });
18172
18576
  });
18173
18577
  },
18174
18578
  arity: toFixedArity(2),
@@ -26799,16 +27203,17 @@ const abundantSequence = {
26799
27203
  'abundant?': n => isAbundant(n),
26800
27204
  'abundant-take-while': (takeWhile) => {
26801
27205
  const abundants = [];
26802
- for (let i = 2;; i += 1) {
26803
- if (!isAbundant(i)) {
26804
- continue;
26805
- }
26806
- if (!takeWhile(i, abundants.length)) {
26807
- break;
26808
- }
26809
- abundants.push(i);
27206
+ function loop(i) {
27207
+ if (!isAbundant(i))
27208
+ return loop(i + 1);
27209
+ return chain(takeWhile(i, abundants.length), (keep) => {
27210
+ if (!keep)
27211
+ return abundants;
27212
+ abundants.push(i);
27213
+ return loop(i + 1);
27214
+ });
26810
27215
  }
26811
- return abundants;
27216
+ return loop(2);
26812
27217
  },
26813
27218
  };
26814
27219
 
@@ -26853,15 +27258,20 @@ const arithmeticNormalExpressions = {
26853
27258
  assertNumber(start, sourceCodeInfo, { finite: true });
26854
27259
  assertNumber(step, sourceCodeInfo, { finite: true });
26855
27260
  assertFunctionLike(fn, sourceCodeInfo);
27261
+ const s = start;
27262
+ const d = step;
27263
+ const f = fn;
26856
27264
  const arithmetic = [];
26857
- for (let i = 0;; i += 1) {
26858
- const value = start + i * step;
26859
- if (!(executeFunction)(fn, [value, i], contextStack, sourceCodeInfo)) {
26860
- break;
26861
- }
26862
- arithmetic[i] = value;
27265
+ function loop(i) {
27266
+ const value = s + i * d;
27267
+ return chain(executeFunction(f, [value, i], contextStack, sourceCodeInfo), (keep) => {
27268
+ if (!keep)
27269
+ return arithmetic;
27270
+ arithmetic.push(value);
27271
+ return loop(i + 1);
27272
+ });
26863
27273
  }
26864
- return arithmetic;
27274
+ return loop(0);
26865
27275
  },
26866
27276
  arity: toFixedArity(3),
26867
27277
  },
@@ -26927,28 +27337,21 @@ function getBernoulliSeq(length) {
26927
27337
  * @returns Array of Bernoulli numbers generated until predicate returns false
26928
27338
  */
26929
27339
  function generateBernoulli(predicate) {
26930
- const batchSize = 100;
26931
- // Start with computing the Bernoulli numbers
26932
27340
  const bernoulli = [1];
26933
- let n = 1;
26934
- // Continue generating as long as the predicate returns true
26935
- while (true) {
26936
- // Generate a batch of numbers at a time for efficiency
26937
- const targetLength = bernoulli.length + batchSize;
26938
- for (; n < targetLength; n++) {
26939
- let sum = 0;
26940
- for (let k = 0; k < n; k++) {
26941
- sum += binomialCoefficient(n + 1, k) * bernoulli[k];
26942
- }
26943
- const newValue = n > 1 && n % 2 === 1 ? 0 : -sum / (n + 1);
26944
- // Check if we should continue
26945
- if (!predicate(newValue, n)) {
26946
- // We're done, return the generated sequence (including the last value)
27341
+ function loop(n) {
27342
+ let sum = 0;
27343
+ for (let k = 0; k < n; k++) {
27344
+ sum += binomialCoefficient(n + 1, k) * bernoulli[k];
27345
+ }
27346
+ const newValue = n > 1 && n % 2 === 1 ? 0 : -sum / (n + 1);
27347
+ return chain(predicate(newValue, n), (keep) => {
27348
+ if (!keep)
26947
27349
  return bernoulli;
26948
- }
26949
27350
  bernoulli.push(newValue);
26950
- }
27351
+ return loop(n + 1);
27352
+ });
26951
27353
  }
27354
+ return loop(1);
26952
27355
  }
26953
27356
  const bernoulliNormalExpressions = {
26954
27357
  'bernoulli-seq': {
@@ -26969,8 +27372,8 @@ const bernoulliNormalExpressions = {
26969
27372
  'bernoulli-take-while': {
26970
27373
  evaluate: ([fn], sourceCodeInfo, contextStack, { executeFunction }) => {
26971
27374
  assertFunctionLike(fn, sourceCodeInfo);
26972
- const bernoulli = generateBernoulli((value, index) => !!(executeFunction)(fn, [value, index], contextStack));
26973
- return bernoulli;
27375
+ const f = fn;
27376
+ return generateBernoulli((value, index) => chain(executeFunction(f, [value, index], contextStack), val => !!val));
26974
27377
  },
26975
27378
  arity: toFixedArity(1),
26976
27379
  },
@@ -27059,16 +27462,17 @@ const primeSequence = {
27059
27462
  'prime?': n => isPrime(n),
27060
27463
  'prime-take-while': (takeWhile) => {
27061
27464
  const primes = [];
27062
- for (let i = 2;; i += 1) {
27063
- if (!isPrime(i)) {
27064
- continue;
27065
- }
27066
- if (!takeWhile(i, primes.length)) {
27067
- break;
27068
- }
27069
- primes.push(i);
27465
+ function loop(i) {
27466
+ if (!isPrime(i))
27467
+ return loop(i + 1);
27468
+ return chain(takeWhile(i, primes.length), (keep) => {
27469
+ if (!keep)
27470
+ return primes;
27471
+ primes.push(i);
27472
+ return loop(i + 1);
27473
+ });
27070
27474
  }
27071
- return primes;
27475
+ return loop(2);
27072
27476
  },
27073
27477
  };
27074
27478
 
@@ -27093,16 +27497,17 @@ const compositeSequence = {
27093
27497
  'composite?': n => isComposite(n),
27094
27498
  'composite-take-while': (takeWhile) => {
27095
27499
  const composites = [];
27096
- for (let i = 4;; i += 1) {
27097
- if (!isComposite(i)) {
27098
- continue;
27099
- }
27100
- if (!takeWhile(i, composites.length)) {
27101
- break;
27102
- }
27103
- composites.push(i);
27500
+ function loop(i) {
27501
+ if (!isComposite(i))
27502
+ return loop(i + 1);
27503
+ return chain(takeWhile(i, composites.length), (keep) => {
27504
+ if (!keep)
27505
+ return composites;
27506
+ composites.push(i);
27507
+ return loop(i + 1);
27508
+ });
27104
27509
  }
27105
- return composites;
27510
+ return loop(4);
27106
27511
  },
27107
27512
  };
27108
27513
 
@@ -27126,16 +27531,17 @@ const deficientSequence = {
27126
27531
  'deficient?': n => isDeficient(n),
27127
27532
  'deficient-take-while': (takeWhile) => {
27128
27533
  const deficients = [];
27129
- for (let i = 1;; i += 1) {
27130
- if (!isDeficient(i)) {
27131
- continue;
27132
- }
27133
- if (!takeWhile(i, deficients.length)) {
27134
- break;
27135
- }
27136
- deficients.push(i);
27534
+ function loop(i) {
27535
+ if (!isDeficient(i))
27536
+ return loop(i + 1);
27537
+ return chain(takeWhile(i, deficients.length), (keep) => {
27538
+ if (!keep)
27539
+ return deficients;
27540
+ deficients.push(i);
27541
+ return loop(i + 1);
27542
+ });
27137
27543
  }
27138
- return deficients;
27544
+ return loop(1);
27139
27545
  },
27140
27546
  };
27141
27547
 
@@ -27295,15 +27701,20 @@ const geometricNormalExpressions = {
27295
27701
  assertNumber(start, sourceCodeInfo, { finite: true });
27296
27702
  assertNumber(ratio, sourceCodeInfo, { finite: true });
27297
27703
  assertFunctionLike(fn, sourceCodeInfo);
27704
+ const s = start;
27705
+ const r = ratio;
27706
+ const f = fn;
27298
27707
  const geometric = [];
27299
- for (let i = 0;; i += 1) {
27300
- const value = start * ratio ** i;
27301
- if (!(executeFunction)(fn, [value, i], contextStack, sourceCodeInfo)) {
27302
- break;
27303
- }
27304
- geometric[i] = value;
27708
+ function loop(i) {
27709
+ const value = s * r ** i;
27710
+ return chain(executeFunction(f, [value, i], contextStack, sourceCodeInfo), (keep) => {
27711
+ if (!keep)
27712
+ return geometric;
27713
+ geometric.push(value);
27714
+ return loop(i + 1);
27715
+ });
27305
27716
  }
27306
- return geometric;
27717
+ return loop(0);
27307
27718
  },
27308
27719
  arity: toFixedArity(3),
27309
27720
  },
@@ -27335,18 +27746,21 @@ function getGolombSeq(n) {
27335
27746
  return golomb.slice(1);
27336
27747
  }
27337
27748
  function generateGolombSeq(pred) {
27338
- if (!pred(1, 0)) {
27339
- return [];
27340
- }
27341
27749
  const golomb = [0, 1];
27342
- for (let i = 2;; i++) {
27343
- const golombNumber = 1 + golomb[i - golomb[golomb[i - 1]]];
27344
- if (!pred(golombNumber, i - 1)) {
27345
- break;
27750
+ return chain(pred(1, 0), (keepFirst) => {
27751
+ if (!keepFirst)
27752
+ return [];
27753
+ function loop(i) {
27754
+ const golombNumber = 1 + golomb[i - golomb[golomb[i - 1]]];
27755
+ return chain(pred(golombNumber, i - 1), (keep) => {
27756
+ if (!keep)
27757
+ return golomb.slice(1);
27758
+ golomb.push(golombNumber);
27759
+ return loop(i + 1);
27760
+ });
27346
27761
  }
27347
- golomb.push(golombNumber);
27348
- }
27349
- return golomb.slice(1);
27762
+ return loop(2);
27763
+ });
27350
27764
  }
27351
27765
  const golombSequence = {
27352
27766
  'golomb-seq': length => getGolombSeq(length),
@@ -27401,23 +27815,17 @@ const happySequence = {
27401
27815
  'happy?': n => isHappyNumber(n),
27402
27816
  'happy-take-while': (takeWhile) => {
27403
27817
  const happyNumbers = [];
27404
- for (let i = 1;; i++) {
27405
- let n = i;
27406
- const seen = new Set();
27407
- while (n !== 1 && !seen.has(n)) {
27408
- seen.add(n);
27409
- n = String(n)
27410
- .split('')
27411
- .reduce((sum, digit) => sum + Number(digit) ** 2, 0);
27412
- }
27413
- if (n === 1) {
27414
- if (!takeWhile(i, happyNumbers.length)) {
27415
- break;
27416
- }
27818
+ function loop(i) {
27819
+ if (!isHappyNumber(i))
27820
+ return loop(i + 1);
27821
+ return chain(takeWhile(i, happyNumbers.length), (keep) => {
27822
+ if (!keep)
27823
+ return happyNumbers;
27417
27824
  happyNumbers.push(i);
27418
- }
27825
+ return loop(i + 1);
27826
+ });
27419
27827
  }
27420
- return happyNumbers;
27828
+ return loop(1);
27421
27829
  },
27422
27830
  };
27423
27831
 
@@ -27500,19 +27908,23 @@ const lookAndSaySequence = {
27500
27908
  return lookAndSay;
27501
27909
  },
27502
27910
  'look-and-say-take-while': (takeWhile) => {
27503
- if (!takeWhile('1', 0)) {
27504
- return [];
27505
- }
27506
- const lookAndSay = ['1'];
27507
- for (let i = 1;; i += 1) {
27508
- const prev = lookAndSay[i - 1];
27509
- const next = prev.replace(/(\d)\1*/g, match => `${match.length}${match[0]}`);
27510
- if (!takeWhile(next, i)) {
27511
- break;
27911
+ const lookAndSay = [];
27912
+ return chain(takeWhile('1', 0), (keepFirst) => {
27913
+ if (!keepFirst)
27914
+ return lookAndSay;
27915
+ lookAndSay.push('1');
27916
+ function loop(i) {
27917
+ const prev = lookAndSay[i - 1];
27918
+ const next = prev.replace(/(\d)\1*/g, match => `${match.length}${match[0]}`);
27919
+ return chain(takeWhile(next, i), (keep) => {
27920
+ if (!keep)
27921
+ return lookAndSay;
27922
+ lookAndSay.push(next);
27923
+ return loop(i + 1);
27924
+ });
27512
27925
  }
27513
- lookAndSay[i] = next;
27514
- }
27515
- return lookAndSay;
27926
+ return loop(1);
27927
+ });
27516
27928
  },
27517
27929
  'look-and-say?': n => isLookAndSay(n),
27518
27930
  };
@@ -27620,42 +28032,45 @@ function generateLuckyNumbers(predicate) {
27620
28032
  const luckyNumbers = [1]; // 1 is always the first lucky number
27621
28033
  let count = 1;
27622
28034
  // Check if we should continue after the first number
27623
- if (!predicate(1, 0)) {
27624
- return [];
27625
- }
27626
- // Continue the sieve process
27627
- let index = 1; // Start with the second element (index 1, which is 3)
27628
- while (index < filteredNumbers.length) {
27629
- // Get the current lucky number
27630
- const luckyNumber = filteredNumbers[index];
27631
- // Check if we should continue
27632
- if (!predicate(luckyNumber, count)) {
27633
- break;
27634
- }
27635
- // Add to result
27636
- luckyNumbers.push(luckyNumber);
27637
- count++;
27638
- // Apply the sieve
27639
- const step = luckyNumber;
27640
- const newFiltered = [];
27641
- for (let i = 0; i < filteredNumbers.length; i++) {
27642
- if ((i + 1) % step !== 0) { // Keep numbers not at positions divisible by step
27643
- newFiltered.push(filteredNumbers[i]);
27644
- }
27645
- }
27646
- filteredNumbers = newFiltered;
27647
- index++;
27648
- // If we're running low on numbers, extend the sequence
27649
- if (index >= filteredNumbers.length - 5) {
27650
- const lastNum = filteredNumbers[filteredNumbers.length - 1];
27651
- let next = lastNum + 2;
27652
- while (filteredNumbers.length < index + 1000) {
27653
- filteredNumbers.push(next);
27654
- next += 2;
27655
- }
28035
+ return chain(predicate(1, 0), (keepFirst) => {
28036
+ if (!keepFirst)
28037
+ return [];
28038
+ // Continue the sieve process
28039
+ let index = 1; // Start with the second element (index 1, which is 3)
28040
+ function loop() {
28041
+ // Get the current lucky number
28042
+ const luckyNumber = filteredNumbers[index];
28043
+ // Check if we should continue
28044
+ return chain(predicate(luckyNumber, count), (keep) => {
28045
+ if (!keep)
28046
+ return luckyNumbers;
28047
+ // Add to result
28048
+ luckyNumbers.push(luckyNumber);
28049
+ count++;
28050
+ // Apply the sieve
28051
+ const step = luckyNumber;
28052
+ const newFiltered = [];
28053
+ for (let i = 0; i < filteredNumbers.length; i++) {
28054
+ if ((i + 1) % step !== 0) { // Keep numbers not at positions divisible by step
28055
+ newFiltered.push(filteredNumbers[i]);
28056
+ }
28057
+ }
28058
+ filteredNumbers = newFiltered;
28059
+ index++;
28060
+ // If we're running low on numbers, extend the sequence
28061
+ if (index >= filteredNumbers.length - 5) {
28062
+ const lastNum = filteredNumbers[filteredNumbers.length - 1];
28063
+ let next = lastNum + 2;
28064
+ while (filteredNumbers.length < index + 1000) {
28065
+ filteredNumbers.push(next);
28066
+ next += 2;
28067
+ }
28068
+ }
28069
+ return loop();
28070
+ });
27656
28071
  }
27657
- }
27658
- return luckyNumbers;
28072
+ return loop();
28073
+ });
27659
28074
  }
27660
28075
  /**
27661
28076
  * Generates lucky numbers up to a specified length or count
@@ -27818,32 +28233,37 @@ const padovanSequence = {
27818
28233
  'padovan?': n => isPadovan(n),
27819
28234
  'padovan-take-while': (takeWhile) => {
27820
28235
  const padovan = [];
27821
- if (!takeWhile(1, 0)) {
27822
- return padovan;
27823
- }
27824
- padovan.push(1);
27825
- if (!takeWhile(1, 1)) {
27826
- return padovan;
27827
- }
27828
- padovan.push(1);
27829
- if (!takeWhile(1, 2)) {
27830
- return padovan;
27831
- }
27832
- padovan.push(1);
27833
- let a = 1;
27834
- let b = 1;
27835
- let c = 1;
27836
- for (let i = 4;; i += 1) {
27837
- const temp = a + b;
27838
- a = b;
27839
- b = c;
27840
- c = temp;
27841
- if (!takeWhile(c, i)) {
27842
- break;
27843
- }
27844
- padovan.push(c);
27845
- }
27846
- return padovan;
28236
+ return chain(takeWhile(1, 0), (keep0) => {
28237
+ if (!keep0)
28238
+ return padovan;
28239
+ padovan.push(1);
28240
+ return chain(takeWhile(1, 1), (keep1) => {
28241
+ if (!keep1)
28242
+ return padovan;
28243
+ padovan.push(1);
28244
+ return chain(takeWhile(1, 2), (keep2) => {
28245
+ if (!keep2)
28246
+ return padovan;
28247
+ padovan.push(1);
28248
+ let a = 1;
28249
+ let b = 1;
28250
+ let c = 1;
28251
+ function loop(i) {
28252
+ const temp = a + b;
28253
+ a = b;
28254
+ b = c;
28255
+ c = temp;
28256
+ return chain(takeWhile(c, i), (keep) => {
28257
+ if (!keep)
28258
+ return padovan;
28259
+ padovan.push(c);
28260
+ return loop(i + 1);
28261
+ });
28262
+ }
28263
+ return loop(4);
28264
+ });
28265
+ });
28266
+ });
27847
28267
  },
27848
28268
  };
27849
28269
 
@@ -27905,14 +28325,16 @@ const perfectCubeSequence = {
27905
28325
  'perfect-cube?': n => n > 0 && Number.isInteger(Math.cbrt(n)),
27906
28326
  'perfect-cube-take-while': (takeWhile) => {
27907
28327
  const perfectcubes = [];
27908
- for (let i = 1;; i++) {
28328
+ function loop(i) {
27909
28329
  const value = i ** 3;
27910
- if (!takeWhile(value, i)) {
27911
- break;
27912
- }
27913
- perfectcubes.push(value);
28330
+ return chain(takeWhile(value, i), (keep) => {
28331
+ if (!keep)
28332
+ return perfectcubes;
28333
+ perfectcubes.push(value);
28334
+ return loop(i + 1);
28335
+ });
27914
28336
  }
27915
- return perfectcubes;
28337
+ return loop(1);
27916
28338
  },
27917
28339
  };
27918
28340
 
@@ -27957,15 +28379,17 @@ const perfectPowerSequence = {
27957
28379
  'perfect-power?': n => perfectPower(n) !== null,
27958
28380
  'perfect-power-take-while': (takeWhile) => {
27959
28381
  const perfectPowers = [];
27960
- for (let i = 1;; i++) {
27961
- if (perfectPower(i)) {
27962
- if (!takeWhile(i, perfectPowers.length)) {
27963
- break;
27964
- }
28382
+ function loop(i) {
28383
+ if (!perfectPower(i))
28384
+ return loop(i + 1);
28385
+ return chain(takeWhile(i, perfectPowers.length), (keep) => {
28386
+ if (!keep)
28387
+ return perfectPowers;
27965
28388
  perfectPowers.push(i);
27966
- }
28389
+ return loop(i + 1);
28390
+ });
27967
28391
  }
27968
- return perfectPowers;
28392
+ return loop(1);
27969
28393
  },
27970
28394
  };
27971
28395
 
@@ -27980,14 +28404,16 @@ const perfectSquareSequence = {
27980
28404
  'perfect-square?': n => n > 0 && Number.isInteger(Math.sqrt(n)),
27981
28405
  'perfect-square-take-while': (takeWhile) => {
27982
28406
  const perfectSquares = [];
27983
- for (let i = 1;; i++) {
28407
+ function loop(i) {
27984
28408
  const value = i ** 2;
27985
- if (!takeWhile(value, i)) {
27986
- break;
27987
- }
27988
- perfectSquares.push(value);
28409
+ return chain(takeWhile(value, i), (keep) => {
28410
+ if (!keep)
28411
+ return perfectSquares;
28412
+ perfectSquares.push(value);
28413
+ return loop(i + 1);
28414
+ });
27989
28415
  }
27990
- return perfectSquares;
28416
+ return loop(1);
27991
28417
  },
27992
28418
  };
27993
28419
 
@@ -28008,15 +28434,19 @@ const poligonalNormalExpressions = {
28008
28434
  evaluate: ([sides, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
28009
28435
  assertNumber(sides, sourceCodeInfo, { integer: true, gte: 3 });
28010
28436
  assertFunctionLike(fn, sourceCodeInfo);
28437
+ const s = sides;
28438
+ const f = fn;
28011
28439
  const polygonal = [];
28012
- for (let i = 1;; i += 1) {
28013
- const value = (i * i * (sides - 2) - i * (sides - 4)) / 2;
28014
- if (!(executeFunction)(fn, [value, i], contextStack, sourceCodeInfo)) {
28015
- break;
28016
- }
28017
- polygonal[i - 1] = (i * i * (sides - 2) - i * (sides - 4)) / 2;
28440
+ function loop(i) {
28441
+ const value = (i * i * (s - 2) - i * (s - 4)) / 2;
28442
+ return chain(executeFunction(f, [value, i], contextStack, sourceCodeInfo), (keep) => {
28443
+ if (!keep)
28444
+ return polygonal;
28445
+ polygonal.push(value);
28446
+ return loop(i + 1);
28447
+ });
28018
28448
  }
28019
- return polygonal;
28449
+ return loop(1);
28020
28450
  },
28021
28451
  arity: toFixedArity(2),
28022
28452
  },
@@ -28080,23 +28510,29 @@ function generateRecamanSequence(n) {
28080
28510
  const recamanSequence = {
28081
28511
  'recaman-seq': length => generateRecamanSequence(length),
28082
28512
  'recaman-take-while': (takeWhile) => {
28083
- if (!takeWhile(0, 0))
28084
- return [];
28085
- const sequence = [0];
28513
+ const sequence = [];
28086
28514
  const seen = new Set([0]);
28087
- for (let i = 1;; i++) {
28088
- // Try to go backward
28089
- let next = sequence[i - 1] - i;
28090
- // If that's not positive or already seen, go forward
28091
- if (next <= 0 || seen.has(next)) {
28092
- next = sequence[i - 1] + i;
28093
- }
28094
- if (!takeWhile(next, i))
28095
- break;
28096
- sequence.push(next);
28097
- seen.add(next);
28098
- }
28099
- return sequence;
28515
+ return chain(takeWhile(0, 0), (keepFirst) => {
28516
+ if (!keepFirst)
28517
+ return sequence;
28518
+ sequence.push(0);
28519
+ function loop(i) {
28520
+ // Try to go backward
28521
+ let next = sequence[i - 1] - i;
28522
+ // If that's not positive or already seen, go forward
28523
+ if (next <= 0 || seen.has(next)) {
28524
+ next = sequence[i - 1] + i;
28525
+ }
28526
+ return chain(takeWhile(next, i), (keep) => {
28527
+ if (!keep)
28528
+ return sequence;
28529
+ sequence.push(next);
28530
+ seen.add(next);
28531
+ return loop(i + 1);
28532
+ });
28533
+ }
28534
+ return loop(1);
28535
+ });
28100
28536
  },
28101
28537
  'recaman?': () => true,
28102
28538
  };
@@ -28120,14 +28556,16 @@ const thueMorseSequence = {
28120
28556
  },
28121
28557
  'thue-morse-take-while': (takeWhile) => {
28122
28558
  const thueMorse = [];
28123
- for (let i = 0;; i += 1) {
28559
+ function loop(i) {
28124
28560
  const value = countSetBits(i) % 2;
28125
- if (!takeWhile(value, i)) {
28126
- break;
28127
- }
28128
- thueMorse[i] = value;
28561
+ return chain(takeWhile(value, i), (keep) => {
28562
+ if (!keep)
28563
+ return thueMorse;
28564
+ thueMorse.push(value);
28565
+ return loop(i + 1);
28566
+ });
28129
28567
  }
28130
- return thueMorse;
28568
+ return loop(0);
28131
28569
  },
28132
28570
  'thue-morse?': n => n === 1 || n === 0,
28133
28571
  };
@@ -28251,16 +28689,16 @@ function getFiniteNumberSequence(name, sequence) {
28251
28689
  return {
28252
28690
  [`${name}-seq`]: createSeqNormalExpression(length => sequence.slice(0, length), sequence.length),
28253
28691
  [`${name}-take-while`]: createTakeWhileNormalExpression((takeWhile) => {
28254
- let i = 0;
28255
- for (i = 0;; i += 1) {
28256
- if (i >= sequence.length) {
28257
- break;
28258
- }
28259
- if (!takeWhile(sequence[i], i)) {
28260
- break;
28261
- }
28692
+ function loop(i) {
28693
+ if (i >= sequence.length)
28694
+ return sequence.slice(0, i);
28695
+ return chain(takeWhile(sequence[i], i), (keep) => {
28696
+ if (!keep)
28697
+ return sequence.slice(0, i);
28698
+ return loop(i + 1);
28699
+ });
28262
28700
  }
28263
- return sequence.slice(0, i);
28701
+ return loop(0);
28264
28702
  }, sequence.length),
28265
28703
  [`${name}-nth`]: createNthNormalExpression(() => sequence, sequence.length),
28266
28704
  [`${name}?`]: createNumberPredNormalExpression(n => sequence.includes(n)),
@@ -28313,14 +28751,16 @@ function createTakeWhileNormalExpression(takeWhileFunction, maxLength) {
28313
28751
  evaluate: (params, sourceCodeInfo, contextStack, { executeFunction }) => {
28314
28752
  const fn = params[0];
28315
28753
  assertFunctionLike(fn, sourceCodeInfo);
28316
- const result = takeWhileFunction((value, index) => !!executeFunction(fn, [value, index], contextStack), sourceCodeInfo);
28317
- if (typeof result[0] === 'number') {
28318
- /* v8 ignore next 3 */
28319
- if (result.some(n => n > Number.MAX_SAFE_INTEGER)) {
28320
- throw new LitsError('Result exceeds maximum safe integer', sourceCodeInfo);
28754
+ const result = takeWhileFunction((value, index) => chain(executeFunction(fn, [value, index], contextStack), val => !!val), sourceCodeInfo);
28755
+ return chain(result, (resolved) => {
28756
+ if (typeof resolved[0] === 'number') {
28757
+ /* v8 ignore next 3 */
28758
+ if (resolved.some(n => n > Number.MAX_SAFE_INTEGER)) {
28759
+ throw new LitsError('Result exceeds maximum safe integer', sourceCodeInfo);
28760
+ }
28321
28761
  }
28322
- }
28323
- return result;
28762
+ return resolved;
28763
+ });
28324
28764
  },
28325
28765
  arity: typeof maxLength === 'number' ? { max: 1 } : toFixedArity(1),
28326
28766
  };
@@ -29789,38 +30229,30 @@ function update(coll, key, fn, params, contextStack, executeFunction, sourceCode
29789
30229
  if (isObj(coll)) {
29790
30230
  assertString(key, sourceCodeInfo);
29791
30231
  const result = { ...coll };
29792
- result[key] = executeFunction(fn, [result[key], ...params], contextStack, sourceCodeInfo);
29793
- return result;
30232
+ return chain(executeFunction(fn, [result[key], ...params], contextStack, sourceCodeInfo), (val) => {
30233
+ result[key] = val;
30234
+ return result;
30235
+ });
29794
30236
  }
29795
30237
  else {
29796
30238
  assertNumber(key, sourceCodeInfo);
29797
30239
  const intKey = toNonNegativeInteger(key);
29798
30240
  assertNumber(intKey, sourceCodeInfo, { lte: coll.length });
29799
30241
  if (Array.isArray(coll)) {
29800
- const result = coll.map((elem, index) => {
30242
+ return chain(mapSequential(Array.from({ length: coll.length + (intKey === coll.length ? 1 : 0) }), (_, index) => {
29801
30243
  if (intKey === index)
29802
- return executeFunction(fn, [elem, ...params], contextStack, sourceCodeInfo);
29803
- return elem;
29804
- });
29805
- if (intKey === coll.length)
29806
- result[intKey] = executeFunction(fn, [undefined, ...params], contextStack, sourceCodeInfo);
29807
- return result;
30244
+ return executeFunction(fn, [coll[index], ...params], contextStack, sourceCodeInfo);
30245
+ return coll[index];
30246
+ }), result => result);
29808
30247
  }
29809
30248
  else {
29810
- const result = coll.split('').map((elem, index) => {
30249
+ const chars = coll.split('');
30250
+ return chain(mapSequential(Array.from({ length: chars.length + (intKey === chars.length ? 1 : 0) }), (_, index) => {
29811
30251
  if (intKey === index) {
29812
- return asString(executeFunction(fn, [elem, ...params], contextStack, sourceCodeInfo), sourceCodeInfo, {
29813
- char: true,
29814
- });
30252
+ return chain(executeFunction(fn, [chars[index], ...params], contextStack, sourceCodeInfo), val => asString(val, sourceCodeInfo, { char: true }));
29815
30253
  }
29816
- return elem;
29817
- });
29818
- if (intKey === coll.length) {
29819
- result[intKey] = asString(executeFunction(fn, [undefined, ...params], contextStack, sourceCodeInfo), sourceCodeInfo, {
29820
- char: true,
29821
- });
29822
- }
29823
- return result.join('');
30254
+ return chars[index];
30255
+ }), result => result.join(''));
29824
30256
  }
29825
30257
  }
29826
30258
  }
@@ -30025,13 +30457,18 @@ cu.update(
30025
30457
  const parentKey = asStringOrNumber(keys[keys.length - 2], sourceCodeInfo);
30026
30458
  if (Array.isArray(innerCollMeta.parent)) {
30027
30459
  assertNumber(parentKey, sourceCodeInfo);
30028
- innerCollMeta.parent[parentKey] = update(innerCollMeta.coll, lastKey, fn, params, contextStack, executeFunction, sourceCodeInfo);
30460
+ return chain(update(innerCollMeta.coll, lastKey, fn, params, contextStack, executeFunction, sourceCodeInfo), (updated) => {
30461
+ innerCollMeta.parent[parentKey] = updated;
30462
+ return coll;
30463
+ });
30029
30464
  }
30030
30465
  else {
30031
30466
  assertString(parentKey, sourceCodeInfo);
30032
- innerCollMeta.parent[parentKey] = update(innerCollMeta.coll, lastKey, fn, params, contextStack, executeFunction, sourceCodeInfo);
30467
+ return chain(update(innerCollMeta.coll, lastKey, fn, params, contextStack, executeFunction, sourceCodeInfo), (updated) => {
30468
+ innerCollMeta.parent[parentKey] = updated;
30469
+ return coll;
30470
+ });
30033
30471
  }
30034
- return coll;
30035
30472
  },
30036
30473
  arity: { min: 3 },
30037
30474
  docs: {
@@ -30092,21 +30529,15 @@ cu.update-in(
30092
30529
  assertColl(coll, sourceCodeInfo);
30093
30530
  assertFunctionLike(fn, sourceCodeInfo);
30094
30531
  if (Array.isArray(coll)) {
30095
- const result = coll.filter((elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo));
30096
- return result;
30532
+ return filterSequential(coll, (elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo));
30097
30533
  }
30098
30534
  if (typeof coll === 'string') {
30099
- return coll
30100
- .split('')
30101
- .filter((elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo))
30102
- .join('');
30535
+ return chain(filterSequential(coll.split(''), (elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo)), filtered => filtered.join(''));
30103
30536
  }
30104
- return Object.entries(coll)
30105
- .filter(([key, value]) => executeFunction(fn, [value, key], contextStack, sourceCodeInfo))
30106
- .reduce((result, [key, value]) => {
30537
+ return chain(filterSequential(Object.entries(coll), ([key, value]) => executeFunction(fn, [value, key], contextStack, sourceCodeInfo)), filtered => filtered.reduce((result, [key, value]) => {
30107
30538
  result[key] = value;
30108
30539
  return result;
30109
- }, {});
30540
+ }, {}));
30110
30541
  },
30111
30542
  arity: toFixedArity(2),
30112
30543
  docs: {
@@ -30134,18 +30565,17 @@ cu.update-in(
30134
30565
  assertColl(coll, sourceCodeInfo);
30135
30566
  assertFunctionLike(fn, sourceCodeInfo);
30136
30567
  if (Array.isArray(coll)) {
30137
- return coll.map((elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo));
30568
+ return mapSequential(coll, (elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo));
30138
30569
  }
30139
30570
  if (typeof coll === 'string') {
30140
- return coll
30141
- .split('')
30142
- .map((elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo))
30143
- .join('');
30571
+ return chain(mapSequential(coll.split(''), (elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo)), mapped => mapped.join(''));
30144
30572
  }
30145
- return Object.entries(coll)
30146
- .reduce((acc, [key, value]) => {
30147
- acc[key] = executeFunction(fn, [value, key], contextStack, sourceCodeInfo);
30148
- return acc;
30573
+ const entries = Object.entries(coll);
30574
+ return reduceSequential(entries, (acc, [key, value]) => {
30575
+ return chain(executeFunction(fn, [value, key], contextStack, sourceCodeInfo), (result) => {
30576
+ acc[key] = result;
30577
+ return acc;
30578
+ });
30149
30579
  }, {});
30150
30580
  },
30151
30581
  arity: toFixedArity(2),
@@ -30180,23 +30610,17 @@ cu.update-in(
30180
30610
  assertString(initial, sourceCodeInfo);
30181
30611
  if (coll.length === 0)
30182
30612
  return initial;
30183
- return coll.split('').reduce((result, elem, index) => {
30184
- return executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30185
- }, initial);
30613
+ return reduceSequential(coll.split('').map((elem, index) => ({ elem, index })), (result, { elem, index }) => executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo), initial);
30186
30614
  }
30187
30615
  else if (Array.isArray(coll)) {
30188
30616
  if (coll.length === 0)
30189
30617
  return initial;
30190
- return coll.reduce((result, elem, index) => {
30191
- return executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30192
- }, initial);
30618
+ return reduceSequential(coll.map((elem, index) => ({ elem, index })), (result, { elem, index }) => executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo), initial);
30193
30619
  }
30194
30620
  else {
30195
30621
  if (Object.keys(coll).length === 0)
30196
30622
  return initial;
30197
- return Object.entries(coll).reduce((result, [key, elem]) => {
30198
- return executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo);
30199
- }, initial);
30623
+ return reduceSequential(Object.entries(coll), (result, [key, elem]) => executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo), initial);
30200
30624
  }
30201
30625
  },
30202
30626
  arity: toFixedArity(3),
@@ -30232,23 +30656,17 @@ cu.update-in(
30232
30656
  if (typeof coll === 'string') {
30233
30657
  if (coll.length === 0)
30234
30658
  return initial;
30235
- return coll.split('').reduceRight((result, elem) => {
30236
- return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30237
- }, initial);
30659
+ return reduceSequential(Array.from(coll.split('')).reverse(), (result, elem) => executeFunction(fn, [result, elem], contextStack, sourceCodeInfo), initial);
30238
30660
  }
30239
30661
  else if (Array.isArray(coll)) {
30240
30662
  if (coll.length === 0)
30241
30663
  return initial;
30242
- return coll.reduceRight((result, elem) => {
30243
- return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30244
- }, initial);
30664
+ return reduceSequential(Array.from(coll).reverse(), (result, elem) => executeFunction(fn, [result, elem], contextStack, sourceCodeInfo), initial);
30245
30665
  }
30246
30666
  else {
30247
30667
  if (Object.keys(coll).length === 0)
30248
30668
  return initial;
30249
- return Object.entries(coll).reduceRight((result, [, elem]) => {
30250
- return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30251
- }, initial);
30669
+ return reduceSequential(Object.entries(coll).reverse(), (result, [, elem]) => executeFunction(fn, [result, elem], contextStack, sourceCodeInfo), initial);
30252
30670
  }
30253
30671
  },
30254
30672
  arity: toFixedArity(3),
@@ -30277,23 +30695,17 @@ cu.update-in(
30277
30695
  if (typeof coll === 'string') {
30278
30696
  if (coll.length === 0)
30279
30697
  return initial;
30280
- return coll.split('').reduceRight((result, elem, index) => {
30281
- return executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30282
- }, initial);
30698
+ return reduceSequential(Array.from(coll.split('')).reverse().map((elem, _, arr) => ({ elem, index: arr.length - 1 - _ })), (result, { elem, index }) => executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo), initial);
30283
30699
  }
30284
30700
  else if (Array.isArray(coll)) {
30285
30701
  if (coll.length === 0)
30286
30702
  return initial;
30287
- return coll.reduceRight((result, elem, index) => {
30288
- return executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30289
- }, initial);
30703
+ return reduceSequential(Array.from(coll).reverse().map((elem, _, arr) => ({ elem, index: arr.length - 1 - _ })), (result, { elem, index }) => executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo), initial);
30290
30704
  }
30291
30705
  else {
30292
30706
  if (Object.keys(coll).length === 0)
30293
30707
  return initial;
30294
- return Object.entries(coll).reduceRight((result, [key, elem]) => {
30295
- return executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo);
30296
- }, initial);
30708
+ return reduceSequential(Object.entries(coll).reverse(), (result, [key, elem]) => executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo), initial);
30297
30709
  }
30298
30710
  },
30299
30711
  arity: toFixedArity(3),
@@ -30327,40 +30739,20 @@ cu.update-in(
30327
30739
  assertFunctionLike(fn, sourceCodeInfo);
30328
30740
  assertAny(initial, sourceCodeInfo);
30329
30741
  assertAny(initial, sourceCodeInfo);
30330
- if (typeof coll === 'string') {
30331
- assertString(initial, sourceCodeInfo);
30332
- if (coll.length === 0)
30333
- return [initial];
30334
- const resultArray = [initial];
30335
- coll.split('').reduce((result, elem) => {
30336
- const newVal = executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30742
+ const items = typeof coll === 'string'
30743
+ ? (assertString(initial, sourceCodeInfo), coll.length === 0 ? [] : coll.split(''))
30744
+ : Array.isArray(coll)
30745
+ ? (coll.length === 0 ? [] : Array.from(coll))
30746
+ : (Object.keys(coll).length === 0 ? [] : Object.entries(coll).map(([, v]) => v));
30747
+ if (items.length === 0)
30748
+ return [initial];
30749
+ const resultArray = [initial];
30750
+ return chain(reduceSequential(items, (result, elem) => {
30751
+ return chain(executeFunction(fn, [result, elem], contextStack, sourceCodeInfo), (newVal) => {
30337
30752
  resultArray.push(newVal);
30338
30753
  return newVal;
30339
- }, initial);
30340
- return resultArray;
30341
- }
30342
- else if (Array.isArray(coll)) {
30343
- if (coll.length === 0)
30344
- return [initial];
30345
- const resultArray = [initial];
30346
- coll.reduce((result, elem) => {
30347
- const newVal = executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30348
- resultArray.push(newVal);
30349
- return newVal;
30350
- }, initial);
30351
- return resultArray;
30352
- }
30353
- else {
30354
- if (Object.keys(coll).length === 0)
30355
- return [initial];
30356
- const resultArray = [initial];
30357
- Object.entries(coll).reduce((result, [, elem]) => {
30358
- const newVal = executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30359
- resultArray.push(newVal);
30360
- return newVal;
30361
- }, initial);
30362
- return resultArray;
30363
- }
30754
+ });
30755
+ }, initial), () => resultArray);
30364
30756
  },
30365
30757
  arity: toFixedArity(3),
30366
30758
  docs: {
@@ -30395,40 +30787,21 @@ cu.reductions(
30395
30787
  assertFunctionLike(fn, sourceCodeInfo);
30396
30788
  assertAny(initial, sourceCodeInfo);
30397
30789
  assertAny(initial, sourceCodeInfo);
30398
- if (typeof coll === 'string') {
30399
- assertString(initial, sourceCodeInfo);
30400
- if (coll.length === 0)
30401
- return [initial];
30402
- const resultArray = [initial];
30403
- coll.split('').reduce((result, elem, index) => {
30404
- const newVal = executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30405
- resultArray.push(newVal);
30406
- return newVal;
30407
- }, initial);
30408
- return resultArray;
30409
- }
30410
- else if (Array.isArray(coll)) {
30411
- if (coll.length === 0)
30412
- return [initial];
30413
- const resultArray = [initial];
30414
- coll.reduce((result, elem, index) => {
30415
- const newVal = executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30416
- resultArray.push(newVal);
30417
- return newVal;
30418
- }, initial);
30419
- return resultArray;
30420
- }
30421
- else {
30422
- if (Object.keys(coll).length === 0)
30423
- return [initial];
30424
- const resultArray = [initial];
30425
- Object.entries(coll).reduce((result, [key, elem]) => {
30426
- const newVal = executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo);
30790
+ const toIndexedItem = (elem, key) => ({ elem, key });
30791
+ const items = typeof coll === 'string'
30792
+ ? (assertString(initial, sourceCodeInfo), coll.length === 0 ? [] : coll.split('').map((elem, index) => toIndexedItem(elem, index)))
30793
+ : Array.isArray(coll)
30794
+ ? (coll.length === 0 ? [] : coll.map((elem, index) => toIndexedItem(elem, index)))
30795
+ : (Object.keys(coll).length === 0 ? [] : Object.entries(coll).map(([key, v]) => toIndexedItem(v, key)));
30796
+ if (items.length === 0)
30797
+ return [initial];
30798
+ const resultArray = [initial];
30799
+ return chain(reduceSequential(items, (result, { elem, key }) => {
30800
+ return chain(executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo), (newVal) => {
30427
30801
  resultArray.push(newVal);
30428
30802
  return newVal;
30429
- }, initial);
30430
- return resultArray;
30431
- }
30803
+ });
30804
+ }, initial), () => resultArray);
30432
30805
  },
30433
30806
  arity: toFixedArity(3),
30434
30807
  docs: {
@@ -30491,11 +30864,12 @@ cu.reductions(
30491
30864
  evaluate: ([coll, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
30492
30865
  assertColl(coll, sourceCodeInfo);
30493
30866
  assertFunctionLike(fn, sourceCodeInfo);
30494
- if (Array.isArray(coll))
30495
- return coll.every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30496
- if (typeof coll === 'string')
30497
- return coll.split('').every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30498
- return Object.entries(coll).every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30867
+ const arr = Array.isArray(coll)
30868
+ ? coll
30869
+ : typeof coll === 'string'
30870
+ ? coll.split('')
30871
+ : Object.entries(coll);
30872
+ return everySequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30499
30873
  },
30500
30874
  arity: toFixedArity(2),
30501
30875
  docs: {
@@ -30545,11 +30919,12 @@ cu.every?(
30545
30919
  evaluate: ([coll, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
30546
30920
  assertFunctionLike(fn, sourceCodeInfo);
30547
30921
  assertColl(coll, sourceCodeInfo);
30548
- if (Array.isArray(coll))
30549
- return coll.some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30550
- if (typeof coll === 'string')
30551
- return coll.split('').some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30552
- return Object.entries(coll).some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30922
+ const arr = Array.isArray(coll)
30923
+ ? coll
30924
+ : typeof coll === 'string'
30925
+ ? coll.split('')
30926
+ : Object.entries(coll);
30927
+ return someSequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30553
30928
  },
30554
30929
  arity: toFixedArity(2),
30555
30930
  docs: {
@@ -30597,11 +30972,12 @@ cu.any?(
30597
30972
  evaluate: ([coll, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
30598
30973
  assertFunctionLike(fn, sourceCodeInfo);
30599
30974
  assertColl(coll, sourceCodeInfo);
30600
- if (Array.isArray(coll))
30601
- return !coll.some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30602
- if (typeof coll === 'string')
30603
- return !coll.split('').some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30604
- return !Object.entries(coll).some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30975
+ const arr = Array.isArray(coll)
30976
+ ? coll
30977
+ : typeof coll === 'string'
30978
+ ? coll.split('')
30979
+ : Object.entries(coll);
30980
+ return chain(someSequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)), result => !result);
30605
30981
  },
30606
30982
  arity: toFixedArity(2),
30607
30983
  docs: {
@@ -30649,11 +31025,12 @@ cu.not-any?(
30649
31025
  evaluate: ([coll, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
30650
31026
  assertFunctionLike(fn, sourceCodeInfo);
30651
31027
  assertColl(coll, sourceCodeInfo);
30652
- if (Array.isArray(coll))
30653
- return !coll.every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30654
- if (typeof coll === 'string')
30655
- return !coll.split('').every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30656
- return !Object.entries(coll).every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31028
+ const arr = Array.isArray(coll)
31029
+ ? coll
31030
+ : typeof coll === 'string'
31031
+ ? coll.split('')
31032
+ : Object.entries(coll);
31033
+ return chain(everySequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)), result => !result);
30657
31034
  },
30658
31035
  arity: toFixedArity(2),
30659
31036
  docs: {
@@ -30710,14 +31087,8 @@ const sequenceUtilsFunctions = {
30710
31087
  if (seq === null)
30711
31088
  return null;
30712
31089
  assertSeq(seq, sourceCodeInfo);
30713
- if (typeof seq === 'string') {
30714
- const index = seq.split('').findIndex(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30715
- return index !== -1 ? index : null;
30716
- }
30717
- else {
30718
- const index = seq.findIndex(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30719
- return index !== -1 ? index : null;
30720
- }
31090
+ const arr = typeof seq === 'string' ? seq.split('') : seq;
31091
+ return chain(findIndexSequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)), index => index !== -1 ? index : null);
30721
31092
  },
30722
31093
  arity: toFixedArity(2),
30723
31094
  docs: {
@@ -30864,50 +31235,39 @@ su.position(
30864
31235
  assertSeq(seq, sourceCodeInfo);
30865
31236
  assertFunctionLike(keyfn, sourceCodeInfo);
30866
31237
  const comparer = defaultComparer ? null : params[2];
30867
- if (typeof seq === 'string') {
30868
- const result = seq.split('');
31238
+ const isString = typeof seq === 'string';
31239
+ const arr = isString ? seq.split('') : [...seq];
31240
+ // Pre-compute all keys using mapSequential (async-safe)
31241
+ return chain(mapSequential(arr, elem => executeFunction(keyfn, [elem], contextStack, sourceCodeInfo)), (keys) => {
30869
31242
  if (defaultComparer) {
30870
- result.sort((a, b) => {
30871
- const aKey = executeFunction(keyfn, [a], contextStack, sourceCodeInfo);
30872
- assertStringOrNumber(aKey, sourceCodeInfo);
30873
- const bKey = executeFunction(keyfn, [b], contextStack, sourceCodeInfo);
30874
- assertStringOrNumber(bKey, sourceCodeInfo);
30875
- return compare(aKey, bKey, sourceCodeInfo);
31243
+ // Create indexed pairs, sort by pre-computed keys
31244
+ const indexed = arr.map((elem, i) => ({ elem, key: keys[i] }));
31245
+ indexed.sort((a, b) => {
31246
+ assertStringOrNumber(a.key, sourceCodeInfo);
31247
+ assertStringOrNumber(b.key, sourceCodeInfo);
31248
+ return compare(a.key, b.key, sourceCodeInfo);
30876
31249
  });
31250
+ const sorted = indexed.map(x => x.elem);
31251
+ return isString ? sorted.join('') : sorted;
30877
31252
  }
30878
31253
  else {
30879
31254
  assertFunctionLike(comparer, sourceCodeInfo);
30880
- result.sort((a, b) => {
30881
- const aKey = executeFunction(keyfn, [a], contextStack, sourceCodeInfo);
30882
- const bKey = executeFunction(keyfn, [b], contextStack, sourceCodeInfo);
30883
- const compareValue = executeFunction(comparer, [aKey, bKey], contextStack, sourceCodeInfo);
31255
+ // Pre-compute keys, then need pairwise comparisons — these may also be async
31256
+ // For sort-by with custom comparer, we must use a non-async sort since
31257
+ // Array.sort requires sync comparators
31258
+ const indexed = arr.map((elem, i) => ({ elem, key: keys[i] }));
31259
+ indexed.sort((a, b) => {
31260
+ const compareValue = executeFunction(comparer, [a.key, b.key], contextStack, sourceCodeInfo);
31261
+ if (compareValue instanceof Promise) {
31262
+ throw new TypeError('Async functions cannot be used as sort-by comparators');
31263
+ }
30884
31264
  assertNumber(compareValue, sourceCodeInfo, { finite: true });
30885
31265
  return compareValue;
30886
31266
  });
31267
+ const sorted = indexed.map(x => x.elem);
31268
+ return isString ? sorted.join('') : sorted;
30887
31269
  }
30888
- return result.join('');
30889
- }
30890
- const result = [...seq];
30891
- if (defaultComparer) {
30892
- result.sort((a, b) => {
30893
- const aKey = executeFunction(keyfn, [a], contextStack, sourceCodeInfo);
30894
- assertStringOrNumber(aKey, sourceCodeInfo);
30895
- const bKey = executeFunction(keyfn, [b], contextStack, sourceCodeInfo);
30896
- assertStringOrNumber(bKey, sourceCodeInfo);
30897
- return compare(aKey, bKey, sourceCodeInfo);
30898
- });
30899
- }
30900
- else {
30901
- assertFunctionLike(comparer, sourceCodeInfo);
30902
- result.sort((a, b) => {
30903
- const aKey = executeFunction(keyfn, [a], contextStack, sourceCodeInfo);
30904
- const bKey = executeFunction(keyfn, [b], contextStack, sourceCodeInfo);
30905
- const compareValue = executeFunction(comparer, [aKey, bKey], contextStack, sourceCodeInfo);
30906
- assertNumber(compareValue, sourceCodeInfo, { finite: true });
30907
- return compareValue;
30908
- });
30909
- }
30910
- return result;
31270
+ });
30911
31271
  },
30912
31272
  arity: { min: 2, max: 3 },
30913
31273
  docs: {
@@ -30994,14 +31354,12 @@ su.position(
30994
31354
  evaluate: ([seq, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
30995
31355
  assertSeq(seq, sourceCodeInfo);
30996
31356
  assertFunctionLike(fn, sourceCodeInfo);
30997
- const result = [];
30998
- for (const item of seq) {
30999
- if (executeFunction(fn, [item], contextStack, sourceCodeInfo))
31000
- result.push(item);
31001
- else
31002
- break;
31003
- }
31004
- return typeof seq === 'string' ? result.join('') : result;
31357
+ const arr = typeof seq === 'string' ? seq.split('') : Array.from(seq);
31358
+ // Find the first index where the predicate is false
31359
+ return chain(findIndexSequential(arr, elem => chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), result => !result)), (index) => {
31360
+ const taken = index === -1 ? arr : arr.slice(0, index);
31361
+ return typeof seq === 'string' ? taken.join('') : taken;
31362
+ });
31005
31363
  },
31006
31364
  arity: toFixedArity(2),
31007
31365
  docs: {
@@ -31092,13 +31450,12 @@ su.take-while(
31092
31450
  evaluate: ([seq, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
31093
31451
  assertSeq(seq, sourceCodeInfo);
31094
31452
  assertFunctionLike(fn, sourceCodeInfo);
31095
- if (Array.isArray(seq)) {
31096
- const from = seq.findIndex(elem => !executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31097
- return seq.slice(from);
31098
- }
31099
- const charArray = seq.split('');
31100
- const from = charArray.findIndex(elem => !executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31101
- return charArray.slice(from).join('');
31453
+ const arr = Array.isArray(seq) ? seq : seq.split('');
31454
+ return chain(findIndexSequential(arr, elem => chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), result => !result)), (from) => {
31455
+ if (from === -1)
31456
+ return typeof seq === 'string' ? '' : [];
31457
+ return typeof seq === 'string' ? arr.slice(from).join('') : seq.slice(from);
31458
+ });
31102
31459
  },
31103
31460
  arity: toFixedArity(2),
31104
31461
  docs: {
@@ -31201,12 +31558,8 @@ l`,
31201
31558
  evaluate: ([input, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
31202
31559
  assertFunctionLike(fn, sourceCodeInfo);
31203
31560
  assertSeq(input, sourceCodeInfo);
31204
- if (Array.isArray(input))
31205
- return input.filter(elem => !executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31206
- return input
31207
- .split('')
31208
- .filter(elem => !executeFunction(fn, [elem], contextStack, sourceCodeInfo))
31209
- .join('');
31561
+ const arr = Array.isArray(input) ? input : input.split('');
31562
+ return chain(filterSequential(arr, elem => chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), result => !result)), filtered => typeof input === 'string' ? filtered.join('') : filtered);
31210
31563
  },
31211
31564
  arity: toFixedArity(2),
31212
31565
  docs: {
@@ -31296,10 +31649,11 @@ l`,
31296
31649
  assertSeq(seq, sourceCodeInfo);
31297
31650
  const seqIsArray = Array.isArray(seq);
31298
31651
  const arr = seqIsArray ? seq : seq.split('');
31299
- const index = arr.findIndex(elem => !executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31300
- if (index === -1)
31301
- return [seq, seqIsArray ? [] : ''];
31302
- return [seq.slice(0, index), seq.slice(index)];
31652
+ return chain(findIndexSequential(arr, elem => chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), result => !result)), (index) => {
31653
+ if (index === -1)
31654
+ return [seq, seqIsArray ? [] : ''];
31655
+ return [seq.slice(0, index), seq.slice(index)];
31656
+ });
31303
31657
  },
31304
31658
  arity: toFixedArity(2),
31305
31659
  docs: {
@@ -31353,13 +31707,14 @@ l`,
31353
31707
  assertFunctionLike(fn, sourceCodeInfo);
31354
31708
  assertSeq(seq, sourceCodeInfo);
31355
31709
  const arr = Array.isArray(seq) ? seq : seq.split('');
31356
- return arr.reduce((result, val) => {
31357
- const key = executeFunction(fn, [val], contextStack, sourceCodeInfo);
31358
- assertString(key, sourceCodeInfo);
31359
- if (!collHasKey(result, key))
31360
- result[key] = [];
31361
- result[key].push(val);
31362
- return result;
31710
+ return reduceSequential(arr, (result, val) => {
31711
+ return chain(executeFunction(fn, [val], contextStack, sourceCodeInfo), (key) => {
31712
+ assertString(key, sourceCodeInfo);
31713
+ if (!collHasKey(result, key))
31714
+ result[key] = [];
31715
+ result[key].push(val);
31716
+ return result;
31717
+ });
31363
31718
  }, {});
31364
31719
  },
31365
31720
  arity: toFixedArity(2),
@@ -31468,17 +31823,17 @@ l`,
31468
31823
  assertFunctionLike(fn, sourceCodeInfo);
31469
31824
  assertSeq(seq, sourceCodeInfo);
31470
31825
  const isStringSeq = typeof seq === 'string';
31471
- let oldValue;
31472
- const result = (isStringSeq ? seq.split('') : seq).reduce((acc, elem) => {
31473
- const value = executeFunction(fn, [elem], contextStack, sourceCodeInfo);
31474
- if (value !== oldValue) {
31475
- acc.push([]);
31476
- oldValue = value;
31477
- }
31478
- acc[acc.length - 1].push(elem);
31479
- return acc;
31480
- }, []);
31481
- return isStringSeq ? result.map(elem => elem.join('')) : result;
31826
+ const arr = isStringSeq ? seq.split('') : seq;
31827
+ return chain(reduceSequential(arr, (acc, elem) => {
31828
+ return chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), (value) => {
31829
+ if (value !== acc.oldValue) {
31830
+ acc.result.push([]);
31831
+ acc.oldValue = value;
31832
+ }
31833
+ acc.result[acc.result.length - 1].push(elem);
31834
+ return acc;
31835
+ });
31836
+ }, { result: [], oldValue: undefined }), ({ result }) => isStringSeq ? result.map(elem => elem.join('')) : result);
31482
31837
  },
31483
31838
  arity: toFixedArity(2),
31484
31839
  docs: {