@scriptc/compiler 0.2.10 → 0.3.1

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 (584) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +7 -38
  2. package/ambient/scriptc-overrides.d.ts +1 -25
  3. package/ambient/scriptc.d.ts +1 -9
  4. package/dist/backend/cycle-analysis.test.js +1 -1
  5. package/dist/backend/cycle-mutability.d.ts +1 -1
  6. package/dist/backend/cycle-mutability.js +1 -18
  7. package/dist/backend/cycle-mutability.js.map +1 -1
  8. package/dist/backend/executable-features.d.ts +1 -1
  9. package/dist/backend/executable-features.js +3 -8
  10. package/dist/backend/executable-features.js.map +1 -1
  11. package/dist/backend/immutability.d.ts +1 -1
  12. package/dist/backend/immutability.js +1 -1
  13. package/dist/backend/immutability.test.js +1 -1
  14. package/dist/backend/library-pack.js +0 -2
  15. package/dist/backend/library-pack.js.map +1 -1
  16. package/dist/backend/linker.js +1 -1
  17. package/dist/backend/linker.js.map +1 -1
  18. package/dist/backend/llvm/bigint-wrap.d.ts +4 -0
  19. package/dist/backend/llvm/bigint-wrap.js +590 -0
  20. package/dist/backend/llvm/bigint-wrap.js.map +1 -0
  21. package/dist/backend/llvm/blocks.d.ts +2 -0
  22. package/dist/backend/llvm/blocks.js +4 -0
  23. package/dist/backend/llvm/blocks.js.map +1 -1
  24. package/dist/backend/llvm/call-lifetimes.js +15 -4
  25. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  26. package/dist/backend/llvm/call-lifetimes.test.js +14 -3
  27. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  28. package/dist/backend/llvm/checked-narrows.test.js +2 -2
  29. package/dist/backend/llvm/checked-narrows.test.js.map +1 -1
  30. package/dist/backend/llvm/classes.js +60 -21
  31. package/dist/backend/llvm/classes.js.map +1 -1
  32. package/dist/backend/llvm/classes.test.js +11 -11
  33. package/dist/backend/llvm/classes.test.js.map +1 -1
  34. package/dist/backend/llvm/common.d.ts +7 -5
  35. package/dist/backend/llvm/common.js +7 -5
  36. package/dist/backend/llvm/common.js.map +1 -1
  37. package/dist/backend/llvm/constant-callbacks.d.ts +1 -1
  38. package/dist/backend/llvm/constant-callbacks.js +13 -31
  39. package/dist/backend/llvm/constant-callbacks.js.map +1 -1
  40. package/dist/backend/llvm/constant-callbacks.test.js +1 -1
  41. package/dist/backend/llvm/dense-array-access.js +133 -45
  42. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  43. package/dist/backend/llvm/dense-array-access.test.js +54 -2
  44. package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
  45. package/dist/backend/llvm/dyn.d.ts +2 -1
  46. package/dist/backend/llvm/dyn.js +4 -73
  47. package/dist/backend/llvm/dyn.js.map +1 -1
  48. package/dist/backend/llvm/emitter.d.ts +123 -23
  49. package/dist/backend/llvm/emitter.js +729 -258
  50. package/dist/backend/llvm/emitter.js.map +1 -1
  51. package/dist/backend/llvm/emitter.test.js +17 -10
  52. package/dist/backend/llvm/emitter.test.js.map +1 -1
  53. package/dist/backend/llvm/expr-async.js +120 -43
  54. package/dist/backend/llvm/expr-async.js.map +1 -1
  55. package/dist/backend/llvm/expr-async.test.js +2 -2
  56. package/dist/backend/llvm/expr-async.test.js.map +1 -1
  57. package/dist/backend/llvm/expr-bytes.js +51 -36
  58. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  59. package/dist/backend/llvm/expr-callbacks.js +72 -3
  60. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  61. package/dist/backend/llvm/expr-calls.d.ts +1 -1
  62. package/dist/backend/llvm/expr-calls.js +159 -30
  63. package/dist/backend/llvm/expr-calls.js.map +1 -1
  64. package/dist/backend/llvm/expr-calls.test.js +132 -0
  65. package/dist/backend/llvm/expr-calls.test.js.map +1 -0
  66. package/dist/backend/llvm/expr-containers.js +25 -8
  67. package/dist/backend/llvm/expr-containers.js.map +1 -1
  68. package/dist/backend/llvm/expr-context.d.ts +2 -0
  69. package/dist/backend/llvm/expr-control.js +4 -107
  70. package/dist/backend/llvm/expr-control.js.map +1 -1
  71. package/dist/backend/llvm/expr-dispatch.d.ts +1 -2
  72. package/dist/backend/llvm/expr-dispatch.js +3 -41
  73. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  74. package/dist/backend/llvm/expr-dynamic.d.ts +1 -1
  75. package/dist/backend/llvm/expr-dynamic.js +39 -31
  76. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  77. package/dist/backend/llvm/expr-primitives.d.ts +7 -0
  78. package/dist/backend/llvm/expr-primitives.js +80 -22
  79. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  80. package/dist/backend/llvm/expr-primitives.test.js +97 -7
  81. package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
  82. package/dist/backend/llvm/expr-records.d.ts +9 -0
  83. package/dist/backend/llvm/expr-records.js +134 -16
  84. package/dist/backend/llvm/expr-records.js.map +1 -1
  85. package/dist/backend/llvm/expr-stream-bridges.d.ts +1 -1
  86. package/dist/backend/llvm/expr-stream-bridges.js +80 -1
  87. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  88. package/dist/backend/llvm/expr-stream-bridges.test.js +51 -2
  89. package/dist/backend/llvm/expr-stream-bridges.test.js.map +1 -1
  90. package/dist/backend/llvm/int32-abi.d.ts +31 -0
  91. package/dist/backend/llvm/int32-abi.js +62 -0
  92. package/dist/backend/llvm/int32-abi.js.map +1 -0
  93. package/dist/backend/llvm/int32-abi.test.js +107 -0
  94. package/dist/backend/llvm/int32-abi.test.js.map +1 -0
  95. package/dist/backend/llvm/int32-locals.d.ts +30 -0
  96. package/dist/backend/llvm/int32-locals.js +95 -0
  97. package/dist/backend/llvm/int32-locals.js.map +1 -0
  98. package/dist/backend/llvm/integer-values.d.ts +4 -0
  99. package/dist/backend/llvm/integer-values.js +30 -1
  100. package/dist/backend/llvm/integer-values.js.map +1 -1
  101. package/dist/backend/llvm/integer-views.d.ts +8 -1
  102. package/dist/backend/llvm/integer-views.js +47 -2
  103. package/dist/backend/llvm/integer-views.js.map +1 -1
  104. package/dist/backend/llvm/lazy-captures.d.ts +16 -0
  105. package/dist/backend/llvm/lazy-captures.js +88 -2
  106. package/dist/backend/llvm/lazy-captures.js.map +1 -1
  107. package/dist/backend/llvm/lazy-captures.test.js +48 -0
  108. package/dist/backend/llvm/lazy-captures.test.js.map +1 -1
  109. package/dist/backend/llvm/lib-dispatch.js +14 -1
  110. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  111. package/dist/backend/llvm/lib-filesystem.js +3 -13
  112. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  113. package/dist/backend/llvm/lib-shared.js +7 -8
  114. package/dist/backend/llvm/lib-shared.js.map +1 -1
  115. package/dist/backend/llvm/local-array-reads.js +21 -2
  116. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  117. package/dist/backend/llvm/local-array-reads.test.js +4 -3
  118. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  119. package/dist/backend/llvm/local-union-storage.test.js +3 -3
  120. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  121. package/dist/backend/llvm/map-number-lookup.d.ts +7 -0
  122. package/dist/backend/llvm/map-number-lookup.js +16 -2
  123. package/dist/backend/llvm/map-number-lookup.js.map +1 -1
  124. package/dist/backend/llvm/map-read-lifetimes.js +7 -1
  125. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  126. package/dist/backend/llvm/map-read-lifetimes.test.js +25 -8
  127. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
  128. package/dist/backend/llvm/reference-effects.js +2 -0
  129. package/dist/backend/llvm/reference-effects.js.map +1 -1
  130. package/dist/backend/llvm/reference-writes.d.ts +3 -0
  131. package/dist/backend/llvm/reference-writes.js +10 -2
  132. package/dist/backend/llvm/reference-writes.js.map +1 -1
  133. package/dist/backend/llvm/regex-matchers.d.ts +39 -0
  134. package/dist/backend/llvm/regex-matchers.js +1649 -0
  135. package/dist/backend/llvm/regex-matchers.js.map +1 -0
  136. package/dist/backend/llvm/regex-matchers.test.js +96 -0
  137. package/dist/backend/llvm/regex-matchers.test.js.map +1 -0
  138. package/dist/backend/llvm/shapes.d.ts +36 -1
  139. package/dist/backend/llvm/shapes.js +128 -16
  140. package/dist/backend/llvm/shapes.js.map +1 -1
  141. package/dist/backend/llvm/shapes.test.js +3 -3
  142. package/dist/backend/llvm/stack-unions.test.js +2 -2
  143. package/dist/backend/llvm/stack-unions.test.js.map +1 -1
  144. package/dist/backend/llvm/string-construction.test.js +3 -3
  145. package/dist/backend/llvm/string-construction.test.js.map +1 -1
  146. package/dist/backend/llvm/string-lifetimes.test.js +6 -6
  147. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  148. package/dist/backend/llvm/string-literal-equality.d.ts +22 -0
  149. package/dist/backend/llvm/string-literal-equality.js +78 -0
  150. package/dist/backend/llvm/string-literal-equality.js.map +1 -0
  151. package/dist/backend/llvm/switch-dispatch.js +59 -13
  152. package/dist/backend/llvm/switch-dispatch.js.map +1 -1
  153. package/dist/backend/llvm/switch-dispatch.test.js +72 -7
  154. package/dist/backend/llvm/switch-dispatch.test.js.map +1 -1
  155. package/dist/backend/llvm/union-retype.test.d.ts +1 -0
  156. package/dist/backend/llvm/union-retype.test.js +229 -0
  157. package/dist/backend/llvm/union-retype.test.js.map +1 -0
  158. package/dist/backend/llvm/wrapping-sums.d.ts +17 -0
  159. package/dist/backend/llvm/wrapping-sums.js +113 -0
  160. package/dist/backend/llvm/wrapping-sums.js.map +1 -0
  161. package/dist/backend/loop-polls.js +1 -0
  162. package/dist/backend/loop-polls.js.map +1 -1
  163. package/dist/backend/mangle.d.ts +9 -0
  164. package/dist/backend/mangle.js +15 -0
  165. package/dist/backend/mangle.js.map +1 -1
  166. package/dist/backend/may-throw.js +6 -12
  167. package/dist/backend/may-throw.js.map +1 -1
  168. package/dist/backend/may-throw.test.js +1 -1
  169. package/dist/backend/native/artifact-stamps.js +0 -2
  170. package/dist/backend/native/artifact-stamps.js.map +1 -1
  171. package/dist/backend/native/cache-warm.d.ts +1 -1
  172. package/dist/backend/native/cache-warm.js +2 -3
  173. package/dist/backend/native/cache-warm.js.map +1 -1
  174. package/dist/backend/native/compiler-fingerprint.d.ts +1 -1
  175. package/dist/backend/native/compiler-fingerprint.js +4 -7
  176. package/dist/backend/native/compiler-fingerprint.js.map +1 -1
  177. package/dist/backend/native/contracts.d.ts +3 -28
  178. package/dist/backend/native/driver.js +1 -3
  179. package/dist/backend/native/driver.js.map +1 -1
  180. package/dist/backend/native/executable.d.ts +0 -15
  181. package/dist/backend/native/executable.js +17 -172
  182. package/dist/backend/native/executable.js.map +1 -1
  183. package/dist/backend/native/tool-identity.js +0 -1
  184. package/dist/backend/native/tool-identity.js.map +1 -1
  185. package/dist/backend/native/vendor.d.ts +1 -1
  186. package/dist/backend/native/vendor.js +1 -1
  187. package/dist/backend/native/vendor.js.map +1 -1
  188. package/dist/backend/native-link-info-core.d.ts +0 -2
  189. package/dist/backend/native-link-info-core.js.map +1 -1
  190. package/dist/backend/native-toolchain.test.js +23 -33
  191. package/dist/backend/native-toolchain.test.js.map +1 -1
  192. package/dist/backend/publication.test.js +1 -1
  193. package/dist/backend/runtime-abi.d.ts +2 -2
  194. package/dist/backend/runtime-abi.js +2 -2
  195. package/dist/backend/runtime-pack-core.d.ts +1 -2
  196. package/dist/backend/runtime-pack-core.js +5 -14
  197. package/dist/backend/runtime-pack-core.js.map +1 -1
  198. package/dist/backend/runtime-pack-targets.test.js +3 -8
  199. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  200. package/dist/backend/runtime-pack.test.js +22 -19
  201. package/dist/backend/runtime-pack.test.js.map +1 -1
  202. package/dist/backend/target-diagnostics.d.ts +0 -5
  203. package/dist/backend/target-diagnostics.js +1 -11
  204. package/dist/backend/target-diagnostics.js.map +1 -1
  205. package/dist/backend/target-diagnostics.test.js +1 -1
  206. package/dist/backend/vendor-archives.d.ts +1 -7
  207. package/dist/backend/vendor-archives.js +9 -189
  208. package/dist/backend/vendor-archives.js.map +1 -1
  209. package/dist/backend/vendor-inputs.d.ts +0 -1
  210. package/dist/backend/vendor-inputs.js +0 -1
  211. package/dist/backend/vendor-inputs.js.map +1 -1
  212. package/dist/backend/warm-cache.js +3 -5
  213. package/dist/backend/warm-cache.js.map +1 -1
  214. package/dist/cli/command.js +4 -8
  215. package/dist/cli/command.js.map +1 -1
  216. package/dist/cli/host.d.ts +1 -1
  217. package/dist/cli/usage.d.ts +1 -5
  218. package/dist/cli/usage.js +4 -9
  219. package/dist/cli/usage.js.map +1 -1
  220. package/dist/compat/fetch-profile.d.ts +2 -2
  221. package/dist/compat/fetch-profile.js +16 -25
  222. package/dist/compat/fetch-profile.js.map +1 -1
  223. package/dist/compile-types.d.ts +2 -17
  224. package/dist/contracts/check.js +6 -6
  225. package/dist/contracts/check.js.map +1 -1
  226. package/dist/coverage/report.d.ts +5 -22
  227. package/dist/coverage/report.js +12 -76
  228. package/dist/coverage/report.js.map +1 -1
  229. package/dist/coverage/surface-manifest.d.ts +3 -3
  230. package/dist/coverage/surface-manifest.js +22 -27
  231. package/dist/coverage/surface-manifest.js.map +1 -1
  232. package/dist/coverage/verdict-cache.d.ts +1 -3
  233. package/dist/coverage/verdict-cache.js +2 -7
  234. package/dist/coverage/verdict-cache.js.map +1 -1
  235. package/dist/diagnostics/diagnostic.d.ts +11 -60
  236. package/dist/diagnostics/diagnostic.js +39 -118
  237. package/dist/diagnostics/diagnostic.js.map +1 -1
  238. package/dist/diagnostics/envelope.d.ts +3 -4
  239. package/dist/diagnostics/envelope.js +0 -9
  240. package/dist/diagnostics/envelope.js.map +1 -1
  241. package/dist/diagnostics/envelope.test.js +1 -1
  242. package/dist/diagnostics/envelope.test.js.map +1 -1
  243. package/dist/executable/executable-cache.d.ts +0 -3
  244. package/dist/executable/executable-cache.js +2 -4
  245. package/dist/executable/executable-cache.js.map +1 -1
  246. package/dist/executable/executable-cache.test.js +0 -4
  247. package/dist/executable/executable-cache.test.js.map +1 -1
  248. package/dist/executable/prepare.js +5 -2
  249. package/dist/executable/prepare.js.map +1 -1
  250. package/dist/frontend/analysis.js +10 -10
  251. package/dist/frontend/analysis.js.map +1 -1
  252. package/dist/frontend/cjs-syntax.js +0 -88
  253. package/dist/frontend/cjs-syntax.js.map +1 -1
  254. package/dist/frontend/dts-paths.d.ts +1 -1
  255. package/dist/frontend/dts-paths.js +1 -1
  256. package/dist/frontend/lowering/abstract-equality.js +1 -4
  257. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  258. package/dist/frontend/lowering/array-values.d.ts +14 -0
  259. package/dist/frontend/lowering/array-values.js +33 -11
  260. package/dist/frontend/lowering/array-values.js.map +1 -1
  261. package/dist/frontend/lowering/builtins/arguments.js +0 -13
  262. package/dist/frontend/lowering/builtins/arguments.js.map +1 -1
  263. package/dist/frontend/lowering/builtins/crypto.d.ts +0 -4
  264. package/dist/frontend/lowering/builtins/crypto.js +0 -4
  265. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  266. package/dist/frontend/lowering/builtins/json.js +1 -39
  267. package/dist/frontend/lowering/builtins/json.js.map +1 -1
  268. package/dist/frontend/lowering/builtins/module-resolution.d.ts +0 -15
  269. package/dist/frontend/lowering/builtins/module-resolution.js +5 -44
  270. package/dist/frontend/lowering/builtins/module-resolution.js.map +1 -1
  271. package/dist/frontend/lowering/builtins/numbers.d.ts +0 -6
  272. package/dist/frontend/lowering/builtins/numbers.js +6 -57
  273. package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
  274. package/dist/frontend/lowering/builtins/promises.js +4 -67
  275. package/dist/frontend/lowering/builtins/promises.js.map +1 -1
  276. package/dist/frontend/lowering/builtins/workers.js +1 -1
  277. package/dist/frontend/lowering/builtins/workers.js.map +1 -1
  278. package/dist/frontend/lowering/call-arguments.d.ts +1 -37
  279. package/dist/frontend/lowering/call-arguments.js +11 -94
  280. package/dist/frontend/lowering/call-arguments.js.map +1 -1
  281. package/dist/frontend/lowering/call-signatures.d.ts +1 -6
  282. package/dist/frontend/lowering/call-signatures.js +16 -68
  283. package/dist/frontend/lowering/call-signatures.js.map +1 -1
  284. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +19 -4
  285. package/dist/frontend/lowering/class-dynamic-dispatch.js +168 -98
  286. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  287. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +44 -4
  288. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  289. package/dist/frontend/lowering/class-method-mutations.js +0 -2
  290. package/dist/frontend/lowering/class-method-mutations.js.map +1 -1
  291. package/dist/frontend/lowering/class-protocols.js +1 -1
  292. package/dist/frontend/lowering/class-protocols.js.map +1 -1
  293. package/dist/frontend/lowering/coercions/function-adapters.js +5 -35
  294. package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
  295. package/dist/frontend/lowering/coercions/state.d.ts +0 -1
  296. package/dist/frontend/lowering/coercions/state.js +0 -1
  297. package/dist/frontend/lowering/coercions/state.js.map +1 -1
  298. package/dist/frontend/lowering/coercions/structural-plans.js +2 -4
  299. package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
  300. package/dist/frontend/lowering/coercions/structural.js +2 -12
  301. package/dist/frontend/lowering/coercions/structural.js.map +1 -1
  302. package/dist/frontend/lowering/coercions/unions.js +0 -1
  303. package/dist/frontend/lowering/coercions/unions.js.map +1 -1
  304. package/dist/frontend/lowering/containers/array-callbacks.js +49 -28
  305. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  306. package/dist/frontend/lowering/containers/array-construction.js +2 -3
  307. package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
  308. package/dist/frontend/lowering/containers/array-methods.js +10 -54
  309. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  310. package/dist/frontend/lowering/containers/array-pipelines.d.ts +54 -0
  311. package/dist/frontend/lowering/containers/array-pipelines.js +1827 -0
  312. package/dist/frontend/lowering/containers/array-pipelines.js.map +1 -0
  313. package/dist/frontend/lowering/containers/bytes.js +0 -1
  314. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  315. package/dist/frontend/lowering/containers/callback-arguments.js +2 -10
  316. package/dist/frontend/lowering/containers/callback-arguments.js.map +1 -1
  317. package/dist/frontend/lowering/containers/collection-methods.js +1 -6
  318. package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
  319. package/dist/frontend/lowering/containers/exec-result-uses.d.ts +10 -0
  320. package/dist/frontend/lowering/containers/exec-result-uses.js +88 -0
  321. package/dist/frontend/lowering/containers/exec-result-uses.js.map +1 -0
  322. package/dist/frontend/lowering/containers/indexed-objects.js +0 -2
  323. package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
  324. package/dist/frontend/lowering/containers/string-and-regexp.d.ts +0 -6
  325. package/dist/frontend/lowering/containers/string-and-regexp.js +17 -17
  326. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  327. package/dist/frontend/lowering/containers/string-replacement.d.ts +2 -1
  328. package/dist/frontend/lowering/containers/string-replacement.js +32 -136
  329. package/dist/frontend/lowering/containers/string-replacement.js.map +1 -1
  330. package/dist/frontend/lowering/devirtualize.d.ts +33 -0
  331. package/dist/frontend/lowering/devirtualize.js +199 -0
  332. package/dist/frontend/lowering/devirtualize.js.map +1 -0
  333. package/dist/frontend/lowering/expressions/evaluation-safety.js +0 -3
  334. package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -1
  335. package/dist/frontend/lowering/expressions/native-proxy.js +1 -1
  336. package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -1
  337. package/dist/frontend/lowering/expressions/nullish-assignment.js +55 -8
  338. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  339. package/dist/frontend/lowering/expressions/object-literals.d.ts +0 -8
  340. package/dist/frontend/lowering/expressions/object-literals.js +8 -35
  341. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  342. package/dist/frontend/lowering/expressions/optional-chains.d.ts +0 -4
  343. package/dist/frontend/lowering/expressions/optional-chains.js +3 -66
  344. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  345. package/dist/frontend/lowering/function-context.js +0 -1
  346. package/dist/frontend/lowering/function-context.js.map +1 -1
  347. package/dist/frontend/lowering/generic-functions.js +0 -1
  348. package/dist/frontend/lowering/generic-functions.js.map +1 -1
  349. package/dist/frontend/lowering/identifier-uses.d.ts +7 -0
  350. package/dist/frontend/lowering/identifier-uses.js +23 -0
  351. package/dist/frontend/lowering/identifier-uses.js.map +1 -0
  352. package/dist/frontend/lowering/iterator-adapters.js +51 -3
  353. package/dist/frontend/lowering/iterator-adapters.js.map +1 -1
  354. package/dist/frontend/lowering/lib-boundary.js +10 -77
  355. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  356. package/dist/frontend/lowering/lower-array-sort.js +14 -10
  357. package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
  358. package/dist/frontend/lowering/lower-array-sort.test.js +2 -2
  359. package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -1
  360. package/dist/frontend/lowering/lower-assert.js +2 -3
  361. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  362. package/dist/frontend/lowering/lower-async-iteration.js +1 -1
  363. package/dist/frontend/lowering/lower-calls.d.ts +2 -27
  364. package/dist/frontend/lowering/lower-calls.js +111 -493
  365. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  366. package/dist/frontend/lowering/lower-classes.js +12 -60
  367. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  368. package/dist/frontend/lowering/lower-comptime.js +2 -3
  369. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  370. package/dist/frontend/lowering/lower-console.d.ts +14 -0
  371. package/dist/frontend/lowering/lower-console.js +195 -0
  372. package/dist/frontend/lowering/lower-console.js.map +1 -0
  373. package/dist/frontend/lowering/lower-enums.js +5 -8
  374. package/dist/frontend/lowering/lower-enums.js.map +1 -1
  375. package/dist/frontend/lowering/lower-event-emitter.js +3 -4
  376. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  377. package/dist/frontend/lowering/lower-expando.js +3 -5
  378. package/dist/frontend/lowering/lower-expando.js.map +1 -1
  379. package/dist/frontend/lowering/lower-exprs.d.ts +0 -8
  380. package/dist/frontend/lowering/lower-exprs.js +180 -905
  381. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  382. package/dist/frontend/lowering/lower-functions.js +9 -8
  383. package/dist/frontend/lowering/lower-functions.js.map +1 -1
  384. package/dist/frontend/lowering/lower-generators.d.ts +10 -0
  385. package/dist/frontend/lowering/lower-generators.js +108 -41
  386. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  387. package/dist/frontend/lowering/lower-inspect.js +1 -50
  388. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  389. package/dist/frontend/lowering/lower-modules.d.ts +0 -43
  390. package/dist/frontend/lowering/lower-modules.js +29 -329
  391. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  392. package/dist/frontend/lowering/lower-modules.test.js +5 -5
  393. package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
  394. package/dist/frontend/lowering/lower-server.js +0 -30
  395. package/dist/frontend/lowering/lower-server.js.map +1 -1
  396. package/dist/frontend/lowering/lower-stdlib.d.ts +98 -0
  397. package/dist/frontend/lowering/{lower-island.js → lower-stdlib.js} +97 -1160
  398. package/dist/frontend/lowering/lower-stdlib.js.map +1 -0
  399. package/dist/frontend/lowering/lower-stmts.d.ts +0 -16
  400. package/dist/frontend/lowering/lower-stmts.js +58 -1016
  401. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  402. package/dist/frontend/lowering/lower-stmts.test.js +1 -1
  403. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -1
  404. package/dist/frontend/lowering/lower-stream.js +14 -13
  405. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  406. package/dist/frontend/lowering/lowerer.d.ts +42 -155
  407. package/dist/frontend/lowering/lowerer.js +192 -816
  408. package/dist/frontend/lowering/lowerer.js.map +1 -1
  409. package/dist/frontend/lowering/lowerer.test.js +4 -51
  410. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  411. package/dist/frontend/lowering/nan-coded-reads.d.ts +16 -0
  412. package/dist/frontend/lowering/nan-coded-reads.js +108 -1
  413. package/dist/frontend/lowering/nan-coded-reads.js.map +1 -1
  414. package/dist/frontend/lowering/narrowing-stability.js +1 -1
  415. package/dist/frontend/lowering/narrowing-stability.js.map +1 -1
  416. package/dist/frontend/lowering/optional-arguments.js +0 -2
  417. package/dist/frontend/lowering/optional-arguments.js.map +1 -1
  418. package/dist/frontend/lowering/runtime-optional-bounds.d.ts +4 -0
  419. package/dist/frontend/lowering/runtime-optional-bounds.js +2 -0
  420. package/dist/frontend/lowering/runtime-optional-bounds.js.map +1 -1
  421. package/dist/frontend/lowering/runtime-optional-bounds.test.js +27 -0
  422. package/dist/frontend/lowering/runtime-optional-bounds.test.js.map +1 -1
  423. package/dist/frontend/lowering/sanitize-class-types.test.js +2 -2
  424. package/dist/frontend/lowering/split-consumers.js +2 -18
  425. package/dist/frontend/lowering/split-consumers.js.map +1 -1
  426. package/dist/frontend/lowering/strict-equality.js +1 -1
  427. package/dist/frontend/lowering/strict-equality.js.map +1 -1
  428. package/dist/frontend/lowering/surfaces.d.ts +6 -45
  429. package/dist/frontend/lowering/surfaces.js +8 -73
  430. package/dist/frontend/lowering/surfaces.js.map +1 -1
  431. package/dist/frontend/lowering/union-retag.d.ts +6 -1
  432. package/dist/frontend/lowering/union-retag.js +64 -1
  433. package/dist/frontend/lowering/union-retag.js.map +1 -1
  434. package/dist/frontend/lowering/union-retag.test.js +46 -0
  435. package/dist/frontend/lowering/union-retag.test.js.map +1 -1
  436. package/dist/frontend/module-syntax.d.ts +0 -3
  437. package/dist/frontend/module-syntax.js.map +1 -1
  438. package/dist/frontend/npm-node.d.ts +0 -7
  439. package/dist/frontend/npm-node.js +0 -7
  440. package/dist/frontend/npm-node.js.map +1 -1
  441. package/dist/frontend/npm-static-rewrite-syntax.d.ts +1 -1
  442. package/dist/frontend/npm-static-rewrite-syntax.js +6 -82
  443. package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -1
  444. package/dist/frontend/npm-static.d.ts +1 -1
  445. package/dist/frontend/npm-static.js +6 -71
  446. package/dist/frontend/npm-static.js.map +1 -1
  447. package/dist/frontend/npm.d.ts +3 -319
  448. package/dist/frontend/npm.js +6 -1007
  449. package/dist/frontend/npm.js.map +1 -1
  450. package/dist/frontend/npm.test.js +2 -197
  451. package/dist/frontend/npm.test.js.map +1 -1
  452. package/dist/frontend/pipeline-native.js +1 -2
  453. package/dist/frontend/pipeline-native.js.map +1 -1
  454. package/dist/frontend/pipeline.d.ts +3 -11
  455. package/dist/frontend/pipeline.js +37 -56
  456. package/dist/frontend/pipeline.js.map +1 -1
  457. package/dist/frontend/pipeline.test.js +12 -6
  458. package/dist/frontend/pipeline.test.js.map +1 -1
  459. package/dist/frontend/program.d.ts +0 -34
  460. package/dist/frontend/program.js +12 -97
  461. package/dist/frontend/program.js.map +1 -1
  462. package/dist/frontend/provenance-core.d.ts +0 -4
  463. package/dist/frontend/provenance-core.js +4 -37
  464. package/dist/frontend/provenance-core.js.map +1 -1
  465. package/dist/frontend/provenance-registry.d.ts +0 -4
  466. package/dist/frontend/provenance-registry.js +0 -20
  467. package/dist/frontend/provenance-registry.js.map +1 -1
  468. package/dist/frontend/resolve.d.ts +0 -12
  469. package/dist/frontend/resolve.js +0 -34
  470. package/dist/frontend/resolve.js.map +1 -1
  471. package/dist/frontend/runtime-resolve.js +2 -2
  472. package/dist/frontend/runtime-resolve.js.map +1 -1
  473. package/dist/frontend/services-node.js +2 -3
  474. package/dist/frontend/services-node.js.map +1 -1
  475. package/dist/frontend/services.d.ts +1 -8
  476. package/dist/frontend/services.js +2 -22
  477. package/dist/frontend/services.js.map +1 -1
  478. package/dist/frontend/services.test.js +0 -38
  479. package/dist/frontend/services.test.js.map +1 -1
  480. package/dist/frontend/tsc-codes.js +0 -11
  481. package/dist/frontend/tsc-codes.js.map +1 -1
  482. package/dist/frontend/type-mapper.d.ts +2 -27
  483. package/dist/frontend/type-mapper.js +58 -156
  484. package/dist/frontend/type-mapper.js.map +1 -1
  485. package/dist/index.d.ts +1 -1
  486. package/dist/index.js +7 -10
  487. package/dist/index.js.map +1 -1
  488. package/dist/ir/api.d.ts +1 -1
  489. package/dist/ir/api.js +1 -1
  490. package/dist/ir/api.js.map +1 -1
  491. package/dist/ir/builtin-effects.js +2 -5
  492. package/dist/ir/builtin-effects.js.map +1 -1
  493. package/dist/ir/builtin-signatures.d.ts +1 -1
  494. package/dist/ir/builtin-signatures.js +13 -56
  495. package/dist/ir/builtin-signatures.js.map +1 -1
  496. package/dist/ir/constant-globals.test.js +1 -1
  497. package/dist/ir/constant-tables.test.js +1 -1
  498. package/dist/ir/final-fields.test.js +1 -1
  499. package/dist/ir/function-references.d.ts +12 -0
  500. package/dist/ir/function-references.js +29 -0
  501. package/dist/ir/function-references.js.map +1 -0
  502. package/dist/ir/function-references.test.d.ts +1 -0
  503. package/dist/ir/function-references.test.js +276 -0
  504. package/dist/ir/function-references.test.js.map +1 -0
  505. package/dist/ir/initializer-bindings.test.js +1 -1
  506. package/dist/ir/int32-slots.d.ts +10 -7
  507. package/dist/ir/int32-slots.js +219 -68
  508. package/dist/ir/int32-slots.js.map +1 -1
  509. package/dist/ir/int32-slots.test.js +39 -2
  510. package/dist/ir/int32-slots.test.js.map +1 -1
  511. package/dist/ir/integer-ranges.d.ts +4 -4
  512. package/dist/ir/integer-ranges.js +89 -64
  513. package/dist/ir/integer-ranges.js.map +1 -1
  514. package/dist/ir/integer-ranges.test.js +71 -9
  515. package/dist/ir/integer-ranges.test.js.map +1 -1
  516. package/dist/ir/intrinsic-signatures.js +1 -0
  517. package/dist/ir/intrinsic-signatures.js.map +1 -1
  518. package/dist/ir/ir.d.ts +64 -290
  519. package/dist/ir/ir.js +11 -259
  520. package/dist/ir/ir.js.map +1 -1
  521. package/dist/ir/ir.test.js +2 -7
  522. package/dist/ir/ir.test.js.map +1 -1
  523. package/dist/ir/runtime-features.d.ts +3 -30
  524. package/dist/ir/runtime-features.js +8 -43
  525. package/dist/ir/runtime-features.js.map +1 -1
  526. package/dist/ir/scalar-records.test.js +1 -1
  527. package/dist/ir/serialize.d.ts +1 -1
  528. package/dist/ir/serialize.js +3 -3
  529. package/dist/ir/serialize.js.map +1 -1
  530. package/dist/ir/traverse.js +4 -21
  531. package/dist/ir/traverse.js.map +1 -1
  532. package/dist/ir/unshare.test.js +1 -1
  533. package/dist/ir/validate.js +66 -213
  534. package/dist/ir/validate.js.map +1 -1
  535. package/dist/ir/validate.test.js +31 -13
  536. package/dist/ir/validate.test.js.map +1 -1
  537. package/dist/library/fence-eval.test.js +1 -1
  538. package/dist/library/int-infer.test.js +4 -4
  539. package/dist/library/library-cache.test.js +5 -5
  540. package/dist/library/prepare.js +5 -20
  541. package/dist/library/prepare.js.map +1 -1
  542. package/dist/native/cli.js +0 -2
  543. package/dist/native/cli.js.map +1 -1
  544. package/dist/native/compiler.test.js +2 -4
  545. package/dist/native/compiler.test.js.map +1 -1
  546. package/dist/native/prepare.js +2 -4
  547. package/dist/native/prepare.js.map +1 -1
  548. package/dist/native/sanitizer.js +2 -16
  549. package/dist/native/sanitizer.js.map +1 -1
  550. package/dist/native/sanitizer.test.js +0 -3
  551. package/dist/native/sanitizer.test.js.map +1 -1
  552. package/dist/startup-cache.js +0 -2
  553. package/dist/startup-cache.js.map +1 -1
  554. package/package.json +20 -20
  555. package/surface-manifest.json +80 -104
  556. package/dist/backend/llvm/expr-island.d.ts +0 -15
  557. package/dist/backend/llvm/expr-island.js +0 -709
  558. package/dist/backend/llvm/expr-island.js.map +0 -1
  559. package/dist/frontend/lowering/coercions/island.d.ts +0 -37
  560. package/dist/frontend/lowering/coercions/island.js +0 -350
  561. package/dist/frontend/lowering/coercions/island.js.map +0 -1
  562. package/dist/frontend/lowering/lower-island.d.ts +0 -229
  563. package/dist/frontend/lowering/lower-island.js.map +0 -1
  564. package/dist/frontend/lowering/lower-island.test.js +0 -56
  565. package/dist/frontend/lowering/lower-island.test.js.map +0 -1
  566. package/dist/frontend/npm-fetch-analysis.d.ts +0 -17
  567. package/dist/frontend/npm-fetch-analysis.js +0 -109
  568. package/dist/frontend/npm-fetch-analysis.js.map +0 -1
  569. package/dist/frontend/npm-fetch-analysis.test.js +0 -130
  570. package/dist/frontend/npm-fetch-analysis.test.js.map +0 -1
  571. package/dist/frontend/npm-fetch-node.d.ts +0 -2
  572. package/dist/frontend/npm-fetch-node.js +0 -12
  573. package/dist/frontend/npm-fetch-node.js.map +0 -1
  574. package/dist/frontend/npm-fetch-syntax.d.ts +0 -6
  575. package/dist/frontend/npm-fetch-syntax.js +0 -202
  576. package/dist/frontend/npm-fetch-syntax.js.map +0 -1
  577. package/dist/native/runtime-typescript.d.ts +0 -4
  578. package/dist/native/runtime-typescript.js +0 -74
  579. package/dist/native/runtime-typescript.js.map +0 -1
  580. package/dist/native/runtime-typescript.test.js +0 -41
  581. package/dist/native/runtime-typescript.test.js.map +0 -1
  582. /package/dist/{frontend/lowering/lower-island.test.d.ts → backend/llvm/expr-calls.test.d.ts} +0 -0
  583. /package/dist/{frontend/npm-fetch-analysis.test.d.ts → backend/llvm/int32-abi.test.d.ts} +0 -0
  584. /package/dist/{native/runtime-typescript.test.d.ts → backend/llvm/regex-matchers.test.d.ts} +0 -0
@@ -0,0 +1,1649 @@
1
+ /** Regex literals compiled to native matchers at build time.
2
+ *
3
+ * A regex literal whose pattern stays inside a common subset (literals,
4
+ * classes and their escapes, `.`, anchors, word boundaries, greedy and lazy
5
+ * quantifiers, alternation, capturing and non-capturing groups) gets a
6
+ * specialized LLVM function next to its immortal template. The runtime calls
7
+ * it in place of the bytecode engines for one-byte (ASCII) subjects; every
8
+ * other subject, and every pattern outside the subset, keeps the interpreter.
9
+ *
10
+ * The generated code is a direct backtracking matcher over the pattern's
11
+ * ECMAScript semantics: ordered alternation, RepeatMatcher's capture reset
12
+ * at each iteration and its empty-iteration check, greedy-first and
13
+ * lazy-first quantifiers. Choice points and the undo records of register
14
+ * writes share one explicit stack; a failure pops the newest entry and
15
+ * resumes there. Single-character loops count instead of pushing one entry
16
+ * per character, and they push nothing when no continuation can start with
17
+ * a character of their own class.
18
+ *
19
+ * Function contract (scr_runtime.h `ScrRegexMatcher`):
20
+ * `i32 (ptr s, i32 len, i32 start, ptr capture)` searches the ASCII bytes
21
+ * `s[0..len)` from `start` (one anchored attempt for sticky patterns) and,
22
+ * on a match, stores `2 * ncap` pointers into `s` (NULL for unset captures)
23
+ * and returns 1; it returns 0 when nothing matches. Called with a negative
24
+ * `len`, it returns the capture count (whole match included) so the runtime
25
+ * can check it against the compiled bytecode. */
26
+ const ASCII = 128;
27
+ const INF = -1;
28
+ /** Larger patterns keep the interpreter (binary size). */
29
+ const MAX_NODES = 400;
30
+ const MAX_COUNT = 100000;
31
+ class RegexBail {
32
+ reason;
33
+ constructor(reason) {
34
+ this.reason = reason;
35
+ }
36
+ }
37
+ function bail(reason) {
38
+ throw new RegexBail(reason);
39
+ }
40
+ function emptySet() {
41
+ const s = [];
42
+ for (let c = 0; c < ASCII; c++)
43
+ s.push(false);
44
+ return s;
45
+ }
46
+ function addRange(s, lo, hi) {
47
+ for (let c = lo < 0 ? 0 : lo; c <= hi && c < ASCII; c++)
48
+ s[c] = true;
49
+ }
50
+ function unionInto(into, from) {
51
+ for (let c = 0; c < ASCII; c++)
52
+ if (from[c])
53
+ into[c] = true;
54
+ }
55
+ function inverted(s) {
56
+ const out = [];
57
+ for (let c = 0; c < ASCII; c++)
58
+ out.push(!s[c]);
59
+ return out;
60
+ }
61
+ /** Canonicalize closure for ASCII members: with or without `u`, ASCII
62
+ * letters fold only onto their other ASCII case. */
63
+ function caseClosed(s) {
64
+ const out = s.slice();
65
+ for (let c = 65; c <= 90; c++) {
66
+ if (s[c] || s[c + 32]) {
67
+ out[c] = true;
68
+ out[c + 32] = true;
69
+ }
70
+ }
71
+ return out;
72
+ }
73
+ function sameSet(a, b) {
74
+ for (let c = 0; c < ASCII; c++)
75
+ if (a[c] !== b[c])
76
+ return false;
77
+ return true;
78
+ }
79
+ function setCount(s) {
80
+ let n = 0;
81
+ for (let c = 0; c < ASCII; c++)
82
+ if (s[c])
83
+ n++;
84
+ return n;
85
+ }
86
+ function disjoint(a, b) {
87
+ for (let c = 0; c < ASCII; c++)
88
+ if (a[c] && b[c])
89
+ return false;
90
+ return true;
91
+ }
92
+ function digitSet() {
93
+ const s = emptySet();
94
+ addRange(s, 48, 57);
95
+ return s;
96
+ }
97
+ function wordSet() {
98
+ const s = emptySet();
99
+ addRange(s, 48, 57);
100
+ addRange(s, 65, 90);
101
+ addRange(s, 97, 122);
102
+ s[95] = true;
103
+ return s;
104
+ }
105
+ /** The ASCII members of WhiteSpace and LineTerminator. */
106
+ function spaceSet() {
107
+ const s = emptySet();
108
+ addRange(s, 9, 13);
109
+ s[32] = true;
110
+ return s;
111
+ }
112
+ function isDigitCode(c) {
113
+ return c >= 48 && c <= 57;
114
+ }
115
+ function hexValue(c) {
116
+ if (c >= 48 && c <= 57)
117
+ return c - 48;
118
+ if (c >= 65 && c <= 70)
119
+ return c - 55;
120
+ if (c >= 97 && c <= 102)
121
+ return c - 87;
122
+ return -1;
123
+ }
124
+ const SYNTAX_CHARS = "^$\\.*+?()[]{}|/";
125
+ /** Parser for the supported subset. Anything else (lookaround, back
126
+ * references, `\c`, `\p`, octal escapes, non-ASCII pattern text, Annex B
127
+ * literal braces) bails, which keeps the interpreter for that literal. The
128
+ * pattern already passed the TypeScript parser, and the runtime compiles
129
+ * its bytecode (and reports its syntax errors) before any match runs. */
130
+ class RxParser {
131
+ src;
132
+ unicode;
133
+ fold;
134
+ dotAll;
135
+ multiline;
136
+ i = 0;
137
+ caps = 1;
138
+ nodes = 0;
139
+ constructor(src, unicode, fold, dotAll, multiline) {
140
+ this.src = src;
141
+ this.unicode = unicode;
142
+ this.fold = fold;
143
+ this.dotAll = dotAll;
144
+ this.multiline = multiline;
145
+ }
146
+ parse() {
147
+ const node = this.disjunction();
148
+ if (this.i !== this.src.length)
149
+ bail("unbalanced");
150
+ return node;
151
+ }
152
+ code() {
153
+ return this.i < this.src.length ? this.src.charCodeAt(this.i) : -1;
154
+ }
155
+ ch() {
156
+ return this.i < this.src.length ? this.src.charAt(this.i) : "";
157
+ }
158
+ count() {
159
+ if (++this.nodes > MAX_NODES)
160
+ bail("too large");
161
+ }
162
+ disjunction() {
163
+ const alts = [this.alternative()];
164
+ while (this.ch() === "|") {
165
+ this.i++;
166
+ alts.push(this.alternative());
167
+ }
168
+ this.count();
169
+ return alts.length === 1 ? alts[0] : { kind: "alt", alts };
170
+ }
171
+ alternative() {
172
+ const items = [];
173
+ for (;;) {
174
+ const c = this.ch();
175
+ if (c === "" || c === "|" || c === ")")
176
+ break;
177
+ const assertion = this.assertion();
178
+ if (assertion !== null) {
179
+ if (this.quantifierAhead())
180
+ bail("quantified assertion");
181
+ items.push(assertion);
182
+ continue;
183
+ }
184
+ const capsBefore = this.caps;
185
+ const atom = this.atom();
186
+ const q = this.quantifier();
187
+ if (q === null) {
188
+ items.push(atom);
189
+ continue;
190
+ }
191
+ this.count();
192
+ items.push({
193
+ kind: "rep",
194
+ body: atom,
195
+ min: q.min,
196
+ max: q.max,
197
+ greedy: q.greedy,
198
+ capFirst: capsBefore,
199
+ capEnd: this.caps,
200
+ });
201
+ }
202
+ this.count();
203
+ return items.length === 1 ? items[0] : { kind: "seq", items };
204
+ }
205
+ assertion() {
206
+ const c = this.ch();
207
+ let what = null;
208
+ if (c === "^") {
209
+ what = this.multiline ? "bolm" : "bol";
210
+ this.i++;
211
+ }
212
+ else if (c === "$") {
213
+ what = this.multiline ? "eolm" : "eol";
214
+ this.i++;
215
+ }
216
+ else if (c === "\\" && this.i + 1 < this.src.length) {
217
+ const n = this.src.charAt(this.i + 1);
218
+ if (n === "b" || n === "B") {
219
+ what = n === "b" ? "wordb" : "nwordb";
220
+ this.i += 2;
221
+ }
222
+ }
223
+ if (what === null)
224
+ return null;
225
+ this.count();
226
+ return { kind: "assert", what };
227
+ }
228
+ quantifierAhead() {
229
+ const c = this.ch();
230
+ return c === "*" || c === "+" || c === "?" || c === "{";
231
+ }
232
+ number() {
233
+ const start = this.i;
234
+ let value = 0;
235
+ while (isDigitCode(this.code())) {
236
+ value = value * 10 + (this.code() - 48);
237
+ if (value > MAX_COUNT)
238
+ bail("large count");
239
+ this.i++;
240
+ }
241
+ return this.i === start ? -1 : value;
242
+ }
243
+ quantifier() {
244
+ const c = this.ch();
245
+ let min = 0;
246
+ let max = INF;
247
+ if (c === "*") {
248
+ this.i++;
249
+ }
250
+ else if (c === "+") {
251
+ min = 1;
252
+ this.i++;
253
+ }
254
+ else if (c === "?") {
255
+ max = 1;
256
+ this.i++;
257
+ }
258
+ else if (c === "{") {
259
+ const save = this.i;
260
+ this.i++;
261
+ const lo = this.number();
262
+ if (lo < 0) {
263
+ this.i = save;
264
+ return null;
265
+ }
266
+ min = lo;
267
+ max = lo;
268
+ if (this.ch() === ",") {
269
+ this.i++;
270
+ if (this.ch() === "}") {
271
+ max = INF;
272
+ }
273
+ else {
274
+ const hi = this.number();
275
+ if (hi < 0) {
276
+ this.i = save;
277
+ return null;
278
+ }
279
+ max = hi;
280
+ }
281
+ }
282
+ if (this.ch() !== "}") {
283
+ this.i = save;
284
+ return null;
285
+ }
286
+ this.i++;
287
+ if (max !== INF && min > max)
288
+ bail("bad range");
289
+ }
290
+ else {
291
+ return null;
292
+ }
293
+ let greedy = true;
294
+ if (this.ch() === "?") {
295
+ greedy = false;
296
+ this.i++;
297
+ }
298
+ return { min, max, greedy };
299
+ }
300
+ literal(code) {
301
+ const set = emptySet();
302
+ set[code] = true;
303
+ return { kind: "set", set: this.fold ? caseClosed(set) : set };
304
+ }
305
+ atom() {
306
+ this.count();
307
+ const c = this.ch();
308
+ const code = this.code();
309
+ if (c === ".") {
310
+ this.i++;
311
+ const set = emptySet();
312
+ addRange(set, 0, ASCII - 1);
313
+ if (!this.dotAll) {
314
+ set[10] = false;
315
+ set[13] = false;
316
+ }
317
+ return { kind: "set", set };
318
+ }
319
+ if (c === "(") {
320
+ this.i++;
321
+ let index = -1;
322
+ if (this.ch() === "?") {
323
+ const n = this.i + 1 < this.src.length ? this.src.charAt(this.i + 1) : "";
324
+ if (n === ":") {
325
+ this.i += 2;
326
+ }
327
+ else if (n === "<") {
328
+ const m = this.i + 2 < this.src.length ? this.src.charAt(this.i + 2) : "";
329
+ if (m === "=" || m === "!")
330
+ bail("lookbehind");
331
+ this.i += 2;
332
+ const nameStart = this.i;
333
+ while (/[A-Za-z0-9_$]/.test(this.ch()))
334
+ this.i++;
335
+ if (this.i === nameStart || this.ch() !== ">")
336
+ bail("group name");
337
+ this.i++;
338
+ index = this.caps++;
339
+ }
340
+ else {
341
+ bail("group modifier or lookahead");
342
+ }
343
+ }
344
+ else {
345
+ index = this.caps++;
346
+ }
347
+ const body = this.disjunction();
348
+ if (this.ch() !== ")")
349
+ bail("unclosed group");
350
+ this.i++;
351
+ return index < 0 ? body : { kind: "cap", index, body };
352
+ }
353
+ if (c === "[")
354
+ return this.charClass();
355
+ if (c === "\\")
356
+ return this.atomEscape();
357
+ if (code < 0 || code >= ASCII)
358
+ bail("non-ASCII pattern text");
359
+ if ("*+?{".includes(c))
360
+ bail("nothing to repeat or literal brace");
361
+ if (c === "}" || c === "]")
362
+ bail("lone bracket");
363
+ this.i++;
364
+ return this.literal(code);
365
+ }
366
+ classEscapeSet(c) {
367
+ switch (c) {
368
+ case "d":
369
+ return digitSet();
370
+ case "D":
371
+ return inverted(digitSet());
372
+ case "w":
373
+ return wordSet();
374
+ case "W":
375
+ return inverted(wordSet());
376
+ case "s":
377
+ return spaceSet();
378
+ case "S":
379
+ return inverted(spaceSet());
380
+ default:
381
+ return null;
382
+ }
383
+ }
384
+ /** The code unit of a character escape after `\` (the `\` consumed), or
385
+ * bails. `inClass` admits `\b` (backspace) and `\-`. */
386
+ characterEscape(inClass) {
387
+ const c = this.ch();
388
+ const code = this.code();
389
+ this.i++;
390
+ switch (c) {
391
+ case "t":
392
+ return 9;
393
+ case "n":
394
+ return 10;
395
+ case "v":
396
+ return 11;
397
+ case "f":
398
+ return 12;
399
+ case "r":
400
+ return 13;
401
+ case "0":
402
+ if (isDigitCode(this.code()))
403
+ bail("octal escape");
404
+ return 0;
405
+ case "x": {
406
+ const a = hexValue(this.code());
407
+ const b = this.i + 1 < this.src.length ? hexValue(this.src.charCodeAt(this.i + 1)) : -1;
408
+ if (a < 0 || b < 0)
409
+ bail("Annex B \\x");
410
+ this.i += 2;
411
+ return a * 16 + b;
412
+ }
413
+ case "u": {
414
+ let value = 0;
415
+ for (let k = 0; k < 4; k++) {
416
+ const h = this.i + k < this.src.length ? hexValue(this.src.charCodeAt(this.i + k)) : -1;
417
+ if (h < 0)
418
+ bail("\\u form");
419
+ value = value * 16 + h;
420
+ }
421
+ this.i += 4;
422
+ return value;
423
+ }
424
+ case "b":
425
+ if (inClass)
426
+ return 8;
427
+ bail("unreachable \\b");
428
+ case "-":
429
+ if (inClass || !this.unicode)
430
+ return 45;
431
+ bail("\\- outside a class");
432
+ default:
433
+ break;
434
+ }
435
+ if (code < 0 || code >= ASCII)
436
+ bail("non-ASCII escape");
437
+ if (/[A-Za-z0-9_]/.test(c))
438
+ bail("escape letter or digit");
439
+ if (this.unicode && !SYNTAX_CHARS.includes(c))
440
+ bail("u-mode identity escape");
441
+ return code;
442
+ }
443
+ atomEscape() {
444
+ this.i++;
445
+ const set = this.classEscapeSet(this.ch());
446
+ if (set !== null) {
447
+ this.i++;
448
+ return { kind: "set", set };
449
+ }
450
+ const code = this.characterEscape(false);
451
+ if (code >= ASCII)
452
+ bail("non-ASCII escape");
453
+ return this.literal(code);
454
+ }
455
+ charClass() {
456
+ this.i++;
457
+ let negate = false;
458
+ if (this.ch() === "^") {
459
+ negate = true;
460
+ this.i++;
461
+ }
462
+ const set = emptySet();
463
+ for (;;) {
464
+ const c = this.ch();
465
+ if (c === "")
466
+ bail("unclosed class");
467
+ if (c === "]") {
468
+ this.i++;
469
+ break;
470
+ }
471
+ const first = this.classAtom();
472
+ if (this.ch() === "-" &&
473
+ this.i + 1 < this.src.length &&
474
+ this.src.charAt(this.i + 1) !== "]") {
475
+ this.i++;
476
+ const second = this.classAtom();
477
+ if (typeof first !== "number" || typeof second !== "number")
478
+ bail("class escape range");
479
+ if (first > second)
480
+ bail("bad class range");
481
+ if (this.fold && second >= ASCII)
482
+ bail("non-ASCII folded range");
483
+ addRange(set, first, second);
484
+ continue;
485
+ }
486
+ if (typeof first === "number") {
487
+ if (first < ASCII)
488
+ set[first] = true;
489
+ else if (this.fold)
490
+ bail("non-ASCII folded member");
491
+ }
492
+ else {
493
+ unionInto(set, first);
494
+ }
495
+ }
496
+ const closed = this.fold ? caseClosed(set) : set;
497
+ return { kind: "set", set: negate ? inverted(closed) : closed };
498
+ }
499
+ /** A class member: a code unit, or the set of a class escape. Non-ASCII
500
+ * code units can only come from `\x`/`\u` escapes here. */
501
+ classAtom() {
502
+ const c = this.ch();
503
+ const code = this.code();
504
+ if (c !== "\\") {
505
+ if (code < 0 || code >= ASCII)
506
+ bail("non-ASCII class member");
507
+ this.i++;
508
+ return code;
509
+ }
510
+ this.i++;
511
+ const set = this.classEscapeSet(this.ch());
512
+ if (set !== null) {
513
+ this.i++;
514
+ return set;
515
+ }
516
+ if (this.ch() === "c")
517
+ bail("\\c");
518
+ return this.characterEscape(true);
519
+ }
520
+ }
521
+ function firstOf(node) {
522
+ switch (node.kind) {
523
+ case "set":
524
+ return { set: node.set, nullable: false, bol: false, uncond: false };
525
+ case "seq": {
526
+ const acc = { set: emptySet(), nullable: true, bol: false, uncond: true };
527
+ for (const item of node.items) {
528
+ const f = firstOf(item);
529
+ unionInto(acc.set, f.set);
530
+ if (f.bol)
531
+ acc.bol = true;
532
+ if (!f.nullable) {
533
+ acc.nullable = false;
534
+ acc.uncond = false;
535
+ break;
536
+ }
537
+ if (!f.uncond)
538
+ acc.uncond = false;
539
+ }
540
+ return acc;
541
+ }
542
+ case "alt": {
543
+ const acc = { set: emptySet(), nullable: false, bol: false, uncond: false };
544
+ for (const alt of node.alts) {
545
+ const f = firstOf(alt);
546
+ unionInto(acc.set, f.set);
547
+ if (f.nullable)
548
+ acc.nullable = true;
549
+ if (f.bol)
550
+ acc.bol = true;
551
+ if (f.uncond)
552
+ acc.uncond = true;
553
+ }
554
+ return acc;
555
+ }
556
+ case "cap":
557
+ return firstOf(node.body);
558
+ case "rep": {
559
+ if (node.max === 0)
560
+ return { set: emptySet(), nullable: true, bol: false, uncond: true };
561
+ const f = firstOf(node.body);
562
+ return {
563
+ set: f.set,
564
+ nullable: node.min === 0 || f.nullable,
565
+ bol: f.bol,
566
+ uncond: node.min === 0 || f.uncond,
567
+ };
568
+ }
569
+ case "assert":
570
+ return node.what === "bol"
571
+ ? { set: emptySet(), nullable: false, bol: true, uncond: false }
572
+ : { set: emptySet(), nullable: true, bol: false, uncond: false };
573
+ }
574
+ }
575
+ /** Whether a node can match without consuming (assertions included). */
576
+ function canMatchEmpty(node) {
577
+ switch (node.kind) {
578
+ case "set":
579
+ return false;
580
+ case "seq":
581
+ return node.items.every(canMatchEmpty);
582
+ case "alt":
583
+ return node.alts.some(canMatchEmpty);
584
+ case "cap":
585
+ return canMatchEmpty(node.body);
586
+ case "rep":
587
+ return node.min === 0 || node.max === 0 || canMatchEmpty(node.body);
588
+ case "assert":
589
+ return true;
590
+ }
591
+ }
592
+ /** `first` followed by `follow`. */
593
+ function thenFollow(first, follow) {
594
+ if (!first.nullable)
595
+ return { set: first.set, nullable: false, bol: first.bol, uncond: false };
596
+ const set = first.set.slice();
597
+ unionInto(set, follow.set);
598
+ return {
599
+ set,
600
+ nullable: follow.nullable,
601
+ bol: first.bol || follow.bol,
602
+ uncond: first.uncond && follow.uncond,
603
+ };
604
+ }
605
+ /** Inclusive code ranges of a set. */
606
+ function intervals(s) {
607
+ const out = [];
608
+ for (let c = 0; c < ASCII; c++) {
609
+ if (!s[c])
610
+ continue;
611
+ let e = c;
612
+ while (e + 1 < ASCII && s[e + 1])
613
+ e++;
614
+ out.push([c, e]);
615
+ c = e;
616
+ }
617
+ return out;
618
+ }
619
+ /** Vector tests use at most this many range compares. */
620
+ const VECTOR_RANGES = 6;
621
+ function splat16(n) {
622
+ const parts = [];
623
+ for (let k = 0; k < 16; k++)
624
+ parts.push(`i8 ${n}`);
625
+ return `<${parts.join(", ")}>`;
626
+ }
627
+ class RxGen {
628
+ sym;
629
+ ncap;
630
+ vector;
631
+ body = [];
632
+ nTmp = 0;
633
+ nLabel = 0;
634
+ /** Resume label of each stack entry kind, by id. */
635
+ resumes = [];
636
+ undoIds = new Map();
637
+ /** Register count: 2 * ncap capture slots, then loop registers. */
638
+ regs;
639
+ tables = [];
640
+ globals = [];
641
+ constructor(sym, ncap,
642
+ /** 16-byte vector scans for long character runs. */
643
+ vector) {
644
+ this.sym = sym;
645
+ this.ncap = ncap;
646
+ this.vector = vector;
647
+ this.regs = 2 * ncap;
648
+ }
649
+ /** The compares of a vector membership test: the set's ranges, or its
650
+ * complement's then negated (bytes >= 128 never occur), or null. */
651
+ vectorPlan(set) {
652
+ if (!this.vector)
653
+ return null;
654
+ const n = setCount(set);
655
+ if (n === 0 || n === ASCII)
656
+ return null;
657
+ const direct = intervals(set), complement = intervals(inverted(set));
658
+ if (direct.length <= complement.length && direct.length <= VECTOR_RANGES)
659
+ return { ranges: direct, negate: false };
660
+ if (complement.length <= VECTOR_RANGES)
661
+ return { ranges: complement, negate: true };
662
+ return null;
663
+ }
664
+ /** Membership of 16 code units at s[index..index+16): an i16 mask, bit
665
+ * k set when s[index + k] is in the set. */
666
+ testVector(plan, index) {
667
+ const wide = this.tmp(), at = this.tmp(), v = this.tmp();
668
+ this.line(`${wide} = sext i32 ${index} to i64`);
669
+ this.line(`${at} = getelementptr inbounds i8, ptr %s, i64 ${wide}`);
670
+ this.line(`${v} = load <16 x i8>, ptr ${at}, align 1`);
671
+ let acc = "";
672
+ for (const [lo, hi] of plan.ranges) {
673
+ const hit = this.tmp();
674
+ if (lo === hi) {
675
+ this.line(`${hit} = icmp eq <16 x i8> ${v}, ${splat16(lo)}`);
676
+ }
677
+ else {
678
+ const d = this.tmp();
679
+ this.line(`${d} = sub <16 x i8> ${v}, ${splat16(lo)}`);
680
+ this.line(`${hit} = icmp ule <16 x i8> ${d}, ${splat16(hi - lo)}`);
681
+ }
682
+ if (acc === "") {
683
+ acc = hit;
684
+ }
685
+ else {
686
+ const both = this.tmp();
687
+ this.line(`${both} = or <16 x i1> ${acc}, ${hit}`);
688
+ acc = both;
689
+ }
690
+ }
691
+ const bits = this.tmp();
692
+ this.line(`${bits} = bitcast <16 x i1> ${acc} to i16`);
693
+ if (!plan.negate)
694
+ return bits;
695
+ const flipped = this.tmp();
696
+ this.line(`${flipped} = xor i16 ${bits}, -1`);
697
+ return flipped;
698
+ }
699
+ /** Index of the lowest set bit of a nonzero i16 mask, as i32. */
700
+ lowestBit(mask) {
701
+ const tz = this.tmp(), wide = this.tmp();
702
+ this.line(`${tz} = call i16 @llvm.cttz.i16(i16 ${mask}, i1 true)`);
703
+ this.line(`${wide} = zext i16 ${tz} to i32`);
704
+ return wide;
705
+ }
706
+ /** The first-character search: from %at, store the next position whose
707
+ * character is in `set` and branch to %attempt, or branch to %nomatch. */
708
+ emitSeek(set) {
709
+ this.block("seek");
710
+ const a = this.tmp();
711
+ this.line(`${a} = load i32, ptr %at`);
712
+ const plan = this.vectorPlan(set);
713
+ let from = "seek", start = a;
714
+ if (plan !== null) {
715
+ const head = this.label("vsh"), load = this.label("vsl"), next = this.label("vsn"), hit = this.label("vsx"), tail = this.label("vst");
716
+ this.line(`br label %${head}`);
717
+ this.block(head);
718
+ const i = this.tmp(), i16 = this.tmp(), fits = this.tmp();
719
+ this.line(`${i} = phi i32 [ ${a}, %seek ], [ ${i16}, %${next} ]`);
720
+ this.line(`${i16} = add i32 ${i}, 16`);
721
+ this.line(`${fits} = icmp sle i32 ${i16}, %len`);
722
+ this.line(`br i1 ${fits}, label %${load}, label %${tail}`);
723
+ this.block(load);
724
+ const mask = this.testVector(plan, i), any = this.tmp();
725
+ this.line(`${any} = icmp ne i16 ${mask}, 0`);
726
+ this.line(`br i1 ${any}, label %${hit}, label %${next}`);
727
+ this.block(next);
728
+ this.line(`br label %${head}`);
729
+ this.block(hit);
730
+ const k = this.lowestBit(mask), found = this.tmp();
731
+ this.line(`${found} = add i32 ${i}, ${k}`);
732
+ this.line(`store i32 ${found}, ptr %at`);
733
+ this.line(`br label %attempt`);
734
+ this.block(tail);
735
+ from = tail;
736
+ start = i;
737
+ }
738
+ const head = this.label("ssh"), probe = this.label("sst"), next = this.label("ssn"), found = this.label("ssf");
739
+ this.line(`br label %${head}`);
740
+ this.block(head);
741
+ const j = this.tmp(), j1 = this.tmp(), inb = this.tmp();
742
+ this.line(`${j} = phi i32 [ ${start}, %${from} ], [ ${j1}, %${next} ]`);
743
+ this.line(`${inb} = icmp slt i32 ${j}, %len`);
744
+ this.line(`br i1 ${inb}, label %${probe}, label %nomatch`);
745
+ this.block(probe);
746
+ const hit = this.test(set, this.loadChar(j));
747
+ this.line(`br i1 ${hit}, label %${found}, label %${next}`);
748
+ this.block(next);
749
+ this.line(`${j1} = add i32 ${j}, 1`);
750
+ this.line(`br label %${head}`);
751
+ this.block(found);
752
+ this.line(`store i32 ${j}, ptr %at`);
753
+ this.line(`br label %attempt`);
754
+ }
755
+ tmp() {
756
+ return `%t${this.nTmp++}`;
757
+ }
758
+ label(prefix) {
759
+ return `${prefix}${this.nLabel++}`;
760
+ }
761
+ block(label) {
762
+ this.body.push(`${label}:`);
763
+ }
764
+ line(text) {
765
+ this.body.push(` ${text}`);
766
+ }
767
+ newReg() {
768
+ return this.regs++;
769
+ }
770
+ newResume(label) {
771
+ this.resumes.push(label);
772
+ return this.resumes.length - 1;
773
+ }
774
+ loadPos() {
775
+ const p = this.tmp();
776
+ this.line(`${p} = load i32, ptr %pos`);
777
+ return p;
778
+ }
779
+ storePos(v) {
780
+ this.line(`store i32 ${v}, ptr %pos`);
781
+ }
782
+ loadReg(r) {
783
+ const v = this.tmp();
784
+ this.line(`${v} = load i32, ptr %r${r}`);
785
+ return v;
786
+ }
787
+ loadChar(index) {
788
+ const wide = this.tmp(), at = this.tmp(), c = this.tmp();
789
+ this.line(`${wide} = sext i32 ${index} to i64`);
790
+ this.line(`${at} = getelementptr inbounds i8, ptr %s, i64 ${wide}`);
791
+ this.line(`${c} = load i8, ptr ${at}`);
792
+ return c;
793
+ }
794
+ /** Straight-line membership test of an i8 ASCII code unit. */
795
+ test(set, c) {
796
+ const n = setCount(set);
797
+ if (n === ASCII)
798
+ return "true";
799
+ if (n === 0)
800
+ return "false";
801
+ const ranges = intervals(set);
802
+ if (ranges.length <= 3) {
803
+ const c32 = this.tmp();
804
+ this.line(`${c32} = zext i8 ${c} to i32`);
805
+ let acc = "";
806
+ for (const [lo, hi] of ranges) {
807
+ const hit = this.tmp();
808
+ if (lo === hi) {
809
+ this.line(`${hit} = icmp eq i32 ${c32}, ${lo}`);
810
+ }
811
+ else {
812
+ const d = this.tmp();
813
+ this.line(`${d} = sub i32 ${c32}, ${lo}`);
814
+ this.line(`${hit} = icmp ule i32 ${d}, ${hi - lo}`);
815
+ }
816
+ if (acc === "") {
817
+ acc = hit;
818
+ }
819
+ else {
820
+ const both = this.tmp();
821
+ this.line(`${both} = or i1 ${acc}, ${hit}`);
822
+ acc = both;
823
+ }
824
+ }
825
+ return acc;
826
+ }
827
+ const table = this.table(set), masked = this.tmp(), wide = this.tmp(), slot = this.tmp(), v = this.tmp(), hit = this.tmp();
828
+ this.line(`${masked} = and i8 ${c}, 127`);
829
+ this.line(`${wide} = zext i8 ${masked} to i64`);
830
+ this.line(`${slot} = getelementptr inbounds [128 x i8], ptr ${table}, i64 0, i64 ${wide}`);
831
+ this.line(`${v} = load i8, ptr ${slot}`);
832
+ this.line(`${hit} = icmp ne i8 ${v}, 0`);
833
+ return hit;
834
+ }
835
+ table(set) {
836
+ for (let k = 0; k < this.tables.length; k++)
837
+ if (sameSet(this.tables[k], set))
838
+ return `@${this.sym}_t${k}`;
839
+ const k = this.tables.length;
840
+ this.tables.push(set);
841
+ let bytes = "";
842
+ for (let c = 0; c < ASCII; c++)
843
+ bytes += set[c] ? "\\01" : "\\00";
844
+ this.globals.push(`@${this.sym}_t${k} = private unnamed_addr constant [128 x i8] c"${bytes}"`);
845
+ return `@${this.sym}_t${k}`;
846
+ }
847
+ /** Push data words and an entry id; may split the current block. */
848
+ push(values, id) {
849
+ const n = values.length + 1;
850
+ const sp = this.tmp(), need = this.tmp(), cap = this.tmp(), full = this.tmp();
851
+ const grow = this.label("grow"), put = this.label("put");
852
+ this.line(`${sp} = load i32, ptr %sp`);
853
+ this.line(`${need} = add i32 ${sp}, ${n}`);
854
+ this.line(`${cap} = load i32, ptr %scap`);
855
+ this.line(`${full} = icmp sgt i32 ${need}, ${cap}`);
856
+ this.line(`br i1 ${full}, label %${grow}, label %${put}`);
857
+ this.block(grow);
858
+ this.line(`call void @scr_regex_stack_grow(ptr %stk, ptr %scap, ptr %sbuf, i32 ${need})`);
859
+ this.line(`br label %${put}`);
860
+ this.block(put);
861
+ const base = this.tmp();
862
+ this.line(`${base} = load ptr, ptr %stk`);
863
+ const words = values.concat([String(id)]);
864
+ for (let k = 0; k < words.length; k++) {
865
+ const idx = this.tmp(), wide = this.tmp(), slot = this.tmp();
866
+ this.line(`${idx} = add i32 ${sp}, ${k}`);
867
+ this.line(`${wide} = sext i32 ${idx} to i64`);
868
+ this.line(`${slot} = getelementptr inbounds i32, ptr ${base}, i64 ${wide}`);
869
+ this.line(`store i32 ${words[k]}, ptr ${slot}`);
870
+ }
871
+ this.line(`store i32 ${need}, ptr %sp`);
872
+ }
873
+ /** Pop `n` data words in push order (the dispatcher popped the id). */
874
+ pop(n) {
875
+ const sp = this.tmp(), base = this.tmp(), rest = this.tmp();
876
+ this.line(`${sp} = load i32, ptr %sp`);
877
+ this.line(`${base} = load ptr, ptr %stk`);
878
+ const out = [];
879
+ for (let k = 0; k < n; k++) {
880
+ const idx = this.tmp(), wide = this.tmp(), slot = this.tmp(), v = this.tmp();
881
+ this.line(`${idx} = sub i32 ${sp}, ${n - k}`);
882
+ this.line(`${wide} = sext i32 ${idx} to i64`);
883
+ this.line(`${slot} = getelementptr inbounds i32, ptr ${base}, i64 ${wide}`);
884
+ this.line(`${v} = load i32, ptr ${slot}`);
885
+ out.push(v);
886
+ }
887
+ this.line(`${rest} = sub i32 ${sp}, ${n}`);
888
+ this.line(`store i32 ${rest}, ptr %sp`);
889
+ return out;
890
+ }
891
+ /** Register write that a backtrack restores. With an empty stack no
892
+ * resume can observe the old value (the attempt fails outright and the
893
+ * next attempt reinitializes), so no undo record is pushed. */
894
+ setReg(r, value) {
895
+ let id = this.undoIds.get(r);
896
+ if (id === undefined) {
897
+ id = this.newResume(`undo${r}`);
898
+ this.undoIds.set(r, id);
899
+ }
900
+ const sp = this.tmp(), live = this.tmp();
901
+ const save = this.label("save"), set = this.label("set");
902
+ this.line(`${sp} = load i32, ptr %sp`);
903
+ this.line(`${live} = icmp ne i32 ${sp}, 0`);
904
+ this.line(`br i1 ${live}, label %${save}, label %${set}`);
905
+ this.block(save);
906
+ const old = this.loadReg(r);
907
+ this.push([old], id);
908
+ this.line(`br label %${set}`);
909
+ this.block(set);
910
+ this.line(`store i32 ${value}, ptr %r${r}`);
911
+ }
912
+ resetCaps(first, end) {
913
+ for (let g = first; g < end; g++) {
914
+ this.setReg(2 * g, "-1");
915
+ this.setReg(2 * g + 1, "-1");
916
+ }
917
+ }
918
+ emit(node, succ, follow) {
919
+ switch (node.kind) {
920
+ case "set":
921
+ return this.emitRun([node.set], succ);
922
+ case "seq":
923
+ return this.emitSeq(node.items, succ, follow);
924
+ case "alt":
925
+ return this.emitAlt(node.alts, succ, follow);
926
+ case "cap":
927
+ return this.emitCap(node, succ, follow);
928
+ case "rep":
929
+ return this.emitRep(node, succ, follow);
930
+ case "assert":
931
+ return this.emitAssert(node.what, succ);
932
+ }
933
+ }
934
+ /** Consecutive single characters: one bounds check, then each test. */
935
+ emitRun(sets, succ) {
936
+ const entry = this.label("run"), check = this.label("chk");
937
+ this.block(entry);
938
+ const p = this.loadPos(), end = this.tmp(), inb = this.tmp();
939
+ this.line(`${end} = add i32 ${p}, ${sets.length}`);
940
+ this.line(`${inb} = icmp sle i32 ${end}, %len`);
941
+ this.line(`br i1 ${inb}, label %${check}, label %fail`);
942
+ this.block(check);
943
+ let acc = "";
944
+ for (let k = 0; k < sets.length; k++) {
945
+ let at = p;
946
+ if (k > 0) {
947
+ at = this.tmp();
948
+ this.line(`${at} = add i32 ${p}, ${k}`);
949
+ }
950
+ const hit = this.test(sets[k], this.loadChar(at));
951
+ if (acc === "") {
952
+ acc = hit;
953
+ }
954
+ else {
955
+ const both = this.tmp();
956
+ this.line(`${both} = and i1 ${acc}, ${hit}`);
957
+ acc = both;
958
+ }
959
+ }
960
+ // Storing before the branch is safe: every resume sets the position.
961
+ this.storePos(end);
962
+ this.line(`br i1 ${acc}, label %${succ}, label %fail`);
963
+ return entry;
964
+ }
965
+ emitSeq(items, succ, follow) {
966
+ // Group consecutive single characters into runs.
967
+ const parts = [];
968
+ for (const item of items) {
969
+ const last = parts.length > 0 ? parts[parts.length - 1] : null;
970
+ if (item.kind === "set" && Array.isArray(last) && last.length < 16) {
971
+ last.push(item.set);
972
+ }
973
+ else if (item.kind === "set") {
974
+ parts.push([item.set]);
975
+ }
976
+ else {
977
+ parts.push(item);
978
+ }
979
+ }
980
+ let next = succ;
981
+ let after = follow;
982
+ for (let k = parts.length - 1; k >= 0; k--) {
983
+ const part = parts[k];
984
+ if (Array.isArray(part)) {
985
+ next = this.emitRun(part, next);
986
+ after = { set: part[0], nullable: false, bol: false, uncond: false };
987
+ }
988
+ else {
989
+ next = this.emit(part, next, after);
990
+ after = thenFollow(firstOf(part), after);
991
+ }
992
+ }
993
+ if (parts.length === 0) {
994
+ const entry = this.label("empty");
995
+ this.block(entry);
996
+ this.line(`br label %${succ}`);
997
+ return entry;
998
+ }
999
+ return next;
1000
+ }
1001
+ emitAlt(alts, succ, follow) {
1002
+ const entries = [];
1003
+ for (const alt of alts)
1004
+ entries.push(this.emit(alt, succ, follow));
1005
+ const resumeLabels = [];
1006
+ const ids = [];
1007
+ for (let k = 1; k < alts.length; k++) {
1008
+ const l = this.label("alt");
1009
+ resumeLabels.push(l);
1010
+ ids.push(this.newResume(l));
1011
+ }
1012
+ const entry = this.label("alts");
1013
+ this.block(entry);
1014
+ const p = this.loadPos();
1015
+ this.push([p], ids[0]);
1016
+ this.line(`br label %${entries[0]}`);
1017
+ for (let k = 1; k < alts.length; k++) {
1018
+ this.block(resumeLabels[k - 1]);
1019
+ const [q] = this.pop(1);
1020
+ this.storePos(q);
1021
+ if (k + 1 < alts.length)
1022
+ this.push([q], ids[k]);
1023
+ this.line(`br label %${entries[k]}`);
1024
+ }
1025
+ return entry;
1026
+ }
1027
+ emitCap(node, succ, follow) {
1028
+ const close = this.label("close");
1029
+ this.block(close);
1030
+ const end = this.loadPos();
1031
+ this.setReg(2 * node.index + 1, end);
1032
+ this.line(`br label %${succ}`);
1033
+ const body = this.emit(node.body, close, follow);
1034
+ const open = this.label("open");
1035
+ this.block(open);
1036
+ const start = this.loadPos();
1037
+ this.setReg(2 * node.index, start);
1038
+ this.line(`br label %${body}`);
1039
+ return open;
1040
+ }
1041
+ emitAssert(what, succ) {
1042
+ const entry = this.label("as");
1043
+ this.block(entry);
1044
+ const p = this.loadPos();
1045
+ if (what === "bol" || what === "eol") {
1046
+ const hit = this.tmp();
1047
+ this.line(`${hit} = icmp eq i32 ${p}, ${what === "bol" ? "0" : "%len"}`);
1048
+ this.line(`br i1 ${hit}, label %${succ}, label %fail`);
1049
+ return entry;
1050
+ }
1051
+ if (what === "bolm" || what === "eolm") {
1052
+ const edge = this.tmp(), look = this.label("nl");
1053
+ this.line(`${edge} = icmp eq i32 ${p}, ${what === "bolm" ? "0" : "%len"}`);
1054
+ this.line(`br i1 ${edge}, label %${succ}, label %${look}`);
1055
+ this.block(look);
1056
+ let at = p;
1057
+ if (what === "bolm") {
1058
+ at = this.tmp();
1059
+ this.line(`${at} = sub i32 ${p}, 1`);
1060
+ }
1061
+ const nl = emptySet();
1062
+ nl[10] = true;
1063
+ nl[13] = true;
1064
+ const hit = this.test(nl, this.loadChar(at));
1065
+ this.line(`br i1 ${hit}, label %${succ}, label %fail`);
1066
+ return entry;
1067
+ }
1068
+ const word = wordSet();
1069
+ const prev = this.label("wp"), noPrev = this.label("wq"), mid = this.label("wm"), next = this.label("wn"), noNext = this.label("wo"), done = this.label("wd");
1070
+ const hasPrev = this.tmp();
1071
+ this.line(`${hasPrev} = icmp sgt i32 ${p}, 0`);
1072
+ this.line(`br i1 ${hasPrev}, label %${prev}, label %${noPrev}`);
1073
+ this.block(prev);
1074
+ const pm = this.tmp();
1075
+ this.line(`${pm} = sub i32 ${p}, 1`);
1076
+ const w1 = this.test(word, this.loadChar(pm));
1077
+ this.line(`br label %${mid}`);
1078
+ this.block(noPrev);
1079
+ this.line(`br label %${mid}`);
1080
+ this.block(mid);
1081
+ const a = this.tmp(), hasNext = this.tmp();
1082
+ this.line(`${a} = phi i1 [ ${w1}, %${prev} ], [ false, %${noPrev} ]`);
1083
+ this.line(`${hasNext} = icmp slt i32 ${p}, %len`);
1084
+ this.line(`br i1 ${hasNext}, label %${next}, label %${noNext}`);
1085
+ this.block(next);
1086
+ const w2 = this.test(word, this.loadChar(p));
1087
+ this.line(`br label %${done}`);
1088
+ this.block(noNext);
1089
+ this.line(`br label %${done}`);
1090
+ this.block(done);
1091
+ const b = this.tmp(), edge = this.tmp();
1092
+ this.line(`${b} = phi i1 [ ${w2}, %${next} ], [ false, %${noNext} ]`);
1093
+ this.line(`${edge} = xor i1 ${a}, ${b}`);
1094
+ const yes = what === "wordb" ? succ : "fail", no = what === "wordb" ? "fail" : succ;
1095
+ this.line(`br i1 ${edge}, label %${yes}, label %${no}`);
1096
+ return entry;
1097
+ }
1098
+ emitRep(node, succ, follow) {
1099
+ if (node.max === 0) {
1100
+ const entry = this.label("none");
1101
+ this.block(entry);
1102
+ this.line(`br label %${succ}`);
1103
+ return entry;
1104
+ }
1105
+ if (node.body.kind === "set") {
1106
+ return node.greedy
1107
+ ? this.emitGreedyChars(node.body.set, node.min, node.max, succ, follow)
1108
+ : this.emitLazyChars(node.body.set, node.min, node.max, succ);
1109
+ }
1110
+ if (node.min === 1 && node.max === 1)
1111
+ return this.emit(node.body, succ, follow);
1112
+ return this.emitLoop(node, succ, follow);
1113
+ }
1114
+ /** `x*`, `x+`, `x{n,m}` over one character: count the run, then give
1115
+ * characters back one at a time on backtrack (skipping positions where
1116
+ * the continuation cannot start). Possessive when giving back can never
1117
+ * succeed. */
1118
+ emitGreedyChars(set, min, max, succ, follow) {
1119
+ const entry = this.label("gl"), head = this.label("glh"), probe = this.label("glt"), step = this.label("glb"), done = this.label("gld"), ok = this.label("glo");
1120
+ this.block(entry);
1121
+ const p = this.loadPos(), rem = this.tmp();
1122
+ this.line(`${rem} = sub i32 %len, ${p}`);
1123
+ let lim = rem;
1124
+ if (max !== INF) {
1125
+ const small = this.tmp();
1126
+ lim = this.tmp();
1127
+ this.line(`${small} = icmp slt i32 ${rem}, ${max}`);
1128
+ this.line(`${lim} = select i1 ${small}, i32 ${rem}, i32 ${max}`);
1129
+ }
1130
+ // Long runs: 16 characters per step while a whole chunk fits.
1131
+ const plan = max === INF || max >= 32 ? this.vectorPlan(set) : null;
1132
+ let from = entry, start = "0", vectorExit = "";
1133
+ if (plan !== null) {
1134
+ const vhead = this.label("gvh"), vload = this.label("gvl"), vnext = this.label("gvn"), vexit = this.label("gvx"), tail = this.label("gvt");
1135
+ this.line(`br label %${vhead}`);
1136
+ this.block(vhead);
1137
+ const kv = this.tmp(), kv16 = this.tmp(), fits = this.tmp();
1138
+ this.line(`${kv} = phi i32 [ 0, %${entry} ], [ ${kv16}, %${vnext} ]`);
1139
+ this.line(`${kv16} = add i32 ${kv}, 16`);
1140
+ this.line(`${fits} = icmp sle i32 ${kv16}, ${lim}`);
1141
+ this.line(`br i1 ${fits}, label %${vload}, label %${tail}`);
1142
+ this.block(vload);
1143
+ const vat = this.tmp();
1144
+ this.line(`${vat} = add i32 ${p}, ${kv}`);
1145
+ const mask = this.testVector(plan, vat), all = this.tmp();
1146
+ this.line(`${all} = icmp eq i16 ${mask}, -1`);
1147
+ this.line(`br i1 ${all}, label %${vnext}, label %${vexit}`);
1148
+ this.block(vnext);
1149
+ this.line(`br label %${vhead}`);
1150
+ this.block(vexit);
1151
+ const missing = this.tmp();
1152
+ this.line(`${missing} = xor i16 ${mask}, -1`);
1153
+ const off = this.lowestBit(missing), kx = this.tmp();
1154
+ this.line(`${kx} = add i32 ${kv}, ${off}`);
1155
+ this.line(`br label %${done}`);
1156
+ vectorExit = `, [ ${kx}, %${vexit} ]`;
1157
+ this.block(tail);
1158
+ from = tail;
1159
+ start = kv;
1160
+ }
1161
+ this.line(`br label %${head}`);
1162
+ this.block(head);
1163
+ const k = this.tmp(), k1 = this.tmp(), more = this.tmp();
1164
+ this.line(`${k} = phi i32 [ ${start}, %${from} ], [ ${k1}, %${step} ]`);
1165
+ this.line(`${more} = icmp slt i32 ${k}, ${lim}`);
1166
+ this.line(`br i1 ${more}, label %${probe}, label %${done}`);
1167
+ this.block(probe);
1168
+ const at = this.tmp();
1169
+ this.line(`${at} = add i32 ${p}, ${k}`);
1170
+ const hit = this.test(set, this.loadChar(at));
1171
+ this.line(`br i1 ${hit}, label %${step}, label %${done}`);
1172
+ this.block(step);
1173
+ this.line(`${k1} = add i32 ${k}, 1`);
1174
+ this.line(`br label %${head}`);
1175
+ this.block(done);
1176
+ const kf = this.tmp(), low = this.tmp();
1177
+ this.line(`${kf} = phi i32 [ ${k}, %${head} ], [ ${k}, %${probe} ]${vectorExit}`);
1178
+ this.line(`${low} = icmp slt i32 ${kf}, ${min}`);
1179
+ this.line(`br i1 ${low}, label %fail, label %${ok}`);
1180
+ this.block(ok);
1181
+ const np = this.tmp();
1182
+ this.line(`${np} = add i32 ${p}, ${kf}`);
1183
+ this.storePos(np);
1184
+ const possessive = follow.uncond || (!follow.nullable && !follow.bol && disjoint(set, follow.set));
1185
+ if (possessive || min === max) {
1186
+ this.line(`br label %${succ}`);
1187
+ return entry;
1188
+ }
1189
+ const give = this.label("gv");
1190
+ const id = this.newResume(give);
1191
+ const keep = this.label("glp");
1192
+ const more2 = this.tmp();
1193
+ this.line(`${more2} = icmp sgt i32 ${kf}, ${min}`);
1194
+ this.line(`br i1 ${more2}, label %${keep}, label %${succ}`);
1195
+ this.block(keep);
1196
+ this.push([p, kf], id);
1197
+ this.line(`br label %${succ}`);
1198
+ this.block(give);
1199
+ const [base, count] = this.pop(2);
1200
+ const back = this.tmp();
1201
+ this.line(`${back} = sub i32 ${count}, 1`);
1202
+ let kk = back;
1203
+ if (!follow.nullable && !follow.bol) {
1204
+ // The continuation must consume a character of follow.set first.
1205
+ const scan = this.label("gs"), look = this.label("gst"), down = this.label("gsd"), found = this.label("gsf");
1206
+ const from = this.label("gse");
1207
+ this.line(`br label %${from}`);
1208
+ this.block(from);
1209
+ this.line(`br label %${scan}`);
1210
+ this.block(scan);
1211
+ const cur = this.tmp(), dec = this.tmp(), under = this.tmp();
1212
+ this.line(`${cur} = phi i32 [ ${back}, %${from} ], [ ${dec}, %${down} ]`);
1213
+ this.line(`${under} = icmp slt i32 ${cur}, ${min}`);
1214
+ this.line(`br i1 ${under}, label %fail, label %${look}`);
1215
+ this.block(look);
1216
+ const at2 = this.tmp();
1217
+ this.line(`${at2} = add i32 ${base}, ${cur}`);
1218
+ const can = this.test(follow.set, this.loadChar(at2));
1219
+ this.line(`br i1 ${can}, label %${found}, label %${down}`);
1220
+ this.block(down);
1221
+ this.line(`${dec} = sub i32 ${cur}, 1`);
1222
+ this.line(`br label %${scan}`);
1223
+ this.block(found);
1224
+ kk = cur;
1225
+ }
1226
+ const again = this.label("gva"), resume = this.label("gvr");
1227
+ const repush = this.tmp();
1228
+ this.line(`${repush} = icmp sgt i32 ${kk}, ${min}`);
1229
+ this.line(`br i1 ${repush}, label %${again}, label %${resume}`);
1230
+ this.block(again);
1231
+ this.push([base, kk], id);
1232
+ this.line(`br label %${resume}`);
1233
+ this.block(resume);
1234
+ const rp = this.tmp();
1235
+ this.line(`${rp} = add i32 ${base}, ${kk}`);
1236
+ this.storePos(rp);
1237
+ this.line(`br label %${succ}`);
1238
+ return entry;
1239
+ }
1240
+ /** `x*?`, `x+?`, `x{n,m}?` over one character: take the minimum, then
1241
+ * one more character per backtrack. */
1242
+ emitLazyChars(set, min, max, succ) {
1243
+ const entry = this.label("ll"), head = this.label("llh"), probe = this.label("llt"), step = this.label("llb"), ok = this.label("llo"), start = this.label("lls");
1244
+ this.block(entry);
1245
+ const p = this.loadPos(), rem = this.tmp(), enough = this.tmp();
1246
+ this.line(`${rem} = sub i32 %len, ${p}`);
1247
+ this.line(`${enough} = icmp sge i32 ${rem}, ${min}`);
1248
+ this.line(`br i1 ${enough}, label %${start}, label %fail`);
1249
+ this.block(start);
1250
+ this.line(`br label %${head}`);
1251
+ this.block(head);
1252
+ const k = this.tmp(), k1 = this.tmp(), reached = this.tmp();
1253
+ this.line(`${k} = phi i32 [ 0, %${start} ], [ ${k1}, %${step} ]`);
1254
+ this.line(`${reached} = icmp sge i32 ${k}, ${min}`);
1255
+ this.line(`br i1 ${reached}, label %${ok}, label %${probe}`);
1256
+ this.block(probe);
1257
+ const at = this.tmp();
1258
+ this.line(`${at} = add i32 ${p}, ${k}`);
1259
+ const hit = this.test(set, this.loadChar(at));
1260
+ this.line(`br i1 ${hit}, label %${step}, label %fail`);
1261
+ this.block(step);
1262
+ this.line(`${k1} = add i32 ${k}, 1`);
1263
+ this.line(`br label %${head}`);
1264
+ this.block(ok);
1265
+ const np = this.tmp();
1266
+ this.line(`${np} = add i32 ${p}, ${min}`);
1267
+ this.storePos(np);
1268
+ if (max !== INF && max <= min) {
1269
+ this.line(`br label %${succ}`);
1270
+ return entry;
1271
+ }
1272
+ const extend = this.label("lx");
1273
+ const id = this.newResume(extend);
1274
+ this.push([p, String(min)], id);
1275
+ this.line(`br label %${succ}`);
1276
+ this.block(extend);
1277
+ const [base, count] = this.pop(2);
1278
+ const pos = this.tmp(), inb = this.tmp(), look = this.label("lxt"), take = this.label("lxy");
1279
+ this.line(`${pos} = add i32 ${base}, ${count}`);
1280
+ this.line(`${inb} = icmp slt i32 ${pos}, %len`);
1281
+ this.line(`br i1 ${inb}, label %${look}, label %fail`);
1282
+ this.block(look);
1283
+ const can = this.test(set, this.loadChar(pos));
1284
+ this.line(`br i1 ${can}, label %${take}, label %fail`);
1285
+ this.block(take);
1286
+ const c1 = this.tmp(), np2 = this.tmp();
1287
+ this.line(`${c1} = add i32 ${count}, 1`);
1288
+ this.line(`${np2} = add i32 ${pos}, 1`);
1289
+ this.storePos(np2);
1290
+ const again = this.label("lxa");
1291
+ if (max !== INF) {
1292
+ const below = this.tmp();
1293
+ this.line(`${below} = icmp slt i32 ${c1}, ${max}`);
1294
+ this.line(`br i1 ${below}, label %${again}, label %${succ}`);
1295
+ }
1296
+ else {
1297
+ this.line(`br label %${again}`);
1298
+ }
1299
+ this.block(again);
1300
+ this.push([base, c1], id);
1301
+ this.line(`br label %${succ}`);
1302
+ return entry;
1303
+ }
1304
+ /** RepeatMatcher over a general atom: captures inside reset at each
1305
+ * iteration; an optional iteration that matched empty fails. */
1306
+ emitLoop(node, succ, follow) {
1307
+ const bodyFirst = firstOf(node.body);
1308
+ const emptyCheck = canMatchEmpty(node.body);
1309
+ const startReg = emptyCheck ? this.newReg() : -1;
1310
+ // After the body: another iteration or the continuation. An empty
1311
+ // check may fail in between, so nothing after the body is
1312
+ // unconditional.
1313
+ const bodyFollow = {
1314
+ set: follow.set.slice(),
1315
+ nullable: follow.nullable,
1316
+ bol: follow.bol || (node.max !== 1 && bodyFirst.bol),
1317
+ uncond: false,
1318
+ };
1319
+ if (node.max !== 1) {
1320
+ unionInto(bodyFollow.set, bodyFirst.set);
1321
+ if (bodyFirst.nullable)
1322
+ bodyFollow.nullable = true;
1323
+ }
1324
+ if (node.min === 0 && node.max === 1) {
1325
+ const iter = this.label("oi"), after = this.label("oa");
1326
+ this.block(after);
1327
+ if (emptyCheck) {
1328
+ const p = this.loadPos(), r = this.loadReg(startReg), same = this.tmp();
1329
+ this.line(`${same} = icmp eq i32 ${p}, ${r}`);
1330
+ this.line(`br i1 ${same}, label %fail, label %${succ}`);
1331
+ }
1332
+ else {
1333
+ this.line(`br label %${succ}`);
1334
+ }
1335
+ const bodyEntry = this.emit(node.body, after, bodyFollow);
1336
+ this.block(iter);
1337
+ const p = this.loadPos();
1338
+ if (emptyCheck)
1339
+ this.setReg(startReg, p);
1340
+ this.resetCaps(node.capFirst, node.capEnd);
1341
+ this.line(`br label %${bodyEntry}`);
1342
+ const entry = this.label("opt");
1343
+ if (node.greedy) {
1344
+ const skip = this.label("os");
1345
+ const id = this.newResume(skip);
1346
+ this.block(entry);
1347
+ const q = this.loadPos();
1348
+ this.push([q], id);
1349
+ this.line(`br label %${iter}`);
1350
+ this.block(skip);
1351
+ const [r] = this.pop(1);
1352
+ this.storePos(r);
1353
+ this.line(`br label %${succ}`);
1354
+ }
1355
+ else {
1356
+ const take = this.label("ot");
1357
+ const id = this.newResume(take);
1358
+ this.block(entry);
1359
+ const q = this.loadPos();
1360
+ this.push([q], id);
1361
+ this.line(`br label %${succ}`);
1362
+ this.block(take);
1363
+ const [r] = this.pop(1);
1364
+ this.storePos(r);
1365
+ this.line(`br label %${iter}`);
1366
+ }
1367
+ return entry;
1368
+ }
1369
+ const counted = !(node.min === 0 && node.max === INF);
1370
+ const cnt = counted ? this.newReg() : -1;
1371
+ const entry = this.label("lp"), head = this.label("lph"), iter = this.label("lpi"), after = this.label("lpa");
1372
+ // after: the empty check, then count the iteration.
1373
+ this.block(after);
1374
+ if (emptyCheck) {
1375
+ const p = this.loadPos(), r = this.loadReg(startReg);
1376
+ let same = this.tmp();
1377
+ this.line(`${same} = icmp eq i32 ${p}, ${r}`);
1378
+ if (counted && node.min > 0) {
1379
+ const c = this.loadReg(cnt), optional = this.tmp(), both = this.tmp();
1380
+ this.line(`${optional} = icmp sge i32 ${c}, ${node.min}`);
1381
+ this.line(`${both} = and i1 ${same}, ${optional}`);
1382
+ same = both;
1383
+ }
1384
+ const count = this.label("lpc");
1385
+ this.line(`br i1 ${same}, label %fail, label %${count}`);
1386
+ this.block(count);
1387
+ }
1388
+ if (counted) {
1389
+ const c = this.loadReg(cnt), c1 = this.tmp();
1390
+ this.line(`${c1} = add i32 ${c}, 1`);
1391
+ this.setReg(cnt, c1);
1392
+ }
1393
+ this.line(`br label %${head}`);
1394
+ const bodyEntry = this.emit(node.body, after, bodyFollow);
1395
+ this.block(entry);
1396
+ if (counted)
1397
+ this.setReg(cnt, "0");
1398
+ this.line(`br label %${head}`);
1399
+ this.block(head);
1400
+ if (counted) {
1401
+ const c = this.loadReg(cnt);
1402
+ if (node.min > 0) {
1403
+ const req = this.tmp(), next = this.label("lpm");
1404
+ this.line(`${req} = icmp slt i32 ${c}, ${node.min}`);
1405
+ this.line(`br i1 ${req}, label %${iter}, label %${next}`);
1406
+ this.block(next);
1407
+ }
1408
+ if (node.max !== INF) {
1409
+ const full = this.tmp(), next = this.label("lpx");
1410
+ this.line(`${full} = icmp eq i32 ${c}, ${node.max}`);
1411
+ this.line(`br i1 ${full}, label %${succ}, label %${next}`);
1412
+ this.block(next);
1413
+ }
1414
+ }
1415
+ const q = this.loadPos();
1416
+ if (node.greedy) {
1417
+ const exit = this.label("lpe");
1418
+ const id = this.newResume(exit);
1419
+ this.push([q], id);
1420
+ this.line(`br label %${iter}`);
1421
+ this.block(exit);
1422
+ const [r] = this.pop(1);
1423
+ this.storePos(r);
1424
+ this.line(`br label %${succ}`);
1425
+ }
1426
+ else {
1427
+ const more = this.label("lpn");
1428
+ const id = this.newResume(more);
1429
+ this.push([q], id);
1430
+ this.line(`br label %${succ}`);
1431
+ this.block(more);
1432
+ const [r] = this.pop(1);
1433
+ this.storePos(r);
1434
+ this.line(`br label %${iter}`);
1435
+ }
1436
+ this.block(iter);
1437
+ const p = this.loadPos();
1438
+ if (emptyCheck)
1439
+ this.setReg(startReg, p);
1440
+ this.resetCaps(node.capFirst, node.capEnd);
1441
+ this.line(`br label %${bodyEntry}`);
1442
+ return entry;
1443
+ }
1444
+ /** The failure dispatcher and the undo resumes. */
1445
+ emitTail() {
1446
+ for (const [r, id] of this.undoIds) {
1447
+ this.block(this.resumes[id]);
1448
+ const [old] = this.pop(1);
1449
+ this.line(`store i32 ${old}, ptr %r${r}`);
1450
+ this.line(`br label %fail`);
1451
+ }
1452
+ this.block("fail");
1453
+ const sp = this.tmp(), empty = this.tmp();
1454
+ this.line(`${sp} = load i32, ptr %sp`);
1455
+ this.line(`${empty} = icmp eq i32 ${sp}, 0`);
1456
+ this.line(`br i1 ${empty}, label %attempt_fail, label %pop`);
1457
+ this.block("pop");
1458
+ const top = this.tmp(), base = this.tmp(), wide = this.tmp(), slot = this.tmp(), id = this.tmp();
1459
+ this.line(`${top} = sub i32 ${sp}, 1`);
1460
+ this.line(`${base} = load ptr, ptr %stk`);
1461
+ this.line(`${wide} = sext i32 ${top} to i64`);
1462
+ this.line(`${slot} = getelementptr inbounds i32, ptr ${base}, i64 ${wide}`);
1463
+ this.line(`${id} = load i32, ptr ${slot}`);
1464
+ this.line(`store i32 ${top}, ptr %sp`);
1465
+ const cases = this.resumes.map((l, k) => `i32 ${k}, label %${l}`).join(" ");
1466
+ this.line(`switch i32 ${id}, label %bad [ ${cases} ]`);
1467
+ this.block("bad");
1468
+ this.line(`unreachable`);
1469
+ }
1470
+ }
1471
+ export const REGEX_MATCHER_DECLS = [
1472
+ `declare void @scr_regex_stack_grow(ptr, ptr, ptr, i32)`,
1473
+ `declare void @scr_regex_stack_free(ptr)`,
1474
+ ];
1475
+ /** Parse a literal's pattern into the compiled subset, or null. */
1476
+ function parseSubset(pattern, flags) {
1477
+ for (const f of flags)
1478
+ if (!"gimsuy".includes(f))
1479
+ return null;
1480
+ if (pattern.length > 2000)
1481
+ return null;
1482
+ const parser = new RxParser(pattern, flags.includes("u"), flags.includes("i"), flags.includes("s"), flags.includes("m"));
1483
+ try {
1484
+ return { root: parser.parse(), ncap: parser.caps };
1485
+ }
1486
+ catch (e) {
1487
+ if (e instanceof RegexBail)
1488
+ return null;
1489
+ throw e;
1490
+ }
1491
+ }
1492
+ /** Whether a literal compiles to a native matcher (tests and size caps). */
1493
+ export function regexLiteralCompiles(pattern, flags) {
1494
+ return parseSubset(pattern, flags) !== null;
1495
+ }
1496
+ /** Why a literal keeps the interpreter ("" when it compiles). */
1497
+ export function regexLiteralBailReason(pattern, flags) {
1498
+ try {
1499
+ new RxParser(pattern, flags.includes("u"), flags.includes("i"), flags.includes("s"), flags.includes("m")).parse();
1500
+ return "";
1501
+ }
1502
+ catch (e) {
1503
+ if (e instanceof RegexBail)
1504
+ return e.reason;
1505
+ throw e;
1506
+ }
1507
+ }
1508
+ /** The native matcher `@sym` of a regex literal, or null when the pattern
1509
+ * is outside the compiled subset. */
1510
+ export function compileRegexMatcher(sym, pattern, flags, sizeType, vector) {
1511
+ const parsed = parseSubset(pattern, flags);
1512
+ if (parsed === null)
1513
+ return null;
1514
+ const sticky = flags.includes("y");
1515
+ const { root, ncap } = parsed;
1516
+ const gen = new RxGen(sym, ncap, vector);
1517
+ const end = { set: emptySet(), nullable: true, bol: false, uncond: true };
1518
+ const start = gen.emit(root, "match", end);
1519
+ const first = thenFollow(firstOf(root), end);
1520
+ const fn = [];
1521
+ fn.push(`define internal i32 @${sym}(ptr %s, i32 %len, i32 %start, ptr %out) #0 {`);
1522
+ fn.push(`entry:`);
1523
+ fn.push(` %pos = alloca i32`);
1524
+ fn.push(` %at = alloca i32`);
1525
+ fn.push(` %sp = alloca i32`);
1526
+ fn.push(` %scap = alloca i32`);
1527
+ fn.push(` %stk = alloca ptr`);
1528
+ fn.push(` %sbuf = alloca [64 x i32]`);
1529
+ for (let r = 0; r < gen.regs; r++)
1530
+ fn.push(` %r${r} = alloca i32`);
1531
+ fn.push(` store ptr %sbuf, ptr %stk`);
1532
+ fn.push(` store i32 64, ptr %scap`);
1533
+ fn.push(` store i32 %start, ptr %at`);
1534
+ fn.push(` %query = icmp slt i32 %len, 0`);
1535
+ fn.push(` br i1 %query, label %count, label %range`);
1536
+ fn.push(`count:`);
1537
+ fn.push(` ret i32 ${ncap}`);
1538
+ fn.push(`range:`);
1539
+ fn.push(` %past = icmp sgt i32 %start, %len`);
1540
+ fn.push(` br i1 %past, label %nomatch, label %scan`);
1541
+ // scan: the next position at or after %at where a match can begin.
1542
+ fn.push(`scan:`);
1543
+ fn.push(` %a = load i32, ptr %at`);
1544
+ const firstCount = setCount(first.set);
1545
+ if (sticky || first.nullable) {
1546
+ fn.push(` br label %attempt`);
1547
+ }
1548
+ else if (first.bol && firstCount === 0) {
1549
+ fn.push(` %a0 = icmp eq i32 %a, 0`);
1550
+ fn.push(` br i1 %a0, label %attempt, label %nomatch`);
1551
+ }
1552
+ else {
1553
+ if (first.bol) {
1554
+ fn.push(` %a0 = icmp eq i32 %a, 0`);
1555
+ fn.push(` br i1 %a0, label %attempt, label %seek`);
1556
+ }
1557
+ else {
1558
+ fn.push(` br label %seek`);
1559
+ }
1560
+ if (firstCount === 1) {
1561
+ fn.push(`seek:`);
1562
+ const byte = intervals(first.set)[0][0];
1563
+ fn.push(` %rest = sub i32 %len, %a`);
1564
+ if (sizeType === "i32")
1565
+ fn.push(` %rest.w = add i32 %rest, 0`);
1566
+ else
1567
+ fn.push(` %rest.w = zext i32 %rest to ${sizeType}`);
1568
+ fn.push(` %a.w = sext i32 %a to i64`);
1569
+ fn.push(` %from = getelementptr inbounds i8, ptr %s, i64 %a.w`);
1570
+ fn.push(` %hit = call ptr @memchr(ptr %from, i32 ${byte}, ${sizeType} %rest.w)`);
1571
+ fn.push(` %none = icmp eq ptr %hit, null`);
1572
+ fn.push(` br i1 %none, label %nomatch, label %found`);
1573
+ fn.push(`found:`);
1574
+ fn.push(` %hit.i = ptrtoint ptr %hit to i64`);
1575
+ fn.push(` %s.i = ptrtoint ptr %s to i64`);
1576
+ fn.push(` %off = sub i64 %hit.i, %s.i`);
1577
+ fn.push(` %off.n = trunc i64 %off to i32`);
1578
+ fn.push(` store i32 %off.n, ptr %at`);
1579
+ fn.push(` br label %attempt`);
1580
+ }
1581
+ else {
1582
+ gen.emitSeek(first.set);
1583
+ }
1584
+ }
1585
+ fn.push(`attempt:`);
1586
+ fn.push(` %b = load i32, ptr %at`);
1587
+ fn.push(` store i32 %b, ptr %pos`);
1588
+ fn.push(` store i32 0, ptr %sp`);
1589
+ for (let r = 2; r < 2 * ncap; r++)
1590
+ fn.push(` store i32 -1, ptr %r${r}`);
1591
+ fn.push(` br label %${start}`);
1592
+ fn.push(`attempt_fail:`);
1593
+ if (sticky) {
1594
+ fn.push(` br label %nomatch`);
1595
+ }
1596
+ else {
1597
+ fn.push(` %c = load i32, ptr %at`);
1598
+ fn.push(` %c1 = add i32 %c, 1`);
1599
+ fn.push(` store i32 %c1, ptr %at`);
1600
+ fn.push(` %over = icmp sgt i32 %c1, %len`);
1601
+ fn.push(` br i1 %over, label %nomatch, label %scan`);
1602
+ }
1603
+ fn.push(`match:`);
1604
+ fn.push(` %m.end = load i32, ptr %pos`);
1605
+ fn.push(` %m.start = load i32, ptr %at`);
1606
+ for (let slot = 0; slot < 2 * ncap; slot++) {
1607
+ const v = slot === 0 ? "%m.start" : slot === 1 ? "%m.end" : `%m.v${slot}`;
1608
+ if (slot >= 2)
1609
+ fn.push(` ${v} = load i32, ptr %r${slot}`);
1610
+ fn.push(` %m.w${slot} = sext i32 ${v} to i64`);
1611
+ fn.push(` %m.p${slot} = getelementptr inbounds i8, ptr %s, i64 %m.w${slot}`);
1612
+ let value = `%m.p${slot}`;
1613
+ if (slot >= 2) {
1614
+ fn.push(` %m.u${slot} = icmp slt i32 ${v}, 0`);
1615
+ fn.push(` %m.q${slot} = select i1 %m.u${slot}, ptr null, ptr %m.p${slot}`);
1616
+ value = `%m.q${slot}`;
1617
+ }
1618
+ fn.push(` %m.o${slot} = getelementptr inbounds ptr, ptr %out, i64 ${slot}`);
1619
+ fn.push(` store ptr ${value}, ptr %m.o${slot}`);
1620
+ }
1621
+ fn.push(` %m.stk = load ptr, ptr %stk`);
1622
+ fn.push(` %m.heap = icmp ne ptr %m.stk, %sbuf`);
1623
+ fn.push(` br i1 %m.heap, label %m.free, label %m.ret`);
1624
+ fn.push(`m.free:`);
1625
+ fn.push(` call void @scr_regex_stack_free(ptr %m.stk)`);
1626
+ fn.push(` br label %m.ret`);
1627
+ fn.push(`m.ret:`);
1628
+ fn.push(` ret i32 1`);
1629
+ fn.push(`nomatch:`);
1630
+ fn.push(` %n.stk = load ptr, ptr %stk`);
1631
+ fn.push(` %n.heap = icmp ne ptr %n.stk, %sbuf`);
1632
+ fn.push(` br i1 %n.heap, label %n.free, label %n.ret`);
1633
+ fn.push(`n.free:`);
1634
+ fn.push(` call void @scr_regex_stack_free(ptr %n.stk)`);
1635
+ fn.push(` br label %n.ret`);
1636
+ fn.push(`n.ret:`);
1637
+ fn.push(` ret i32 0`);
1638
+ gen.emitTail();
1639
+ for (const l of gen.body)
1640
+ fn.push(l);
1641
+ fn.push(`}`);
1642
+ const decls = REGEX_MATCHER_DECLS.slice();
1643
+ if (gen.body.some((l) => l.includes("@llvm.cttz.i16")))
1644
+ decls.push(`declare i16 @llvm.cttz.i16(i16, i1 immarg)`);
1645
+ if (!sticky && !first.nullable && firstCount === 1)
1646
+ decls.push(`declare ptr @memchr(ptr, i32, ${sizeType})`);
1647
+ return { lines: [...gen.globals, ...fn], decls };
1648
+ }
1649
+ //# sourceMappingURL=regex-matchers.js.map