@poe-platform/safe-bash 0.1.726 → 0.1.727

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 (207) hide show
  1. package/dist/safe-bash/chunks/{chunk-6VZX7ESE.js → chunk-26N7BLXE.js} +3 -3
  2. package/dist/safe-bash/chunks/{chunk-ZZ7JQBPX.js → chunk-4A2OLEML.js} +2 -2
  3. package/dist/safe-bash/chunks/{chunk-LTREB3HX.js → chunk-54MC6XF5.js} +4 -4
  4. package/dist/safe-bash/chunks/{chunk-Z3CCN6Y2.js → chunk-6J5FUESH.js} +2 -2
  5. package/dist/safe-bash/chunks/{chunk-YR5RZBWS.js → chunk-6TBFZ5JE.js} +2 -2
  6. package/dist/safe-bash/chunks/{chunk-6HJNJ625.js → chunk-7MMYQG3P.js} +2 -2
  7. package/dist/safe-bash/chunks/{chunk-WTZZX4LV.js → chunk-A4MB2KXV.js} +2 -2
  8. package/dist/safe-bash/chunks/{chunk-EM2JW7ZH.js → chunk-ATYJKRBZ.js} +2 -2
  9. package/dist/safe-bash/chunks/{chunk-VV24PRPB.js → chunk-AZQOEGP3.js} +1050 -101
  10. package/dist/safe-bash/chunks/chunk-AZQOEGP3.js.map +7 -0
  11. package/dist/safe-bash/chunks/{chunk-EFMXWUYE.js → chunk-B6JEJ6AT.js} +2 -2
  12. package/dist/safe-bash/chunks/{chunk-JFGGQUYP.js → chunk-BFXGHT3R.js} +2 -2
  13. package/dist/safe-bash/chunks/{chunk-RP5IZOOR.js → chunk-BJYV5J65.js} +1050 -101
  14. package/dist/safe-bash/chunks/chunk-BJYV5J65.js.map +7 -0
  15. package/dist/safe-bash/chunks/{chunk-HNHOPD3P.js → chunk-DIEFWGXO.js} +46 -26
  16. package/dist/safe-bash/chunks/{chunk-HNHOPD3P.js.map → chunk-DIEFWGXO.js.map} +2 -2
  17. package/dist/safe-bash/chunks/{chunk-SME47P4B.js → chunk-DV6EZOKM.js} +46 -26
  18. package/dist/safe-bash/chunks/{chunk-SME47P4B.js.map → chunk-DV6EZOKM.js.map} +2 -2
  19. package/dist/safe-bash/chunks/{chunk-646RTREQ.js → chunk-EEDOYIPC.js} +2 -2
  20. package/dist/safe-bash/chunks/{chunk-OFAAHWL5.js → chunk-GCQ5A2T2.js} +2 -2
  21. package/dist/safe-bash/chunks/{chunk-MJW4KSKV.js → chunk-GLPJEDLY.js} +2 -2
  22. package/dist/safe-bash/chunks/{chunk-FOOJWH7J.js → chunk-GO5OKPBO.js} +4 -4
  23. package/dist/safe-bash/chunks/{chunk-5JANWFJ3.js → chunk-GWYXCCGO.js} +4 -4
  24. package/dist/safe-bash/chunks/{chunk-DPHRNHPT.js → chunk-H6KJ4L22.js} +2 -2
  25. package/dist/safe-bash/chunks/{chunk-FLX2BZBF.js → chunk-HGBYIDAK.js} +4 -4
  26. package/dist/safe-bash/chunks/{chunk-VGJIDLZM.js → chunk-KS5VSJYM.js} +15 -8
  27. package/dist/safe-bash/chunks/chunk-KS5VSJYM.js.map +7 -0
  28. package/dist/safe-bash/chunks/{chunk-PO3Z7W3A.js → chunk-MUHYGUFD.js} +4 -4
  29. package/dist/safe-bash/chunks/{chunk-5DLGYPGJ.js → chunk-PDSTXORC.js} +126 -58
  30. package/dist/safe-bash/chunks/chunk-PDSTXORC.js.map +7 -0
  31. package/dist/safe-bash/chunks/{chunk-TIHMU25L.js → chunk-PQ37GDJF.js} +3 -3
  32. package/dist/safe-bash/chunks/{chunk-OTM5RCWZ.js → chunk-QNEDWYC2.js} +15 -8
  33. package/dist/safe-bash/chunks/chunk-QNEDWYC2.js.map +7 -0
  34. package/dist/safe-bash/chunks/{chunk-LZ7FUN6K.js → chunk-RHHDOA67.js} +5 -5
  35. package/dist/safe-bash/chunks/{chunk-DSCL3VA2.js → chunk-SJ3B26XV.js} +4 -4
  36. package/dist/safe-bash/chunks/{chunk-6JBTVWHH.js → chunk-SWACYEIT.js} +5 -5
  37. package/dist/safe-bash/chunks/{chunk-7UJW7TYR.js → chunk-TD6NWAUK.js} +126 -58
  38. package/dist/safe-bash/chunks/chunk-TD6NWAUK.js.map +7 -0
  39. package/dist/safe-bash/chunks/{chunk-Q4I754TV.js → chunk-THOBFD5C.js} +2 -2
  40. package/dist/safe-bash/chunks/{chunk-XELW5O3R.js → chunk-U2STHT7S.js} +2 -2
  41. package/dist/safe-bash/chunks/{chunk-5X4SOSTT.js → chunk-UJHE5PTK.js} +2 -2
  42. package/dist/safe-bash/chunks/{chunk-B6YFFKYG.js → chunk-X4I3RHTC.js} +5 -1
  43. package/dist/safe-bash/chunks/chunk-X4I3RHTC.js.map +7 -0
  44. package/dist/safe-bash/chunks/{chunk-YOK5UHA7.js → chunk-XKXFX3RH.js} +5 -1
  45. package/dist/safe-bash/chunks/chunk-XKXFX3RH.js.map +7 -0
  46. package/dist/safe-bash/chunks/{chunk-PLCYP2E5.js → chunk-XV4K3UUF.js} +2 -2
  47. package/dist/safe-bash/commands/csplit/index.browser.js +2 -2
  48. package/dist/safe-bash/commands/factor/index.browser.js +2 -2
  49. package/dist/safe-bash/commands/getopt/index.browser.js +2 -2
  50. package/dist/safe-bash/commands/hexdump/index.browser.js +2 -2
  51. package/dist/safe-bash/commands/iconv/index.browser.js +2 -2
  52. package/dist/safe-bash/commands/internal.d.ts.map +1 -1
  53. package/dist/safe-bash/commands/internal.js +4 -3
  54. package/dist/safe-bash/commands/internal.js.map +1 -1
  55. package/dist/safe-bash/commands/line-endings/index.browser.js +2 -2
  56. package/dist/safe-bash/commands/llm/index.browser.js +4 -4
  57. package/dist/safe-bash/commands/network/index.browser.js +4 -4
  58. package/dist/safe-bash/commands/node/index.browser.js +4 -4
  59. package/dist/safe-bash/commands/pandoc/index.js.map +1 -1
  60. package/dist/safe-bash/commands/pr/index.browser.js +3 -3
  61. package/dist/safe-bash/commands/python/index.browser.js +2 -2
  62. package/dist/safe-bash/commands/record-buffer.d.ts.map +1 -1
  63. package/dist/safe-bash/commands/record-buffer.js +12 -4
  64. package/dist/safe-bash/commands/record-buffer.js.map +1 -1
  65. package/dist/safe-bash/commands/regex-execution/bounded-provider.d.ts.map +1 -1
  66. package/dist/safe-bash/commands/regex-execution/bounded-provider.js +75 -8
  67. package/dist/safe-bash/commands/regex-execution/bounded-provider.js.map +1 -1
  68. package/dist/safe-bash/commands/regex-execution/ere/limits.d.ts +1 -1
  69. package/dist/safe-bash/commands/regex-execution/ere/limits.d.ts.map +1 -1
  70. package/dist/safe-bash/commands/regex-execution/ere/limits.js +6 -4
  71. package/dist/safe-bash/commands/regex-execution/ere/limits.js.map +1 -1
  72. package/dist/safe-bash/commands/regex-execution/portable.d.ts.map +1 -1
  73. package/dist/safe-bash/commands/regex-execution/portable.js +7 -2
  74. package/dist/safe-bash/commands/regex-execution/portable.js.map +1 -1
  75. package/dist/safe-bash/commands/regex-execution/protocol.d.ts +2 -0
  76. package/dist/safe-bash/commands/regex-execution/protocol.d.ts.map +1 -1
  77. package/dist/safe-bash/commands/regex-execution/protocol.js +26 -0
  78. package/dist/safe-bash/commands/regex-execution/protocol.js.map +1 -1
  79. package/dist/safe-bash/commands/regex-execution/utf8.d.ts +1 -1
  80. package/dist/safe-bash/commands/regex-execution/utf8.d.ts.map +1 -1
  81. package/dist/safe-bash/commands/regex-execution/utf8.js +26 -2
  82. package/dist/safe-bash/commands/regex-execution/utf8.js.map +1 -1
  83. package/dist/safe-bash/commands/search/grep.d.ts.map +1 -1
  84. package/dist/safe-bash/commands/search/grep.js +109 -15
  85. package/dist/safe-bash/commands/search/grep.js.map +1 -1
  86. package/dist/safe-bash/commands/search/matcher.d.ts +1 -1
  87. package/dist/safe-bash/commands/search/matcher.d.ts.map +1 -1
  88. package/dist/safe-bash/commands/search/matcher.js +2 -0
  89. package/dist/safe-bash/commands/search/matcher.js.map +1 -1
  90. package/dist/safe-bash/commands/search/shared.d.ts.map +1 -1
  91. package/dist/safe-bash/commands/search/shared.js +23 -12
  92. package/dist/safe-bash/commands/search/shared.js.map +1 -1
  93. package/dist/safe-bash/commands/standard.d.ts.map +1 -1
  94. package/dist/safe-bash/commands/standard.js +22 -0
  95. package/dist/safe-bash/commands/standard.js.map +1 -1
  96. package/dist/safe-bash/commands/streams.d.ts.map +1 -1
  97. package/dist/safe-bash/commands/streams.js +54 -10
  98. package/dist/safe-bash/commands/streams.js.map +1 -1
  99. package/dist/safe-bash/commands/structured/input.d.ts.map +1 -1
  100. package/dist/safe-bash/commands/structured/input.js +484 -55
  101. package/dist/safe-bash/commands/structured/input.js.map +1 -1
  102. package/dist/safe-bash/commands/structured/interpreter.d.ts +3 -0
  103. package/dist/safe-bash/commands/structured/interpreter.d.ts.map +1 -1
  104. package/dist/safe-bash/commands/structured/interpreter.js +157 -1
  105. package/dist/safe-bash/commands/structured/interpreter.js.map +1 -1
  106. package/dist/safe-bash/commands/structured/jq.d.ts.map +1 -1
  107. package/dist/safe-bash/commands/structured/jq.js +50 -24
  108. package/dist/safe-bash/commands/structured/jq.js.map +1 -1
  109. package/dist/safe-bash/commands/structured/limits.d.ts +5 -0
  110. package/dist/safe-bash/commands/structured/limits.d.ts.map +1 -1
  111. package/dist/safe-bash/commands/structured/limits.js +51 -36
  112. package/dist/safe-bash/commands/structured/limits.js.map +1 -1
  113. package/dist/safe-bash/commands/structured/numbers.d.ts +1 -0
  114. package/dist/safe-bash/commands/structured/numbers.d.ts.map +1 -1
  115. package/dist/safe-bash/commands/structured/numbers.js +32 -0
  116. package/dist/safe-bash/commands/structured/numbers.js.map +1 -1
  117. package/dist/safe-bash/commands/text-programs/awk-reader.d.ts +1 -0
  118. package/dist/safe-bash/commands/text-programs/awk-reader.d.ts.map +1 -1
  119. package/dist/safe-bash/commands/text-programs/awk-reader.js +41 -5
  120. package/dist/safe-bash/commands/text-programs/awk-reader.js.map +1 -1
  121. package/dist/safe-bash/commands/text-programs/awk-retention.d.ts +1 -0
  122. package/dist/safe-bash/commands/text-programs/awk-retention.d.ts.map +1 -1
  123. package/dist/safe-bash/commands/text-programs/awk-retention.js +9 -0
  124. package/dist/safe-bash/commands/text-programs/awk-retention.js.map +1 -1
  125. package/dist/safe-bash/commands/text-programs/awk-runtime.d.ts +13 -0
  126. package/dist/safe-bash/commands/text-programs/awk-runtime.d.ts.map +1 -1
  127. package/dist/safe-bash/commands/text-programs/awk-runtime.js +421 -83
  128. package/dist/safe-bash/commands/text-programs/awk-runtime.js.map +1 -1
  129. package/dist/safe-bash/commands/text-programs/awk-values.d.ts.map +1 -1
  130. package/dist/safe-bash/commands/text-programs/awk-values.js +21 -0
  131. package/dist/safe-bash/commands/text-programs/awk-values.js.map +1 -1
  132. package/dist/safe-bash/commands/text-programs/regex.d.ts +15 -2
  133. package/dist/safe-bash/commands/text-programs/regex.d.ts.map +1 -1
  134. package/dist/safe-bash/commands/text-programs/regex.js +501 -13
  135. package/dist/safe-bash/commands/text-programs/regex.js.map +1 -1
  136. package/dist/safe-bash/commands/text-programs/sed.d.ts.map +1 -1
  137. package/dist/safe-bash/commands/text-programs/sed.js +242 -102
  138. package/dist/safe-bash/commands/text-programs/sed.js.map +1 -1
  139. package/dist/safe-bash/commands/text-programs/shared.d.ts +2 -0
  140. package/dist/safe-bash/commands/text-programs/shared.d.ts.map +1 -1
  141. package/dist/safe-bash/commands/text-programs/shared.js +36 -0
  142. package/dist/safe-bash/commands/text-programs/shared.js.map +1 -1
  143. package/dist/safe-bash/commands/text.d.ts.map +1 -1
  144. package/dist/safe-bash/commands/text.js +136 -19
  145. package/dist/safe-bash/commands/text.js.map +1 -1
  146. package/dist/safe-bash/commands/tsort/index.browser.js +2 -2
  147. package/dist/safe-bash/commands/xml/index.browser.js +5 -5
  148. package/dist/safe-bash/commands/yq/index.browser.js +5 -5
  149. package/dist/safe-bash/contracts/yield.d.ts +1 -0
  150. package/dist/safe-bash/contracts/yield.d.ts.map +1 -1
  151. package/dist/safe-bash/contracts/yield.js +3 -0
  152. package/dist/safe-bash/contracts/yield.js.map +1 -1
  153. package/dist/safe-bash/core.browser.js +1052 -256
  154. package/dist/safe-bash/core.browser.js.map +3 -3
  155. package/dist/safe-bash/plugins/composition.d.ts +1 -0
  156. package/dist/safe-bash/plugins/composition.d.ts.map +1 -1
  157. package/dist/safe-bash/plugins/composition.js +80 -2
  158. package/dist/safe-bash/plugins/composition.js.map +1 -1
  159. package/dist/safe-bash/plugins/index.d.ts.map +1 -1
  160. package/dist/safe-bash/plugins/index.js +2 -2
  161. package/dist/safe-bash/plugins/index.js.map +1 -1
  162. package/dist/safe-bash-command-fold/arguments.d.ts +1 -1
  163. package/dist/safe-bash-command-fold/contracts.d.ts +2 -1
  164. package/dist/safe-bash-command-fold/engine.d.ts +1 -1
  165. package/dist/safe-bash-command-fold/index.js +10 -8
  166. package/dist/safe-bash-command-fold/index.js.map +2 -2
  167. package/dist/safe-bash-command-sips/index.js +231 -67
  168. package/dist/safe-bash-command-sips/index.js.map +2 -2
  169. package/dist/safe-bash-command-unrtf/contracts.d.ts +5 -2
  170. package/dist/safe-bash-command-unrtf/index.js +6 -5
  171. package/dist/safe-bash-command-unrtf/index.js.map +2 -2
  172. package/dist/safe-playwright-cloudflare/browser-run-code.js +22 -6
  173. package/package.json +2 -2
  174. package/dist/safe-bash/chunks/chunk-5DLGYPGJ.js.map +0 -7
  175. package/dist/safe-bash/chunks/chunk-7UJW7TYR.js.map +0 -7
  176. package/dist/safe-bash/chunks/chunk-B6YFFKYG.js.map +0 -7
  177. package/dist/safe-bash/chunks/chunk-OTM5RCWZ.js.map +0 -7
  178. package/dist/safe-bash/chunks/chunk-RP5IZOOR.js.map +0 -7
  179. package/dist/safe-bash/chunks/chunk-VGJIDLZM.js.map +0 -7
  180. package/dist/safe-bash/chunks/chunk-VV24PRPB.js.map +0 -7
  181. package/dist/safe-bash/chunks/chunk-YOK5UHA7.js.map +0 -7
  182. /package/dist/safe-bash/chunks/{chunk-6VZX7ESE.js.map → chunk-26N7BLXE.js.map} +0 -0
  183. /package/dist/safe-bash/chunks/{chunk-ZZ7JQBPX.js.map → chunk-4A2OLEML.js.map} +0 -0
  184. /package/dist/safe-bash/chunks/{chunk-LTREB3HX.js.map → chunk-54MC6XF5.js.map} +0 -0
  185. /package/dist/safe-bash/chunks/{chunk-Z3CCN6Y2.js.map → chunk-6J5FUESH.js.map} +0 -0
  186. /package/dist/safe-bash/chunks/{chunk-YR5RZBWS.js.map → chunk-6TBFZ5JE.js.map} +0 -0
  187. /package/dist/safe-bash/chunks/{chunk-6HJNJ625.js.map → chunk-7MMYQG3P.js.map} +0 -0
  188. /package/dist/safe-bash/chunks/{chunk-WTZZX4LV.js.map → chunk-A4MB2KXV.js.map} +0 -0
  189. /package/dist/safe-bash/chunks/{chunk-EM2JW7ZH.js.map → chunk-ATYJKRBZ.js.map} +0 -0
  190. /package/dist/safe-bash/chunks/{chunk-EFMXWUYE.js.map → chunk-B6JEJ6AT.js.map} +0 -0
  191. /package/dist/safe-bash/chunks/{chunk-JFGGQUYP.js.map → chunk-BFXGHT3R.js.map} +0 -0
  192. /package/dist/safe-bash/chunks/{chunk-646RTREQ.js.map → chunk-EEDOYIPC.js.map} +0 -0
  193. /package/dist/safe-bash/chunks/{chunk-OFAAHWL5.js.map → chunk-GCQ5A2T2.js.map} +0 -0
  194. /package/dist/safe-bash/chunks/{chunk-MJW4KSKV.js.map → chunk-GLPJEDLY.js.map} +0 -0
  195. /package/dist/safe-bash/chunks/{chunk-FOOJWH7J.js.map → chunk-GO5OKPBO.js.map} +0 -0
  196. /package/dist/safe-bash/chunks/{chunk-5JANWFJ3.js.map → chunk-GWYXCCGO.js.map} +0 -0
  197. /package/dist/safe-bash/chunks/{chunk-DPHRNHPT.js.map → chunk-H6KJ4L22.js.map} +0 -0
  198. /package/dist/safe-bash/chunks/{chunk-FLX2BZBF.js.map → chunk-HGBYIDAK.js.map} +0 -0
  199. /package/dist/safe-bash/chunks/{chunk-PO3Z7W3A.js.map → chunk-MUHYGUFD.js.map} +0 -0
  200. /package/dist/safe-bash/chunks/{chunk-TIHMU25L.js.map → chunk-PQ37GDJF.js.map} +0 -0
  201. /package/dist/safe-bash/chunks/{chunk-LZ7FUN6K.js.map → chunk-RHHDOA67.js.map} +0 -0
  202. /package/dist/safe-bash/chunks/{chunk-DSCL3VA2.js.map → chunk-SJ3B26XV.js.map} +0 -0
  203. /package/dist/safe-bash/chunks/{chunk-6JBTVWHH.js.map → chunk-SWACYEIT.js.map} +0 -0
  204. /package/dist/safe-bash/chunks/{chunk-Q4I754TV.js.map → chunk-THOBFD5C.js.map} +0 -0
  205. /package/dist/safe-bash/chunks/{chunk-XELW5O3R.js.map → chunk-U2STHT7S.js.map} +0 -0
  206. /package/dist/safe-bash/chunks/{chunk-5X4SOSTT.js.map → chunk-UJHE5PTK.js.map} +0 -0
  207. /package/dist/safe-bash/chunks/{chunk-PLCYP2E5.js.map → chunk-XV4K3UUF.js.map} +0 -0
@@ -11,7 +11,7 @@ function textSize(value) {
11
11
  }
12
12
  function ownScalar(value) {
13
13
  return value.kind === "string" || value.kind === "numeric"
14
- ? { ...value, text: Buffer.from(value.text, "latin1").toString("latin1") } : value;
14
+ ? { ...value, text: value.text.length < 13 ? value.text : Buffer.from(value.text, "latin1").toString("latin1") } : value;
15
15
  }
16
16
  class Flow {
17
17
  kind;
@@ -79,7 +79,13 @@ export class AwkRuntime {
79
79
  store(name) { return this.frames.at(-1)?.has(name) ? this.frames.at(-1) : this.variables; }
80
80
  get(name) { return this.store(name).get(name) ?? unset; }
81
81
  getScalar(name) { return scalar(this.get(name)); }
82
- asText(value) { return text(value, text(this.getScalar("CONVFMT"), undefined, this.budget), this.budget); }
82
+ asText(value) {
83
+ if (value.kind === "string" || value.kind === "numeric")
84
+ return value.text;
85
+ if (value.kind === "unset")
86
+ return "";
87
+ return text(value, text(this.getScalar("CONVFMT"), undefined, this.budget), this.budget);
88
+ }
83
89
  varText(name) { return this.asText(this.getScalar(name)); }
84
90
  retainName(path) {
85
91
  this.context.signal.throwIfAborted();
@@ -88,8 +94,8 @@ export class AwkRuntime {
88
94
  storeScalar(store, name, value) {
89
95
  if (value.kind === "string" || value.kind === "numeric")
90
96
  this.budget.check(value.text);
91
- const owned = this.retention.replace(textSize(store.get(name)), textSize(value), () => ownScalar(value));
92
- store.set(name, owned);
97
+ this.retention.admit(textSize(store.get(name)), textSize(value));
98
+ store.set(name, ownScalar(value));
93
99
  }
94
100
  bindArray(store, name, array) {
95
101
  let allocation = this.arrays.get(array);
@@ -144,14 +150,14 @@ export class AwkRuntime {
144
150
  this.budget.check(key);
145
151
  if (value.kind === "string" || value.kind === "numeric")
146
152
  this.budget.check(value.text);
147
- const existing = array.entries.has(key);
153
+ const existingValue = array.entries.get(key);
154
+ const existing = existingValue !== undefined || array.entries.has(key);
148
155
  if (!existing && this.entries >= (this.budget.options.maxArrayEntries ?? Infinity))
149
156
  throw new ProgramError("array entry limit exceeded");
150
- const previous = textSize(array.entries.get(key)), next = textSize(value) + (existing ? 0 : key.length);
151
- const owned = this.retention.replace(previous, next, () => ({
152
- key: existing ? key : Buffer.from(key, "latin1").toString("latin1"), value: ownScalar(value),
153
- }));
154
- array.entries.set(owned.key, owned.value);
157
+ const previous = textSize(existingValue), next = textSize(value) + (existing ? 0 : key.length);
158
+ this.retention.admit(previous, next);
159
+ const ownedKey = existing || key.length < 13 ? key : Buffer.from(key, "latin1").toString("latin1");
160
+ array.entries.set(ownedKey, ownScalar(value));
155
161
  this.arrays.get(array).bytes += next - previous;
156
162
  if (!existing)
157
163
  this.entries++;
@@ -167,6 +173,50 @@ export class AwkRuntime {
167
173
  return pattern;
168
174
  }
169
175
  async regex(expression) { return expression.kind === "regex" ? expression.pattern : this.pattern(this.asText(await this.scalarExpression(expression))); }
176
+ splitSync(value, separator, paragraph) {
177
+ if (!paragraph && value.length < 256 && (separator === " " || separator.length === 1)) {
178
+ this.budget.step(value.length);
179
+ const maxFields = this.budget.options.maxFields ?? Infinity;
180
+ const parts = [];
181
+ if (separator === " ") {
182
+ let start = -1;
183
+ for (let index = 0; index < value.length; index++) {
184
+ const ch = value.charCodeAt(index);
185
+ if (ch === 32 || ch === 9 || ch === 10) {
186
+ if (start >= 0) {
187
+ if (parts.length >= maxFields)
188
+ throw new ProgramError("field count limit exceeded");
189
+ parts.push(inputValue(value.slice(start, index)));
190
+ start = -1;
191
+ }
192
+ }
193
+ else if (start < 0)
194
+ start = index;
195
+ }
196
+ if (start >= 0) {
197
+ if (parts.length >= maxFields)
198
+ throw new ProgramError("field count limit exceeded");
199
+ parts.push(inputValue(value.slice(start, value.length)));
200
+ }
201
+ return parts;
202
+ }
203
+ if (value !== "") {
204
+ let start = 0;
205
+ let idx;
206
+ while ((idx = value.indexOf(separator, start)) >= 0) {
207
+ if (parts.length >= maxFields)
208
+ throw new ProgramError("field count limit exceeded");
209
+ parts.push(inputValue(value.slice(start, idx)));
210
+ start = idx + 1;
211
+ }
212
+ if (parts.length >= maxFields)
213
+ throw new ProgramError("field count limit exceeded");
214
+ parts.push(inputValue(value.slice(start, value.length)));
215
+ }
216
+ return parts;
217
+ }
218
+ return this.split(value, separator, paragraph);
219
+ }
170
220
  async split(value, separator, paragraph = false) {
171
221
  // Admit the byte scan/copy before building fields; regex matching charges its own work.
172
222
  this.budget.step(value.length);
@@ -180,7 +230,7 @@ export class AwkRuntime {
180
230
  let start = -1;
181
231
  for (let index = 0; index < value.length; index++) {
182
232
  if (index % 256 === 0)
183
- await this.budget.checkpoint();
233
+ await this.budget.checkpointSync();
184
234
  if (" \t\n".includes(value[index])) {
185
235
  if (start >= 0) {
186
236
  append(start, index);
@@ -198,15 +248,30 @@ export class AwkRuntime {
198
248
  throw new ProgramError("field count limit exceeded");
199
249
  for (let index = 0; index < value.length; index++) {
200
250
  if (index % 256 === 0)
201
- await this.budget.checkpoint();
251
+ await this.budget.checkpointSync();
202
252
  append(index, index + 1);
203
253
  }
204
254
  }
205
255
  else if (typeof separator === "string" && separator.length === 1) {
256
+ if (!paragraph && value.length < 256) {
257
+ if (value !== "") {
258
+ let start = 0;
259
+ let idx;
260
+ while ((idx = value.indexOf(separator, start)) >= 0) {
261
+ append(start, idx);
262
+ start = idx + 1;
263
+ }
264
+ append(start, value.length);
265
+ }
266
+ return parts;
267
+ }
206
268
  let start = 0;
207
269
  for (let index = 0; index < value.length; index++) {
208
- if (index % 256 === 0)
209
- await this.budget.checkpoint();
270
+ if (index > 0 && index % 256 === 0) {
271
+ const p = this.budget.checkpointSync();
272
+ if (p)
273
+ await p;
274
+ }
210
275
  if (value[index] === separator || paragraph && value[index] === "\n") {
211
276
  append(start, index);
212
277
  start = index + 1;
@@ -221,7 +286,7 @@ export class AwkRuntime {
221
286
  if (paragraph)
222
287
  for (let index = start; index < end; index++) {
223
288
  if (index % 256 === 0)
224
- await this.budget.checkpoint();
289
+ await this.budget.checkpointSync();
225
290
  if (value[index] === "\n") {
226
291
  append(start, index);
227
292
  start = index + 1;
@@ -232,7 +297,7 @@ export class AwkRuntime {
232
297
  let consumed = 0;
233
298
  let search = 0;
234
299
  while (search <= value.length) {
235
- await this.budget.checkpoint();
300
+ await this.budget.checkpointSync();
236
301
  const match = await matcher.find(value, this.budget, search);
237
302
  if (!match)
238
303
  break;
@@ -249,10 +314,17 @@ export class AwkRuntime {
249
314
  }
250
315
  return parts;
251
316
  }
252
- async setRecord(record, value = inputValue(record)) {
317
+ setRecordSync(record, value = inputValue(record)) {
253
318
  this.budget.check(record);
254
- const fields = await this.split(record, this.varText("FS"), this.varText("RS") === "");
255
- this.replaceRecord(record, fields, value);
319
+ const fields = this.splitSync(record, this.varText("FS"), this.varText("RS") === "");
320
+ if (!(fields instanceof Promise)) {
321
+ this.replaceRecord(record, fields, value);
322
+ return;
323
+ }
324
+ return fields.then(resolved => { this.replaceRecord(record, resolved, value); });
325
+ }
326
+ async setRecord(record, value = inputValue(record)) {
327
+ await this.setRecordSync(record, value);
256
328
  }
257
329
  replaceRecord(record, fields, value = string(record)) {
258
330
  let fieldBytes = 0;
@@ -261,12 +333,9 @@ export class AwkRuntime {
261
333
  this.budget.check(field.text);
262
334
  fieldBytes += textSize(field);
263
335
  }
264
- const owned = this.retention.replace(this.record.length + this.fieldBytes, record.length + fieldBytes, () => ({
265
- record: Buffer.from(record, "latin1").toString("latin1"),
266
- fields: fields.map((field, index) => field === this.fields[index] ? field : ownScalar(field)),
267
- }));
268
- this.record = owned.record;
269
- this.fields = owned.fields;
336
+ this.retention.admit(this.record.length + this.fieldBytes, record.length + fieldBytes);
337
+ this.record = record;
338
+ this.fields = fields;
270
339
  this.fieldBytes = fieldBytes;
271
340
  this.recordValue = value.kind === "string" || value.kind === "numeric" ? { ...value, text: this.record } : value;
272
341
  this.variables.set("NF", numeric(fields.length));
@@ -294,7 +363,21 @@ export class AwkRuntime {
294
363
  const record = this.join(fields.map(value => this.asText(value)), this.varText("OFS"));
295
364
  this.replaceRecord(record, fields);
296
365
  }
297
- async key(items) {
366
+ key(items) {
367
+ if (items.length === 1) {
368
+ const first = this.scalarExpression(items[0]);
369
+ if (!(first instanceof Promise)) {
370
+ const k = this.asText(first);
371
+ this.budget.step(2);
372
+ if (k.length > this.budget.maxBufferBytes)
373
+ throw new ProgramError("text buffer limit exceeded");
374
+ this.budget.step(k.length);
375
+ return k;
376
+ }
377
+ }
378
+ return this.keySlow(items);
379
+ }
380
+ async keySlow(items) {
298
381
  const pieces = [];
299
382
  for (const item of items)
300
383
  pieces.push(this.asText(await this.scalarExpression(item)));
@@ -336,76 +419,237 @@ export class AwkRuntime {
336
419
  throw new ProgramError("non-finite arithmetic result");
337
420
  return result;
338
421
  }
339
- async scalarExpression(expression) { return scalar(await this.evaluate(expression)); }
340
- async evaluate(expression) {
422
+ scalarExpression(expression) {
423
+ const val = this.evaluate(expression);
424
+ return val instanceof Promise ? val.then(scalar) : scalar(val);
425
+ }
426
+ evaluate(expression) {
341
427
  this.budget.step();
342
428
  switch (expression.kind) {
343
429
  case "number": return numeric(expression.value);
344
430
  case "string": return string(expression.value);
345
- case "regex": return numeric((await expression.pattern.find(this.record, this.budget)) ? 1 : 0);
431
+ case "regex": return expression.pattern.find(this.record, this.budget).then(m => numeric(m ? 1 : 0));
346
432
  case "variable": return this.get(expression.name);
347
- case "field":
348
- case "array": return (await this.reference(expression)).get();
433
+ case "field": {
434
+ const idxVal = this.scalarExpression(expression.index);
435
+ if (!(idxVal instanceof Promise)) {
436
+ const index = Math.trunc(number(idxVal));
437
+ if (!Number.isSafeInteger(index) || index < 0 || index > (this.budget.options.maxFields ?? Infinity))
438
+ throw new ProgramError("invalid or excessive field index");
439
+ return index === 0 ? this.recordValue : this.fields[index - 1] ?? unset;
440
+ }
441
+ return idxVal.then(resolved => {
442
+ const index = Math.trunc(number(resolved));
443
+ if (!Number.isSafeInteger(index) || index < 0 || index > (this.budget.options.maxFields ?? Infinity))
444
+ throw new ProgramError("invalid or excessive field index");
445
+ return index === 0 ? this.recordValue : this.fields[index - 1] ?? unset;
446
+ });
447
+ }
448
+ case "array": {
449
+ const array = this.array(expression.name);
450
+ const k = this.key(expression.indexes);
451
+ if (!(k instanceof Promise)) {
452
+ let existing = array.entries.get(k);
453
+ if (existing === undefined && !array.entries.has(k)) {
454
+ this.arraySet(array, k, unset);
455
+ existing = unset;
456
+ }
457
+ return existing;
458
+ }
459
+ return k.then(resolvedKey => {
460
+ let existing = array.entries.get(resolvedKey);
461
+ if (existing === undefined && !array.entries.has(resolvedKey)) {
462
+ this.arraySet(array, resolvedKey, unset);
463
+ existing = unset;
464
+ }
465
+ return existing;
466
+ });
467
+ }
349
468
  case "getline": return this.getline(expression);
350
469
  case "tuple": throw new ProgramError("tuple is only valid as an array membership key");
351
- case "conditional": return this.evaluate(truth(await this.scalarExpression(expression.condition)) ? expression.yes : expression.no);
470
+ case "conditional": {
471
+ const cond = this.scalarExpression(expression.condition);
472
+ return cond instanceof Promise ? cond.then(c => this.evaluate(truth(c) ? expression.yes : expression.no)) : this.evaluate(truth(cond) ? expression.yes : expression.no);
473
+ }
352
474
  case "unary": {
353
475
  if (expression.operator === "++" || expression.operator === "--") {
354
- const reference = await this.reference(expression.operand);
355
- const previous = number(scalar(reference.get()));
356
- const next = previous + (expression.operator === "++" ? 1 : -1);
357
- await reference.set(numeric(next));
358
- return numeric(expression.postfix ? previous : next);
476
+ if (expression.operand.kind === "variable") {
477
+ const name = expression.operand.name;
478
+ const previous = number(scalar(this.get(name)));
479
+ const next = previous + (expression.operator === "++" ? 1 : -1);
480
+ this.set(name, numeric(next));
481
+ return numeric(expression.postfix ? previous : next);
482
+ }
483
+ if (expression.operand.kind === "array") {
484
+ const array = this.array(expression.operand.name);
485
+ const k = this.key(expression.operand.indexes);
486
+ if (!(k instanceof Promise)) {
487
+ let current = array.entries.get(k);
488
+ if (current === undefined && !array.entries.has(k)) {
489
+ this.arraySet(array, k, unset);
490
+ current = unset;
491
+ }
492
+ const previous = number(scalar(current));
493
+ const next = previous + (expression.operator === "++" ? 1 : -1);
494
+ this.arraySet(array, k, numeric(next));
495
+ return numeric(expression.postfix ? previous : next);
496
+ }
497
+ return k.then(resolvedKey => {
498
+ let current = array.entries.get(resolvedKey);
499
+ if (current === undefined && !array.entries.has(resolvedKey)) {
500
+ this.arraySet(array, resolvedKey, unset);
501
+ current = unset;
502
+ }
503
+ const previous = number(scalar(current));
504
+ const next = previous + (expression.operator === "++" ? 1 : -1);
505
+ this.arraySet(array, resolvedKey, numeric(next));
506
+ return numeric(expression.postfix ? previous : next);
507
+ });
508
+ }
509
+ return this.evaluateUnarySlow(expression);
359
510
  }
360
- const operand = await this.scalarExpression(expression.operand);
361
- return numeric(expression.operator === "!" ? truth(operand) ? 0 : 1 : expression.operator === "-" ? -number(operand) : number(operand));
511
+ const operand = this.scalarExpression(expression.operand);
512
+ if (!(operand instanceof Promise)) {
513
+ return numeric(expression.operator === "!" ? truth(operand) ? 0 : 1 : expression.operator === "-" ? -number(operand) : number(operand));
514
+ }
515
+ return operand.then(op => numeric(expression.operator === "!" ? truth(op) ? 0 : 1 : expression.operator === "-" ? -number(op) : number(op)));
362
516
  }
363
517
  case "binary": {
364
518
  const operator = expression.operator;
365
- if (["=", "+=", "-=", "*=", "/=", "%=", "^="].includes(operator)) {
366
- const reference = await this.reference(expression.left);
367
- const previous = operator === "=" ? unset : scalar(reference.get());
368
- let value = await this.scalarExpression(expression.right);
369
- if (operator !== "=")
370
- value = numeric(this.arithmetic(operator[0], number(previous), number(value)));
371
- await reference.set(value);
372
- return value;
519
+ if (operator === "=" || operator === "+=" || operator === "-=" || operator === "*=" || operator === "/=" || operator === "%=" || operator === "^=") {
520
+ if (expression.left.kind === "variable") {
521
+ const name = expression.left.name;
522
+ const previous = operator === "=" ? unset : scalar(this.get(name));
523
+ const rightVal = this.scalarExpression(expression.right);
524
+ if (!(rightVal instanceof Promise)) {
525
+ const value = operator === "=" ? rightVal : numeric(this.arithmetic(operator[0], number(previous), number(rightVal)));
526
+ this.set(name, value);
527
+ return value;
528
+ }
529
+ return rightVal.then(resolved => {
530
+ const value = operator === "=" ? resolved : numeric(this.arithmetic(operator[0], number(previous), number(resolved)));
531
+ this.set(name, value);
532
+ return value;
533
+ });
534
+ }
535
+ else if (expression.left.kind === "array") {
536
+ const array = this.array(expression.left.name);
537
+ const k = this.key(expression.left.indexes);
538
+ if (!(k instanceof Promise)) {
539
+ let current = operator === "=" ? unset : array.entries.get(k);
540
+ if (operator !== "=" && current === undefined && !array.entries.has(k)) {
541
+ this.arraySet(array, k, unset);
542
+ current = unset;
543
+ }
544
+ const previous = scalar(current);
545
+ const rightVal = this.scalarExpression(expression.right);
546
+ if (!(rightVal instanceof Promise)) {
547
+ const value = operator === "=" ? rightVal : numeric(this.arithmetic(operator[0], number(previous), number(rightVal)));
548
+ this.arraySet(array, k, value);
549
+ return value;
550
+ }
551
+ return rightVal.then(resolved => {
552
+ const value = operator === "=" ? resolved : numeric(this.arithmetic(operator[0], number(previous), number(resolved)));
553
+ this.arraySet(array, k, value);
554
+ return value;
555
+ });
556
+ }
557
+ return k.then(async (resolvedKey) => {
558
+ let current = operator === "=" ? unset : array.entries.get(resolvedKey);
559
+ if (operator !== "=" && current === undefined && !array.entries.has(resolvedKey)) {
560
+ this.arraySet(array, resolvedKey, unset);
561
+ current = unset;
562
+ }
563
+ const previous = scalar(current);
564
+ const resolved = await this.scalarExpression(expression.right);
565
+ const value = operator === "=" ? resolved : numeric(this.arithmetic(operator[0], number(previous), number(resolved)));
566
+ this.arraySet(array, resolvedKey, value);
567
+ return value;
568
+ });
569
+ }
570
+ return this.evaluateBinarySlow(expression);
373
571
  }
374
- if (operator === "in") {
375
- const array = this.array(expression.right.name);
376
- const key = expression.left.kind === "tuple" ? await this.key(expression.left.items) : this.asText(await this.scalarExpression(expression.left));
377
- return numeric(array.entries.has(key) ? 1 : 0);
572
+ if (operator === "in" || operator === "~" || operator === "!~") {
573
+ return this.evaluateBinarySlow(expression);
378
574
  }
379
- const left = await this.scalarExpression(expression.left);
575
+ const left = this.scalarExpression(expression.left);
576
+ if (left instanceof Promise)
577
+ return this.evaluateBinaryWithLeftPromise(expression, left);
380
578
  if (operator === "&&" && !truth(left))
381
579
  return numeric(0);
382
580
  if (operator === "||" && truth(left))
383
581
  return numeric(1);
384
- if (operator === "~" || operator === "!~") {
385
- const matched = (await (await this.regex(expression.right)).find(this.asText(left), this.budget)) !== undefined;
386
- return numeric((operator === "~" ? matched : !matched) ? 1 : 0);
387
- }
388
- const right = await this.scalarExpression(expression.right);
389
- if (operator === "&&" || operator === "||")
390
- return numeric(truth(right) ? 1 : 0);
391
- if (operator === "concat") {
392
- const leftText = this.asText(left);
393
- const rightText = this.asText(right);
394
- this.budget.step(0);
395
- if (rightText.length > this.budget.maxBufferBytes - leftText.length)
396
- throw new ProgramError("text buffer limit exceeded");
397
- this.budget.step(leftText.length + rightText.length);
398
- return string(leftText + rightText);
399
- }
400
- if (["==", "!=", "<", "<=", ">", ">="].includes(operator)) {
401
- const order = compare(left, right, this.varText("CONVFMT"), this.budget);
402
- return numeric((operator === "==" ? order === 0 : operator === "!=" ? order !== 0 : operator === "<" ? order < 0 : operator === "<=" ? order <= 0 : operator === ">" ? order > 0 : order >= 0) ? 1 : 0);
403
- }
404
- return numeric(this.arithmetic(operator, number(left), number(right)));
582
+ const right = this.scalarExpression(expression.right);
583
+ if (right instanceof Promise)
584
+ return right.then(r => this.evaluateBinarySyncOperands(operator, left, r));
585
+ return this.evaluateBinarySyncOperands(operator, left, right);
405
586
  }
406
587
  case "call": return this.call(expression.name, expression.args);
407
588
  }
408
589
  }
590
+ evaluateBinarySyncOperands(operator, left, right) {
591
+ if (operator === "&&" || operator === "||")
592
+ return numeric(truth(right) ? 1 : 0);
593
+ if (operator === "concat") {
594
+ const leftText = this.asText(left);
595
+ const rightText = this.asText(right);
596
+ this.budget.step(0);
597
+ if (rightText.length > this.budget.maxBufferBytes - leftText.length)
598
+ throw new ProgramError("text buffer limit exceeded");
599
+ this.budget.step(leftText.length + rightText.length);
600
+ return string(leftText + rightText);
601
+ }
602
+ if (operator === "==" || operator === "!=" || operator === "<" || operator === "<=" || operator === ">" || operator === ">=") {
603
+ const order = compare(left, right, this.varText("CONVFMT"), this.budget);
604
+ return numeric((operator === "==" ? order === 0 : operator === "!=" ? order !== 0 : operator === "<" ? order < 0 : operator === "<=" ? order <= 0 : operator === ">" ? order > 0 : order >= 0) ? 1 : 0);
605
+ }
606
+ return numeric(this.arithmetic(operator, number(left), number(right)));
607
+ }
608
+ async evaluateBinaryWithLeftPromise(expression, leftPromise) {
609
+ const operator = expression.operator;
610
+ const left = await leftPromise;
611
+ if (operator === "&&" && !truth(left))
612
+ return numeric(0);
613
+ if (operator === "||" && truth(left))
614
+ return numeric(1);
615
+ const right = await this.scalarExpression(expression.right);
616
+ return this.evaluateBinarySyncOperands(operator, left, right);
617
+ }
618
+ async evaluateUnarySlow(expression) {
619
+ if (expression.operator === "++" || expression.operator === "--") {
620
+ const reference = await this.reference(expression.operand);
621
+ const previous = number(scalar(reference.get()));
622
+ const next = previous + (expression.operator === "++" ? 1 : -1);
623
+ await reference.set(numeric(next));
624
+ return numeric(expression.postfix ? previous : next);
625
+ }
626
+ const operand = await this.scalarExpression(expression.operand);
627
+ return numeric(expression.operator === "!" ? truth(operand) ? 0 : 1 : expression.operator === "-" ? -number(operand) : number(operand));
628
+ }
629
+ async evaluateBinarySlow(expression) {
630
+ const operator = expression.operator;
631
+ if (["=", "+=", "-=", "*=", "/=", "%=", "^="].includes(operator)) {
632
+ const reference = await this.reference(expression.left);
633
+ const previous = operator === "=" ? unset : scalar(reference.get());
634
+ let value = await this.scalarExpression(expression.right);
635
+ if (operator !== "=")
636
+ value = numeric(this.arithmetic(operator[0], number(previous), number(value)));
637
+ await reference.set(value);
638
+ return value;
639
+ }
640
+ if (operator === "in") {
641
+ const array = this.array(expression.right.name);
642
+ const key = expression.left.kind === "tuple" ? await this.key(expression.left.items) : this.asText(await this.scalarExpression(expression.left));
643
+ return numeric(array.entries.has(key) ? 1 : 0);
644
+ }
645
+ const left = await this.scalarExpression(expression.left);
646
+ if (operator === "~" || operator === "!~") {
647
+ const matched = (await (await this.regex(expression.right)).find(this.asText(left), this.budget)) !== undefined;
648
+ return numeric((operator === "~" ? matched : !matched) ? 1 : 0);
649
+ }
650
+ const right = await this.scalarExpression(expression.right);
651
+ return this.evaluateBinarySyncOperands(operator, left, right);
652
+ }
409
653
  async getline(expression) {
410
654
  if (!expression.file) {
411
655
  const record = await this.readMainRecord();
@@ -444,7 +688,7 @@ export class AwkRuntime {
444
688
  yield* context.stdin;
445
689
  else {
446
690
  budget.step();
447
- await budget.checkpoint();
691
+ await budget.checkpointSync();
448
692
  const capabilities = await context.fs.capabilitiesFor?.(name, { signal: context.signal }) ?? context.fs.capabilities;
449
693
  context.signal.throwIfAborted();
450
694
  if (context.fs.readStream && capabilities.streamingRead !== false)
@@ -626,11 +870,52 @@ export class AwkRuntime {
626
870
  throw new ProgramError(`invalid mathematical result in '${name}'`);
627
871
  return numeric(result);
628
872
  }
873
+ executeSync(statement) {
874
+ if (!this.inspection) {
875
+ const p = this.budget.checkpointSync();
876
+ if (!p) {
877
+ if (statement.kind === "expression") {
878
+ this.budget.step();
879
+ const val = this.evaluate(statement.expression);
880
+ return val instanceof Promise ? val.then(() => undefined) : undefined;
881
+ }
882
+ if (statement.kind === "block") {
883
+ this.budget.step();
884
+ for (let i = 0; i < statement.body.length; i++) {
885
+ const res = this.executeSync(statement.body[i]);
886
+ if (res instanceof Promise) {
887
+ return this.executeBlockRemainder(statement.body, i + 1, res);
888
+ }
889
+ }
890
+ return undefined;
891
+ }
892
+ if (statement.kind === "if") {
893
+ this.budget.step();
894
+ const cond = this.scalarExpression(statement.condition);
895
+ if (!(cond instanceof Promise)) {
896
+ const branch = truth(cond) ? statement.yes : statement.no;
897
+ return branch ? this.executeSync(branch) : undefined;
898
+ }
899
+ }
900
+ }
901
+ }
902
+ return this.execute(statement);
903
+ }
904
+ async executeBlockRemainder(body, startIndex, current) {
905
+ await current;
906
+ for (let i = startIndex; i < body.length; i++) {
907
+ const res = this.executeSync(body[i]);
908
+ if (res instanceof Promise)
909
+ await res;
910
+ }
911
+ }
629
912
  async execute(statement) {
630
913
  this.budget.step();
631
914
  if (this.inspection)
632
915
  await this.inspection.observe(statement, this.phase);
633
- await this.budget.checkpoint();
916
+ const p = this.budget.checkpointSync();
917
+ if (p)
918
+ await p;
634
919
  switch (statement.kind) {
635
920
  case "block":
636
921
  for (const child of statement.body)
@@ -796,6 +1081,47 @@ export class AwkRuntime {
796
1081
  return status;
797
1082
  }
798
1083
  async readMainRecord() {
1084
+ const syncRes = this.readMainRecordSync();
1085
+ return syncRes instanceof Promise ? await syncRes : syncRes;
1086
+ }
1087
+ incrementCounter(name) {
1088
+ const current = this.variables.get(name);
1089
+ if (current && !(current instanceof AwkArray) && current.kind === "number" && !this.frames.at(-1)?.has(name)) {
1090
+ this.retention.admit(0, 0);
1091
+ this.variables.set(name, numeric(current.number + 1));
1092
+ return;
1093
+ }
1094
+ this.set(name, numeric(number(this.getScalar(name)) + 1));
1095
+ }
1096
+ readMainRecordSync() {
1097
+ if (this.mainReader) {
1098
+ this.budget.step();
1099
+ const record = this.mainReader.readSync(this.varText("RS"));
1100
+ if (typeof record === "string") {
1101
+ this.incrementCounter("NR");
1102
+ this.incrementCounter("FNR");
1103
+ return record;
1104
+ }
1105
+ if (record instanceof Promise) {
1106
+ return record.then(resolved => {
1107
+ if (resolved !== undefined) {
1108
+ this.incrementCounter("NR");
1109
+ this.incrementCounter("FNR");
1110
+ return resolved;
1111
+ }
1112
+ return this.readMainRecordSlowAfterEof();
1113
+ });
1114
+ }
1115
+ return this.readMainRecordSlowAfterEof();
1116
+ }
1117
+ return this.readMainRecordSlow();
1118
+ }
1119
+ async readMainRecordSlowAfterEof() {
1120
+ await this.mainReader?.close();
1121
+ this.mainReader = undefined;
1122
+ return this.readMainRecordSlow();
1123
+ }
1124
+ async readMainRecordSlow() {
799
1125
  while (true) {
800
1126
  this.budget.step();
801
1127
  if (!this.mainReader) {
@@ -805,7 +1131,9 @@ export class AwkRuntime {
805
1131
  const argumentOptions = this.budget.options;
806
1132
  if (this.argument > (argumentOptions?.maxArguments ?? Infinity))
807
1133
  throw new ProgramError("argument count limit exceeded");
808
- await this.budget.checkpoint();
1134
+ const p = this.budget.checkpointSync();
1135
+ if (p)
1136
+ await p;
809
1137
  const next = this.asText(this.array("ARGV").entries.get(String(this.argument++)) ?? unset);
810
1138
  if (!next)
811
1139
  continue;
@@ -833,8 +1161,8 @@ export class AwkRuntime {
833
1161
  this.mainReader = undefined;
834
1162
  continue;
835
1163
  }
836
- this.set("NR", numeric(number(this.getScalar("NR")) + 1));
837
- this.set("FNR", numeric(number(this.getScalar("FNR")) + 1));
1164
+ this.incrementCounter("NR");
1165
+ this.incrementCounter("FNR");
838
1166
  return record;
839
1167
  }
840
1168
  }
@@ -857,23 +1185,33 @@ export class AwkRuntime {
857
1185
  if (!stopped && (this.program.rules.length || this.program.end.length))
858
1186
  while (true) {
859
1187
  this.budget.step();
860
- const record = await this.readMainRecord();
1188
+ const recOrPromise = this.readMainRecordSync();
1189
+ const record = recOrPromise instanceof Promise ? await recOrPromise : recOrPromise;
861
1190
  if (record === undefined)
862
1191
  break;
863
- await this.setRecord(record);
1192
+ const setRecPromise = this.setRecordSync(record);
1193
+ if (setRecPromise instanceof Promise)
1194
+ await setRecPromise;
864
1195
  try {
865
1196
  for (let index = 0; index < this.program.rules.length; index++) {
866
1197
  const rule = this.program.rules[index];
867
- const selected = !rule.pattern || ranges.has(index) || truth(await this.scalarExpression(rule.pattern));
1198
+ let selected = !rule.pattern || ranges.has(index);
1199
+ if (!selected) {
1200
+ const patVal = this.scalarExpression(rule.pattern);
1201
+ selected = truth(patVal instanceof Promise ? await patVal : patVal);
1202
+ }
868
1203
  if (!selected)
869
1204
  continue;
870
1205
  if (rule.end) {
871
- if (truth(await this.scalarExpression(rule.end)))
1206
+ const endVal = this.scalarExpression(rule.end);
1207
+ if (truth(endVal instanceof Promise ? await endVal : endVal))
872
1208
  ranges.delete(index);
873
1209
  else
874
1210
  ranges.add(index);
875
1211
  }
876
- await this.execute(rule.action);
1212
+ const execRes = this.executeSync(rule.action);
1213
+ if (execRes instanceof Promise)
1214
+ await execRes;
877
1215
  }
878
1216
  }
879
1217
  catch (error) {