functionalscript 0.45.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/README.md +5 -3
  2. package/fjs/asn.1/module.f.mjs +8 -1
  3. package/fjs/asn.1/proof.f.d.mts +10 -0
  4. package/fjs/asn.1/proof.f.mjs +16 -0
  5. package/fjs/basen/base128/module.f.mjs +22 -5
  6. package/fjs/bnf/data/module.f.d.mts +32 -6
  7. package/fjs/bnf/data/module.f.mjs +112 -7
  8. package/fjs/bnf/data/proof.f.d.mts +2 -0
  9. package/fjs/bnf/data/proof.f.mjs +74 -3
  10. package/fjs/bnf/data/types.d.ts +20 -2
  11. package/fjs/bnf/descent/module.f.d.mts +28 -14
  12. package/fjs/bnf/descent/module.f.mjs +122 -77
  13. package/fjs/bnf/descent/proof.f.d.mts +2 -0
  14. package/fjs/bnf/descent/proof.f.mjs +117 -31
  15. package/fjs/bnf/descent/types.d.ts +12 -14
  16. package/fjs/bnf/ll1/module.f.d.mts +64 -22
  17. package/fjs/bnf/ll1/module.f.mjs +214 -154
  18. package/fjs/bnf/ll1/proof.f.d.mts +15 -2
  19. package/fjs/bnf/ll1/proof.f.mjs +323 -149
  20. package/fjs/bnf/ll1/types.d.ts +16 -24
  21. package/fjs/bnf/matcher/module.f.d.mts +66 -0
  22. package/fjs/bnf/matcher/module.f.mjs +81 -0
  23. package/fjs/bnf/matcher/proof.f.d.mts +10 -0
  24. package/fjs/bnf/matcher/proof.f.mjs +79 -0
  25. package/fjs/bnf/matcher/types.d.ts +54 -0
  26. package/fjs/bnf/testlib.f.d.mts +31 -0
  27. package/fjs/bnf/testlib.f.mjs +80 -0
  28. package/fjs/cas/cli/module.f.d.mts +1 -1
  29. package/fjs/cas/cli/module.f.mjs +14 -20
  30. package/fjs/cas/cli/proof.f.d.mts +1 -3
  31. package/fjs/cas/cli/proof.f.mjs +44 -33
  32. package/fjs/cas/evo/module.f.d.mts +64 -18
  33. package/fjs/cas/evo/module.f.mjs +148 -70
  34. package/fjs/cas/evo/proof.f.d.mts +10 -1
  35. package/fjs/cas/evo/proof.f.mjs +305 -223
  36. package/fjs/cas/evo/types.d.ts +45 -9
  37. package/fjs/cas/module.f.d.mts +18 -32
  38. package/fjs/cas/module.f.mjs +129 -128
  39. package/fjs/cas/proof.f.d.mts +11 -8
  40. package/fjs/cas/proof.f.mjs +259 -147
  41. package/fjs/cas/types.d.ts +24 -10
  42. package/fjs/ci/config/module.f.d.mts +2 -2
  43. package/fjs/ci/config/module.f.mjs +2 -2
  44. package/fjs/ci/module.f.d.mts +5 -5
  45. package/fjs/ci/module.f.mjs +8 -7
  46. package/fjs/ci/nix/module.f.d.mts +7 -5
  47. package/fjs/ci/nix/module.f.mjs +13 -12
  48. package/fjs/ci/nix/proof.f.mjs +2 -2
  49. package/fjs/ci/proof.f.mjs +9 -5
  50. package/fjs/cli/module.f.d.mts +4 -6
  51. package/fjs/cli/module.f.mjs +4 -8
  52. package/fjs/cli/proof.f.mjs +17 -16
  53. package/fjs/cli/types.d.ts +2 -3
  54. package/fjs/common/monoid/types.d.ts +1 -1
  55. package/fjs/crypto/hmac/module.f.mjs +2 -2
  56. package/fjs/crypto/sha2/module.f.mjs +3 -1
  57. package/fjs/crypto/sha2/proof.f.d.mts +1 -0
  58. package/fjs/crypto/sha2/proof.f.mjs +24 -0
  59. package/fjs/crypto/sha2/types.d.ts +11 -0
  60. package/fjs/crypto/sign/module.f.mjs +2 -2
  61. package/fjs/dev/module.f.d.mts +13 -4
  62. package/fjs/dev/module.f.mjs +56 -27
  63. package/fjs/dev/update/module.f.d.mts +9 -4
  64. package/fjs/dev/update/module.f.mjs +14 -10
  65. package/fjs/dev/update/proof.f.d.mts +1 -3
  66. package/fjs/dev/update/proof.f.mjs +10 -5
  67. package/fjs/djs/module.f.d.mts +13 -5
  68. package/fjs/djs/module.f.mjs +31 -16
  69. package/fjs/djs/parser/module.f.d.mts +13 -3
  70. package/fjs/djs/parser/module.f.mjs +117 -16
  71. package/fjs/djs/parser/proof.f.d.mts +5 -1
  72. package/fjs/djs/parser/proof.f.mjs +274 -12
  73. package/fjs/djs/parser/types.d.ts +7 -1
  74. package/fjs/djs/proof.f.d.mts +18 -2
  75. package/fjs/djs/proof.f.mjs +187 -12
  76. package/fjs/djs/serializer/module.f.d.mts +25 -8
  77. package/fjs/djs/serializer/module.f.mjs +61 -15
  78. package/fjs/djs/serializer/proof.f.d.mts +5 -0
  79. package/fjs/djs/serializer/proof.f.mjs +23 -1
  80. package/fjs/djs/tokenizer/module.f.d.mts +17 -5
  81. package/fjs/djs/tokenizer/module.f.mjs +99 -60
  82. package/fjs/djs/tokenizer/proof.f.d.mts +1 -1
  83. package/fjs/djs/tokenizer/proof.f.mjs +74 -67
  84. package/fjs/djs/transpiler/module.f.d.mts +12 -7
  85. package/fjs/djs/transpiler/module.f.mjs +82 -56
  86. package/fjs/djs/transpiler/types.d.ts +7 -3
  87. package/fjs/djs/types.d.ts +7 -1
  88. package/fjs/effects/list/module.f.d.mts +14 -11
  89. package/fjs/effects/list/module.f.mjs +13 -11
  90. package/fjs/effects/list/types.d.ts +27 -7
  91. package/fjs/effects/memory/module.f.d.mts +2 -1
  92. package/fjs/effects/memory/module.f.mjs +3 -4
  93. package/fjs/effects/memory/proof.f.mjs +13 -7
  94. package/fjs/effects/memory/types.d.ts +4 -3
  95. package/fjs/effects/mock/module.f.d.mts +20 -4
  96. package/fjs/effects/mock/module.f.mjs +37 -5
  97. package/fjs/effects/mock/types.d.ts +10 -1
  98. package/fjs/effects/module.d.mts +4 -2
  99. package/fjs/effects/module.f.d.mts +466 -280
  100. package/fjs/effects/module.f.mjs +537 -299
  101. package/fjs/effects/module.mjs +2 -1
  102. package/fjs/effects/node/memory/module.d.mts +4 -2
  103. package/fjs/effects/node/memory/module.mjs +6 -3
  104. package/fjs/effects/node/memory/proof.mjs +10 -4
  105. package/fjs/effects/node/module.d.mts +4 -3
  106. package/fjs/effects/node/module.f.d.mts +168 -33
  107. package/fjs/effects/node/module.f.mjs +256 -52
  108. package/fjs/effects/node/module.mjs +57 -34
  109. package/fjs/effects/node/proof.f.d.mts +28 -2
  110. package/fjs/effects/node/proof.f.mjs +161 -42
  111. package/fjs/effects/node/types.d.ts +106 -18
  112. package/fjs/effects/node/virtual/module.f.d.mts +18 -4
  113. package/fjs/effects/node/virtual/module.f.mjs +110 -68
  114. package/fjs/effects/node/virtual/proof.f.d.mts +28 -2
  115. package/fjs/effects/node/virtual/proof.f.mjs +190 -9
  116. package/fjs/effects/proof.f.d.mts +69 -37
  117. package/fjs/effects/proof.f.mjs +410 -130
  118. package/fjs/effects/types.d.ts +161 -33
  119. package/fjs/emergent_testing/module.f.d.mts +19 -12
  120. package/fjs/emergent_testing/module.f.mjs +93 -33
  121. package/fjs/emergent_testing/proof.f.d.mts +21 -7
  122. package/fjs/emergent_testing/proof.f.mjs +166 -32
  123. package/fjs/emergent_testing/types.d.ts +22 -4
  124. package/fjs/fsm/module.f.d.mts +14 -4
  125. package/fjs/fsm/module.f.mjs +54 -37
  126. package/fjs/fsm/proof.f.d.mts +2 -0
  127. package/fjs/fsm/proof.f.mjs +83 -114
  128. package/fjs/js/keywords/module.f.d.mts +52 -0
  129. package/fjs/js/keywords/module.f.mjs +72 -0
  130. package/fjs/js/keywords/proof.f.d.mts +3 -0
  131. package/fjs/js/keywords/proof.f.mjs +13 -0
  132. package/fjs/js/tokenizer/module.f.d.mts +26 -6
  133. package/fjs/js/tokenizer/module.f.mjs +145 -159
  134. package/fjs/js/tokenizer/proof.f.d.mts +1 -0
  135. package/fjs/js/tokenizer/proof.f.mjs +54 -24
  136. package/fjs/js/tokenizer/types.d.ts +33 -24
  137. package/fjs/mcp/cas/module.f.d.mts +1 -6
  138. package/fjs/mcp/cas/module.f.mjs +55 -51
  139. package/fjs/mcp/cas/proof.f.d.mts +15 -0
  140. package/fjs/mcp/cas/proof.f.mjs +174 -0
  141. package/fjs/mcp/evo/module.f.d.mts +19 -10
  142. package/fjs/mcp/evo/module.f.mjs +48 -27
  143. package/fjs/mcp/evo/proof.f.d.mts +6 -1
  144. package/fjs/mcp/evo/proof.f.mjs +115 -31
  145. package/fjs/mcp/module.f.d.mts +4 -4
  146. package/fjs/mcp/module.f.mjs +6 -6
  147. package/fjs/mcp/proof.f.d.mts +5 -3
  148. package/fjs/mcp/proof.f.mjs +112 -46
  149. package/fjs/media/html/module.f.mjs +1 -1
  150. package/fjs/media/json/extended/module.f.d.mts +82 -0
  151. package/fjs/media/json/extended/module.f.mjs +153 -0
  152. package/fjs/media/json/extended/proof.f.d.mts +42 -0
  153. package/fjs/media/json/extended/proof.f.mjs +127 -0
  154. package/fjs/media/json/extended/types.d.ts +23 -0
  155. package/fjs/media/json/module.f.d.mts +8 -2
  156. package/fjs/media/json/module.f.mjs +43 -41
  157. package/fjs/media/json/number/module.f.d.mts +59 -0
  158. package/fjs/media/json/number/module.f.mjs +136 -0
  159. package/fjs/media/json/number/proof.f.d.mts +24 -0
  160. package/fjs/media/json/number/proof.f.mjs +86 -0
  161. package/fjs/media/json/number/types.d.ts +28 -0
  162. package/fjs/media/json/parser/module.f.d.mts +25 -13
  163. package/fjs/media/json/parser/module.f.mjs +114 -70
  164. package/fjs/media/json/parser/proof.f.d.mts +5 -0
  165. package/fjs/media/json/parser/proof.f.mjs +31 -1
  166. package/fjs/media/json/parser/types.d.ts +33 -14
  167. package/fjs/media/json/rtti/module.f.d.mts +1 -1
  168. package/fjs/media/json/rtti/module.f.mjs +1 -1
  169. package/fjs/media/json/rtti/proof.f.mjs +9 -9
  170. package/fjs/media/json/schema/module.f.mjs +3 -13
  171. package/fjs/media/json/schema/proof.f.d.mts +0 -1
  172. package/fjs/media/json/schema/proof.f.mjs +1 -2
  173. package/fjs/media/json/serializer/module.f.d.mts +32 -1
  174. package/fjs/media/json/serializer/module.f.mjs +64 -2
  175. package/fjs/media/json/tokenizer/module.f.mjs +7 -3
  176. package/fjs/media/json/tokenizer/proof.f.d.mts +6 -0
  177. package/fjs/media/json/tokenizer/proof.f.mjs +62 -21
  178. package/fjs/media/json/types.d.ts +36 -10
  179. package/fjs/media/lock/module.f.d.mts +100 -0
  180. package/fjs/media/lock/module.f.mjs +125 -0
  181. package/fjs/media/lock/proof.f.d.mts +33 -0
  182. package/fjs/media/lock/proof.f.mjs +196 -0
  183. package/fjs/media/lock/types.d.ts +15 -0
  184. package/fjs/media/module.f.d.mts +6 -5
  185. package/fjs/media/module.f.mjs +8 -7
  186. package/fjs/media/note/module.f.d.mts +121 -0
  187. package/fjs/media/note/module.f.mjs +131 -0
  188. package/fjs/media/note/proof.f.d.mts +29 -0
  189. package/fjs/media/note/proof.f.mjs +150 -0
  190. package/fjs/media/note/types.d.ts +10 -0
  191. package/fjs/media/proof.f.d.mts +4 -1
  192. package/fjs/media/proof.f.mjs +40 -21
  193. package/fjs/media/revision/module.f.d.mts +78 -7
  194. package/fjs/media/revision/module.f.mjs +119 -12
  195. package/fjs/media/revision/proof.f.d.mts +10 -0
  196. package/fjs/media/revision/proof.f.mjs +88 -0
  197. package/fjs/media/revision/types.d.ts +34 -5
  198. package/fjs/media/type/module.f.d.mts +33 -15
  199. package/fjs/media/type/module.f.mjs +35 -29
  200. package/fjs/media/type/proof.f.d.mts +2 -1
  201. package/fjs/media/type/proof.f.mjs +30 -10
  202. package/fjs/module.f.mjs +29 -8
  203. package/fjs/nanvm/proof.f.mjs +3 -3
  204. package/fjs/nanvm/rust/module.f.mjs +1 -1
  205. package/fjs/nanvm/update/module.f.d.mts +4 -4
  206. package/fjs/nanvm/update/module.f.mjs +8 -9
  207. package/fjs/nanvm/update/proof.f.mjs +4 -3
  208. package/fjs/proof.f.d.mts +3 -3
  209. package/fjs/proof.f.mjs +36 -10
  210. package/fjs/protocol/json_rpc/module.f.d.mts +2 -2
  211. package/fjs/protocol/json_rpc/module.f.mjs +3 -3
  212. package/fjs/protocol/json_rpc/proof.f.mjs +4 -4
  213. package/fjs/protocol/mcp/module.f.d.mts +10 -13
  214. package/fjs/protocol/mcp/module.f.mjs +74 -58
  215. package/fjs/protocol/mcp/proof.f.d.mts +13 -4
  216. package/fjs/protocol/mcp/proof.f.mjs +193 -61
  217. package/fjs/protocol/mcp/stdio/module.f.d.mts +15 -7
  218. package/fjs/protocol/mcp/stdio/module.f.mjs +38 -25
  219. package/fjs/protocol/mcp/stdio/proof.f.d.mts +4 -2
  220. package/fjs/protocol/mcp/stdio/proof.f.mjs +45 -12
  221. package/fjs/protocol/mcp/stdio/types.d.ts +1 -1
  222. package/fjs/protocol/mcp/types.d.ts +17 -6
  223. package/fjs/sul/id/module.f.d.mts +0 -1
  224. package/fjs/sul/id/module.f.mjs +2 -3
  225. package/fjs/sul/level/hash/module.f.mjs +2 -1
  226. package/fjs/sul/level/hash/proof.f.mjs +2 -2
  227. package/fjs/sul/module.f.mjs +18 -13
  228. package/fjs/text/code_point/module.f.d.mts +8 -0
  229. package/fjs/text/code_point/module.f.mjs +8 -1
  230. package/fjs/text/code_point/proof.f.d.mts +1 -0
  231. package/fjs/text/code_point/proof.f.mjs +11 -0
  232. package/fjs/text/sgr/module.f.d.mts +4 -6
  233. package/fjs/text/sgr/module.f.mjs +6 -7
  234. package/fjs/text/utf16/module.f.mjs +7 -2
  235. package/fjs/text/utf16/proof.f.mjs +3 -3
  236. package/fjs/text/utf8/module.f.mjs +4 -2
  237. package/fjs/types/array/module.f.mjs +14 -2
  238. package/fjs/types/bit_vec/module.f.d.mts +0 -2
  239. package/fjs/types/bit_vec/module.f.mjs +46 -32
  240. package/fjs/types/bit_vec/proof.f.mjs +2 -2
  241. package/fjs/types/btree/remove/module.f.mjs +1 -1
  242. package/fjs/types/btree/set/module.f.mjs +9 -11
  243. package/fjs/types/btree/set/proof.f.mjs +12 -0
  244. package/fjs/types/byte_set/module.f.d.mts +11 -4
  245. package/fjs/types/byte_set/module.f.mjs +14 -6
  246. package/fjs/types/byte_set/proof.f.mjs +7 -7
  247. package/fjs/types/function/compare/module.f.mjs +10 -3
  248. package/fjs/types/list/module.f.d.mts +1 -1
  249. package/fjs/types/list/module.f.mjs +1 -1
  250. package/fjs/types/nullable/module.f.d.mts +18 -4
  251. package/fjs/types/nullable/module.f.mjs +21 -4
  252. package/fjs/types/nullable/proof.f.d.mts +4 -0
  253. package/fjs/types/nullable/proof.f.mjs +15 -0
  254. package/fjs/types/object/module.f.d.mts +12 -2
  255. package/fjs/types/object/module.f.mjs +11 -1
  256. package/fjs/types/patricia_trie/module.f.mjs +26 -11
  257. package/fjs/types/result/module.f.d.mts +3 -3
  258. package/fjs/types/result/module.f.mjs +3 -3
  259. package/fjs/types/rtti/common/module.f.d.mts +25 -28
  260. package/fjs/types/rtti/common/module.f.mjs +36 -32
  261. package/fjs/types/rtti/common/proof.f.mjs +5 -5
  262. package/fjs/types/rtti/data/module.f.d.mts +14 -0
  263. package/fjs/types/rtti/data/module.f.mjs +25 -2
  264. package/fjs/types/rtti/data/proof.f.d.mts +1 -0
  265. package/fjs/types/rtti/data/proof.f.mjs +25 -2
  266. package/fjs/types/rtti/parse/module.f.d.mts +24 -14
  267. package/fjs/types/rtti/parse/module.f.mjs +37 -28
  268. package/fjs/types/rtti/parse/proof.f.d.mts +3 -2
  269. package/fjs/types/rtti/parse/proof.f.mjs +33 -14
  270. package/fjs/types/rtti/proof.f.mjs +3 -1
  271. package/fjs/types/rtti/ts/module.f.mjs +13 -17
  272. package/fjs/types/rtti/ts/types.d.ts +14 -1
  273. package/fjs/types/sorted_set/module.f.d.mts +18 -0
  274. package/fjs/types/sorted_set/module.f.mjs +22 -0
  275. package/fjs/types/sorted_set/proof.f.d.mts +1 -0
  276. package/fjs/types/sorted_set/proof.f.mjs +16 -1
  277. package/fjs/types/uint8array/module.f.d.mts +1 -1
  278. package/fjs/types/uint8array/module.f.mjs +1 -1
  279. package/fjs/website/module.f.d.mts +3 -3
  280. package/fjs/website/module.f.mjs +4 -7
  281. package/fjs/website/proof.f.mjs +2 -1
  282. package/package.json +2 -2
  283. package/fjs/dev/package_json/module.f.d.mts +0 -39
  284. package/fjs/dev/package_json/module.f.mjs +0 -40
  285. package/fjs/dev/package_json/proof.f.d.mts +0 -6
  286. package/fjs/dev/package_json/proof.f.mjs +0 -32
  287. package/fjs/effects/eff/module.f.d.mts +0 -20
  288. package/fjs/effects/eff/module.f.mjs +0 -70
  289. package/fjs/effects/eff/proof.f.d.mts +0 -15
  290. package/fjs/effects/eff/proof.f.mjs +0 -69
  291. package/fjs/effects/eff/types.d.ts +0 -71
  292. package/fjs/types/rtti/validate/module.f.d.mts +0 -41
  293. package/fjs/types/rtti/validate/module.f.mjs +0 -171
  294. package/fjs/types/rtti/validate/proof.f.d.mts +0 -125
  295. package/fjs/types/rtti/validate/proof.f.mjs +0 -437
  296. package/fjs/types/rtti/validate/types.d.ts +0 -6
@@ -7,6 +7,8 @@
7
7
  * @import { Result } from '../../types/result/types.ts'
8
8
  * @import { ParseError } from '../parser/types.ts'
9
9
  * @import { AstModule } from '../ast/types.ts'
10
+ * @import { Operation } from '../../effects/types.ts'
11
+ * @import { IoChannel } from '../../effects/node/types.ts'
10
12
  * @import { Effect } from '../../effects/types.ts'
11
13
  * @import { ReadFile } from '../../effects/node/types.ts'
12
14
  * @import { ParseContext } from './types.ts'
@@ -19,10 +21,21 @@ import { setReplace, at } from '../../types/ordered_map/module.f.mjs'
19
21
  import { stringToList } from '../../text/utf16/module.f.mjs'
20
22
  import { concat as pathConcat } from '../../path/module.f.mjs'
21
23
  import { parseFromTokens } from '../parser/module.f.mjs'
24
+ import { parse as jsonParse } from '../../media/json/module.f.mjs'
22
25
  import { run } from '../ast/module.f.mjs'
23
- import { foldStep, pure, step } from '../../effects/module.f.mjs'
26
+ import { pure } from '../../effects/module.f.mjs'
27
+ import { catchStep, foldStep, mapStep, pureError, pureOk, step } from '../../effects/module.f.mjs'
24
28
  import { readUtf8File } from '../../effects/node/module.f.mjs'
25
29
 
30
+ /**
31
+ * Reads a file, reporting any failure as the one `ParseError` a caller can act
32
+ * on. Both readers want this and neither wants the node channel's vocabulary.
33
+ *
34
+ * @type {<O extends Operation>(e: Effect<O, string, IoChannel>) => Effect<O, string, ParseError>}
35
+ */
36
+ const notFound = e =>
37
+ catchStep(e, () => pureError({ message: 'file not found', metadata: null }))
38
+
26
39
  /** @type {(context: ParseContext) => (path: string) => Unknown} */
27
40
  const mapDjs = context => path => {
28
41
  const res = at(path)(context.complete)
@@ -33,82 +46,95 @@ const mapDjs = context => path => {
33
46
  return res.djs
34
47
  }
35
48
 
36
- /** @type {(path: string) => Effect<ReadFile, Result<AstModule, ParseError>>} */
49
+ /**
50
+ * `catchStep` rather than a branch on the read's `Result`: however the read
51
+ * failed — missing file, unreadable, a runner without `readFile` — the answer
52
+ * a transpiler gives is the same `ParseError`, so the node channel is
53
+ * translated once here rather than travelling any further.
54
+ *
55
+ * @type {(path: string) => Effect<ReadFile, AstModule, ParseError>}
56
+ */
37
57
  const parseModule = path => step(
38
- readUtf8File(path),
39
- result => {
40
- if (result[0] === 'error') {
41
- return pure(error({ message: 'file not found', metadata: null }))
42
- }
43
- const tokens = tokenize(stringToList(result[1]))(path)
44
- return pure(parseFromTokens(tokens))
45
- })
58
+ notFound(readUtf8File(path)),
59
+ text => pure(parseFromTokens(tokenize(stringToList(text))(path))))
46
60
 
47
- /** @type {(path: string) => (parseModuleResult: Result<AstModule, ParseError>) => (context: ParseContext) => Effect<ReadFile, ParseContext>} */
48
- const transpileWithImports = path => parseModuleResult => context => {
49
- if (parseModuleResult[0] === 'ok') {
50
- const dir = pathConcat(path)('..')
51
- const pathsCombine = listMap(pathConcat(dir))(parseModuleResult[1][0])
52
- const pathsArray = toArray(pathsCombine)
53
- const contextWithStack = { ...context, stack: { first: path, tail: context.stack } }
54
- const x0 = foldStep(pure(pathsArray), contextWithStack, foldNextModuleOp)
55
- return step(
56
- x0,
57
- contextWithImports => {
58
- if (contextWithImports.error !== null) {
59
- return pure(contextWithImports)
60
- }
61
- const args = toArray(listMap(mapDjs(contextWithImports))(pathsCombine))
62
- const djs = { djs: run(parseModuleResult[1][1])(args) }
63
- return pure({
64
- ...contextWithImports,
65
- stack: drop(1)(contextWithImports.stack),
66
- complete: setReplace(path)(djs)(contextWithImports.complete),
67
- })
61
+ /** @type {(path: string) => (module: AstModule) => (context: ParseContext) => Effect<ReadFile, ParseContext, ParseError>} */
62
+ const transpileWithImports = path => module => context => {
63
+ const dir = pathConcat(path)('..')
64
+ const pathsCombine = listMap(pathConcat(dir))(module[0])
65
+ const pathsArray = toArray(pathsCombine)
66
+ const contextWithStack = { ...context, stack: { first: path, tail: context.stack } }
67
+ const x0 = foldStep(pureOk(pathsArray), contextWithStack, foldNextModuleOp)
68
+ return step(
69
+ x0,
70
+ contextWithImports => {
71
+ const args = toArray(listMap(mapDjs(contextWithImports))(pathsCombine))
72
+ const djs = { djs: run(module[1])(args) }
73
+ return pureOk({
74
+ ...contextWithImports,
75
+ stack: drop(1)(contextWithImports.stack),
76
+ complete: setReplace(path)(djs)(contextWithImports.complete),
68
77
  })
69
- }
70
- return pure({ ...context, error: parseModuleResult[1] })
78
+ })
71
79
  }
72
80
 
73
- /** @type {(path: string) => (context: ParseContext) => Effect<ReadFile, ParseContext>} */
81
+ /** @type {(path: string) => (context: ParseContext) => Effect<ReadFile, ParseContext, ParseError>} */
74
82
  const foldNextModuleOp = path => context => {
75
- if (context.error !== null) {
76
- return pure(context)
77
- }
78
-
79
83
  if (includes(path)(context.stack)) {
80
- return pure({ ...context, error: { message: 'circular dependency', metadata: null } })
84
+ return pureError({ message: 'circular dependency', metadata: null })
81
85
  }
82
86
 
83
87
  if (at(path)(context.complete) !== null) {
84
- return pure(context)
88
+ return pureOk(context)
85
89
  }
86
90
 
87
91
  return step(
88
92
  parseModule(path),
89
- parseModuleResult => transpileWithImports(path)(parseModuleResult)(context))
93
+ module => transpileWithImports(path)(module)(context))
90
94
  }
91
95
 
96
+ /** @type {(path: string) => Effect<ReadFile, Unknown, ParseError>} */
97
+ const transpileModule = path => mapStep(
98
+ foldNextModuleOp(path)({ stack: null, complete: null }),
99
+ context => at(path)(context.complete)?.djs)
100
+
92
101
  /**
93
- * Transpiles a DJS module graph rooted at `path` into a single `Unknown` value.
102
+ * A JSON document is a value, not a module: it imports nothing and names
103
+ * nothing, so it needs no AST and no evaluation — `fjs/media/json` reads it
104
+ * and the value is the result.
94
105
  *
95
- * Reads each file via the `ReadFile` effect, resolves imports recursively, and
96
- * evaluates the AST. Returns `['ok', value]` on success, or `['error', ParseError]`
97
- * on a parse failure or circular dependency.
106
+ * That reader reports its errors without a position, so the `ParseError` has
107
+ * no metadata and `fjs/djs`'s `compile` names the file instead of a line and
108
+ * column.
98
109
  *
99
- * @type {(path: string) => Effect<ReadFile, Result<Unknown, ParseError>>}
110
+ * @type {(path: string) => Effect<ReadFile, Unknown, ParseError>}
100
111
  */
101
- export const transpile = path => step(
102
- foldNextModuleOp(path)({ stack: null, complete: null, error: null }),
103
- /** @type {(context: ParseContext) => Effect<ReadFile, Result<Unknown, ParseError>>} */
104
- (context) => {
105
- if (context.error !== null) {
106
- return pure(error(context.error))
107
- }
108
- const result = at(path)(context.complete)?.djs
109
- return pure(ok(result))
112
+ const transpileJson = path => step(
113
+ notFound(readUtf8File(path)),
114
+ text => {
115
+ const json = jsonParse(text)
116
+ return pure(json[0] === 'error'
117
+ ? error({ message: json[1], metadata: null })
118
+ : ok(json[1]))
110
119
  })
111
120
 
121
+ /**
122
+ * Transpiles the file at `path` into a single `Unknown` value.
123
+ *
124
+ * The extension names its language: a `.json` file is a JSON document, read by
125
+ * `fjs/media/json`, and anything else is a FunctionalScript module, whose
126
+ * imports are resolved recursively — each of them a module too, whatever it is
127
+ * called ([spec: the `__proto__` key](../../../spec/README.md#the-__proto__-key)).
128
+ *
129
+ * Returns `['ok', value]` on success, or `['error', ParseError]` on a parse
130
+ * failure, a missing file, or a circular dependency.
131
+ *
132
+ * @type {(path: string) => Effect<ReadFile, Unknown, ParseError>}
133
+ */
134
+ export const transpile = path => path.endsWith('.json')
135
+ ? transpileJson(path)
136
+ : transpileModule(path)
137
+
112
138
  // ── Tests ────────────────────────────────────────────────────────────────────
113
139
 
114
140
  export const proof = {
@@ -117,6 +143,6 @@ export const proof = {
117
143
  // has already resolved into `context.complete`, so the `res === null`
118
144
  // guard is an internal-invariant check unreachable through `transpile`'s
119
145
  // public API. Call it directly with an empty `complete` map to cover it.
120
- mapDjsUnresolvedImport: () => mapDjs({ complete: null, stack: null, error: null })('missing.djs'),
146
+ mapDjsUnresolvedImport: () => mapDjs({ complete: null, stack: null })('missing.djs'),
121
147
  },
122
148
  }
@@ -6,7 +6,6 @@
6
6
  import type { Unknown } from '../types.ts';
7
7
  import type { List } from '../../types/list/types.ts';
8
8
  import type { OrderedMap } from '../../types/ordered_map/types.ts';
9
- import type { ParseError } from '../parser/types.ts';
10
9
  /** The evaluated DJS value produced for one successfully transpiled module. */
11
10
  export type djsResult = {
12
11
  djs: Unknown;
@@ -16,10 +15,15 @@ export type djsResult = {
16
15
  *
17
16
  * - `complete`: modules that have been fully parsed and evaluated, keyed by path.
18
17
  * - `stack`: import chain currently being resolved (used to detect circular dependencies).
19
- * - `error`: the first parse error encountered, or `null` while everything is clean.
18
+ *
19
+ * There is no `error` field. It used to hold "the first parse error
20
+ * encountered, or `null` while everything is clean" — a hand-rolled error
21
+ * channel that every step had to set, and that three separate places had to
22
+ * test before doing any work. It is the effect's channel now
23
+ * (`Effect<ReadFile, ParseContext, ParseError>`), so `step` short-circuits and
24
+ * a context that exists is a context that is still good.
20
25
  */
21
26
  export type ParseContext = {
22
27
  readonly complete: OrderedMap<djsResult>;
23
28
  readonly stack: List<string>;
24
- readonly error: ParseError | null;
25
29
  };
@@ -4,10 +4,16 @@
4
4
  *
5
5
  * @module
6
6
  */
7
- import type { Primitive as JsonPrimitive } from '../media/json/types.ts';
7
+ import type { Primitive as JsonPrimitive, TreeMapEntries } from '../media/json/types.ts';
8
8
  export type Object = {
9
9
  readonly [k in string]?: Unknown;
10
10
  };
11
11
  export type Array = readonly Unknown[];
12
12
  export type Primitive = JsonPrimitive | bigint | undefined;
13
13
  export type Unknown = Primitive | Object | Array;
14
+ /**
15
+ * How the serializer orders an object's entries — `sort` for canonical
16
+ * output, `identity` to keep insertion order. The same alias JSON and
17
+ * extended JSON instantiate, at DJS's leaf set.
18
+ */
19
+ export type _MapEntries = TreeMapEntries<Primitive>;
@@ -5,28 +5,31 @@
5
5
  *
6
6
  * @module
7
7
  *
8
- * @import { Effect, Operation } from "../types.ts"
8
+ * @import { Operation } from "../types.ts"
9
+ * @import { Effect } from "../types.ts"
9
10
  * @import { List, Next } from "./types.ts"
10
11
  */
11
- import type { Effect, Operation } from "../types.ts";
12
+ import type { Operation } from "../types.ts";
13
+ import type { Effect } from "../types.ts";
12
14
  import type { List, Next } from "./types.ts";
13
15
  /**
14
16
  * The empty `List`: a pure end-of-stream marker (`undefined`).
15
17
  *
16
- * The explicit `Effect<O, Next<O, T>>` return type lets the contextual type drive the
17
- * check, so the recursive payload type-checks without a cast. Construct streams through
18
- * these two combinators.
18
+ * The explicit `Effect<O, Next<O, T, E>, E>` return type lets the contextual
19
+ * type drive the check, so the recursive payload type-checks without a cast.
20
+ * Construct streams through these two combinators, and end a stream that
21
+ * *failed* with `pureError` rather than with either of them.
19
22
  *
20
- * Note: we use `Effect<O, Next<O, T>>` because TypeScript can't convert `pure(...)` to
21
- * `List<O, T>`.
23
+ * Note: the expanded type is written out because TypeScript cannot convert
24
+ * `pureOk(...)` to `List<O, T, E>`.
22
25
  *
23
- * @type {<O extends Operation, T>() => Effect<O, Next<O, T>>}
26
+ * @type {<O extends Operation, T, E>() => Effect<O, Next<O, T, E>, E>}
24
27
  */
25
- export declare const empty: <O extends Operation, T>() => Effect<O, Next<O, T>>;
28
+ export declare const empty: <O extends Operation, T, E>() => Effect<O, Next<O, T, E>, E>;
26
29
  /**
27
30
  * Prepends `first` to a {@link List} `tail`, as a pure cons cell. `tail` is an
28
31
  * ordinary argument, so it is built before the cell is — see {@link Next}.
29
32
  *
30
- * @type {<O extends Operation, T>(first: T, tail: List<O, T>) => Effect<O, Next<O, T>>}
33
+ * @type {<O extends Operation, T, E>(first: T, tail: List<O, T, E>) => Effect<O, Next<O, T, E>, E>}
31
34
  */
32
- export declare const nonEmpty: <O extends Operation, T>(first: T, tail: List<O, T>) => Effect<O, Next<O, T>>;
35
+ export declare const nonEmpty: <O extends Operation, T, E>(first: T, tail: List<O, T, E>) => Effect<O, Next<O, T, E>, E>;
@@ -5,32 +5,34 @@
5
5
  *
6
6
  * @module
7
7
  *
8
- * @import { Effect, Operation } from "../types.ts"
8
+ * @import { Operation } from "../types.ts"
9
+ * @import { Effect } from "../types.ts"
9
10
  * @import { List, Next } from "./types.ts"
10
11
  */
11
12
 
12
- import { pure } from "../module.f.mjs"
13
+ import { pureOk } from "../module.f.mjs"
13
14
 
14
15
  /**
15
16
  * The empty `List`: a pure end-of-stream marker (`undefined`).
16
17
  *
17
- * The explicit `Effect<O, Next<O, T>>` return type lets the contextual type drive the
18
- * check, so the recursive payload type-checks without a cast. Construct streams through
19
- * these two combinators.
18
+ * The explicit `Effect<O, Next<O, T, E>, E>` return type lets the contextual
19
+ * type drive the check, so the recursive payload type-checks without a cast.
20
+ * Construct streams through these two combinators, and end a stream that
21
+ * *failed* with `pureError` rather than with either of them.
20
22
  *
21
- * Note: we use `Effect<O, Next<O, T>>` because TypeScript can't convert `pure(...)` to
22
- * `List<O, T>`.
23
+ * Note: the expanded type is written out because TypeScript cannot convert
24
+ * `pureOk(...)` to `List<O, T, E>`.
23
25
  *
24
- * @type {<O extends Operation, T>() => Effect<O, Next<O, T>>}
26
+ * @type {<O extends Operation, T, E>() => Effect<O, Next<O, T, E>, E>}
25
27
  */
26
28
  export const empty = () =>
27
- pure(undefined)
29
+ pureOk(undefined)
28
30
 
29
31
  /**
30
32
  * Prepends `first` to a {@link List} `tail`, as a pure cons cell. `tail` is an
31
33
  * ordinary argument, so it is built before the cell is — see {@link Next}.
32
34
  *
33
- * @type {<O extends Operation, T>(first: T, tail: List<O, T>) => Effect<O, Next<O, T>>}
35
+ * @type {<O extends Operation, T, E>(first: T, tail: List<O, T, E>) => Effect<O, Next<O, T, E>, E>}
34
36
  */
35
37
  export const nonEmpty = (first, tail) =>
36
- pure({ first, tail })
38
+ pureOk({ first, tail })
@@ -3,10 +3,11 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import type { Effect, Operation } from '../types.ts';
7
- export type NonEmpty<O extends Operation, T> = {
6
+ import type { Operation } from '../types.ts';
7
+ import type { Effect, NotImplemented } from '../types.ts';
8
+ export type NonEmpty<O extends Operation, T, E> = {
8
9
  readonly first: T;
9
- readonly tail: List<O, T>;
10
+ readonly tail: List<O, T, E>;
10
11
  };
11
12
  /**
12
13
  * The payload of a `List` effect: the next cons cell, or `undefined` at
@@ -19,8 +20,27 @@ export type NonEmpty<O extends Operation, T> = {
19
20
  * streaming comes from cells produced inside a command's continuation, where
20
21
  * the tail is not reached until a runner performs the command.
21
22
  *
22
- * `Effect<O, Next<O, T>>` is used directly in places where `List<O, T>` cannot
23
- * be written as a return type (see `empty`).
23
+ * `Effect<O, Next<O, T, E>, E>` is used directly in places where
24
+ * `List<O, T, E>` cannot be written as a return type (see `empty`).
24
25
  */
25
- export type Next<O extends Operation, T> = NonEmpty<O, T> | undefined;
26
- export type List<O extends Operation, T> = Effect<O, Next<O, T>>;
26
+ export type Next<O extends Operation, T, E> = NonEmpty<O, T, E> | undefined;
27
+ /**
28
+ * A stream of `T`s, pulled one cell at a time, which may fail with `E`.
29
+ *
30
+ * **The failure belongs to the cell, not to the item.** A producer that cannot
31
+ * deliver ends the stream by failing it, so there is no such thing as a stream
32
+ * that continues after an error and no tail to construct after one. Putting the
33
+ * failure in `T` instead — `List<O, IoResult<Vec>>`, as this used to be — made
34
+ * an `error` item and an `undefined` end-of-stream two values of one union that
35
+ * every consumer had to keep apart by hand, and left a failing producer
36
+ * obliged to supply a tail nobody would ever pull.
37
+ *
38
+ * It also made short-circuiting unfactorable: a combinator generic in `T`
39
+ * cannot look inside it, so every consumer hand-wrote the same
40
+ * `if (t === 'error') return …`. With the failure in the cell, `step` does it.
41
+ *
42
+ * The cost is that a stream can no longer report one bad item and carry on.
43
+ * Nothing wanted that; a reader that did would carry a `Result` in `T`
44
+ * deliberately, which remains expressible and now means what it says.
45
+ */
46
+ export type List<O extends Operation, T, E = NotImplemented> = Effect<O, Next<O, T, E>, E>;
@@ -7,7 +7,7 @@
7
7
  * generation strategy.
8
8
  *
9
9
  * Memory effects compose with other effects by unioning operation types, for
10
- * example `Effect<IoOp | MemOp, T>` for a program that performs both I/O and
10
+ * example `Effect<IoOp | MemOp, T, E>` for a program that performs both I/O and
11
11
  * memory operations.
12
12
  *
13
13
  * See `./types.ts` for the `Key`/`MemCreate`/`MemRead`/`MemWrite`/`MemOp`
@@ -31,4 +31,5 @@ export declare const create: <T>(value: T) => Effect<MemCreate, Key<T>>;
31
31
  /** Reads the current contents of a typed memory slot. */
32
32
  export declare const read: <T>(key: Key<T>) => Effect<MemRead, T>;
33
33
  /** Replaces the current contents of a typed memory slot. */
34
+ /** @type {<T>(key: Key<T>, value: T) => Effect<MemWrite, void>} */
34
35
  export declare const write: <T>(key: Key<T>, value: T) => Effect<MemWrite, void>;
@@ -7,7 +7,7 @@
7
7
  * generation strategy.
8
8
  *
9
9
  * Memory effects compose with other effects by unioning operation types, for
10
- * example `Effect<IoOp | MemOp, T>` for a program that performs both I/O and
10
+ * example `Effect<IoOp | MemOp, T, E>` for a program that performs both I/O and
11
11
  * memory operations.
12
12
  *
13
13
  * See `./types.ts` for the `Key`/`MemCreate`/`MemRead`/`MemWrite`/`MemOp`
@@ -40,6 +40,5 @@ export const read =
40
40
  (do_('memRead'))
41
41
 
42
42
  /** Replaces the current contents of a typed memory slot. */
43
- export const write =
44
- /** @type {<T>(key: Key<T>, value: T) => Effect<MemWrite, void>} */
45
- (do_('memWrite'))
43
+ /** @type {<T>(key: Key<T>, value: T) => Effect<MemWrite, void>} */
44
+ export const write = do_('memWrite')
@@ -4,8 +4,9 @@
4
4
  */
5
5
 
6
6
  import { assert, assertEq } from '../../asserts/module.f.mjs'
7
+ import { ok } from '../../types/result/module.f.mjs'
7
8
  import { run } from '../mock/module.f.mjs'
8
- import { pure, step } from '../module.f.mjs'
9
+ import { pureOk, step } from '../module.f.mjs'
9
10
  import {
10
11
  asBase, asNominal,
11
12
  create, read, write,
@@ -30,20 +31,22 @@ const mock = {
30
31
  return [{
31
32
  next: state.next + 1,
32
33
  values: { ...state.values, [id]: value },
33
- }, key]
34
+ }, ok(key)]
34
35
  },
35
36
  memRead: key => state =>
36
- [state, state.values[asBase(key)]],
37
+ [state, ok(state.values[asBase(key)])],
37
38
  memWrite: (key, value) => state => {
38
39
  const id = asBase(key)
39
40
  assert(id in state.values, id)
40
41
  return [{
41
42
  ...state,
42
43
  values: { ...state.values, [id]: value },
43
- }, undefined]
44
+ }, ok(undefined)]
44
45
  },
45
46
  }
46
47
 
48
+ // `step`: each link runs only because the previous one returned `ok`,
49
+ // and a runner that omitted a handler would propagate rather than be ignored.
47
50
  const program = step(
48
51
  create(1),
49
52
  key => {
@@ -58,7 +61,8 @@ const program = step(
58
61
  export const proof = {
59
62
  roundTrip: () => {
60
63
  const [state, result] = run(mock)(initial)(program)
61
- assertEq(result, 42)
64
+ assert(result[0] === 'ok', result)
65
+ assertEq(result[1], 42)
62
66
  assertEq(state.values.k0, 42, state)
63
67
  },
64
68
  allocatesFreshKeys: () => {
@@ -66,8 +70,10 @@ export const proof = {
66
70
  create('a'),
67
71
  a => step(
68
72
  create('b'),
69
- b => pure(/** @type {const} */ ([asBase(a), asBase(b)]))))
70
- const [state, [a, b]] = run(mock)(initial)(effect)
73
+ b => pureOk(/** @type {const} */ ([asBase(a), asBase(b)]))))
74
+ const [state, result] = run(mock)(initial)(effect)
75
+ assert(result[0] === 'ok', result)
76
+ const [a, b] = result[1]
71
77
  assertEq(a, 'k0')
72
78
  assertEq(b, 'k1')
73
79
  assertEq(state.values.k0, 'a', state)
@@ -5,14 +5,15 @@
5
5
  */
6
6
  import type { Phantom } from '../../types/phantom/types.ts';
7
7
  import type { Nominal } from '../../types/nominal/types.ts';
8
+ import type { OpResult } from '../node/types.ts';
8
9
  /** Nominal brand version for memory keys. */
9
10
  export type _MemKeyHash = '3f114fa6036a8da026b827f0c3e6d901f5e81ad9a320e431ccce31451892d286';
10
11
  /** Opaque handle for a value stored by the memory interpreter. */
11
12
  export type Key<T> = Phantom<Nominal<'MemKey', _MemKeyHash, string>, T>;
12
13
  /** Allocates a fresh memory slot and initializes it with `value`. */
13
- export type MemCreate = readonly ['memCreate', <T>(value: T) => Key<T>];
14
+ export type MemCreate = readonly ['memCreate', <T>(value: T) => OpResult<Key<T>>];
14
15
  /** Reads the current value stored at `key`. */
15
- export type MemRead = readonly ['memRead', <T>(key: Key<T>) => T];
16
+ export type MemRead = readonly ['memRead', <T>(key: Key<T>) => OpResult<T>];
16
17
  /** Replaces the current value stored at `key`. */
17
- export type MemWrite = readonly ['memWrite', <T>(key: Key<T>, value: T) => void];
18
+ export type MemWrite = readonly ['memWrite', <T>(key: Key<T>, value: T) => OpResult<void>];
18
19
  export type MemOp = MemCreate | MemRead | MemWrite;
@@ -5,10 +5,26 @@
5
5
  *
6
6
  * @module
7
7
  *
8
- * @import { Operation } from '../types.ts'
9
- * @import { MemOperationMap, RunInstance } from './types.ts'
8
+ * @import { Commands, Effect, MatchResult, Operation } from '../types.ts'
9
+ * @import { MemOperationMap, PartialMemOperationMap, RunInstance } from './types.ts'
10
10
  */
11
- import type { Operation } from '../types.ts';
12
- import type { MemOperationMap, RunInstance } from './types.ts';
11
+ import type { Commands, Operation } from '../types.ts';
12
+ import type { MemOperationMap, PartialMemOperationMap, RunInstance } from './types.ts';
13
13
  /** @type {<O extends Operation, S>(o: MemOperationMap<O, S>) => RunInstance<O, S>} */
14
14
  export declare const run: <O extends Operation, S>(o: MemOperationMap<O, S>) => RunInstance<O, S>;
15
+ /**
16
+ * {@link run} for a runner that implements only part of `O`.
17
+ *
18
+ * A command in `commands` with no handler answers `error(notImplemented)`
19
+ * through the ordinary continuation, so a program that asks for something this
20
+ * runner lacks gets its control back and decides what to do. A command outside
21
+ * `commands` still panics — see `partialMatch`.
22
+ *
23
+ * **The injector lives here rather than at the call site.** `partialMatch`
24
+ * cannot build one because the shape of an answer is the runner's, not the
25
+ * operation's; this loop's is `(state) => [state, …]`, and writing it once here
26
+ * is the whole reason each runner supplies its own.
27
+ *
28
+ * @type {<O extends Operation, S>(commands: Commands<O>) => (o: PartialMemOperationMap<O, S>) => RunInstance<O, S>}
29
+ */
30
+ export declare const partialRun: <O extends Operation, S>(commands: Commands<O>) => (o: PartialMemOperationMap<O, S>) => RunInstance<O, S>;
@@ -5,15 +5,47 @@
5
5
  *
6
6
  * @module
7
7
  *
8
- * @import { Operation } from '../types.ts'
9
- * @import { MemOperationMap, RunInstance } from './types.ts'
8
+ * @import { Commands, Effect, MatchResult, Operation } from '../types.ts'
9
+ * @import { MemOperationMap, PartialMemOperationMap, RunInstance } from './types.ts'
10
10
  */
11
11
 
12
- import { match } from "../module.f.mjs"
12
+ import { match, partialMatch } from "../module.f.mjs"
13
+ import { notImplemented } from "../module.f.mjs"
14
+ import { error } from "../../types/result/module.f.mjs"
13
15
 
14
16
  /** @type {<O extends Operation, S>(o: MemOperationMap<O, S>) => RunInstance<O, S>} */
15
- export const run = o => state => effect => {
16
- const next = match(o)
17
+ export const run = o => _loop(match(o))
18
+
19
+ /**
20
+ * {@link run} for a runner that implements only part of `O`.
21
+ *
22
+ * A command in `commands` with no handler answers `error(notImplemented)`
23
+ * through the ordinary continuation, so a program that asks for something this
24
+ * runner lacks gets its control back and decides what to do. A command outside
25
+ * `commands` still panics — see `partialMatch`.
26
+ *
27
+ * **The injector lives here rather than at the call site.** `partialMatch`
28
+ * cannot build one because the shape of an answer is the runner's, not the
29
+ * operation's; this loop's is `(state) => [state, …]`, and writing it once here
30
+ * is the whole reason each runner supplies its own.
31
+ *
32
+ * @type {<O extends Operation, S>(commands: Commands<O>) => (o: PartialMemOperationMap<O, S>) => RunInstance<O, S>}
33
+ */
34
+ export const partialRun = commands => o => {
35
+ /** @type {(command: string) => (state: any) => readonly[any, any]} */
36
+ const onMissing = command => state => [state, error(notImplemented(command))]
37
+ return _loop(partialMatch(commands, onMissing)(o))
38
+ }
39
+
40
+ /**
41
+ * The interpreter loop both runners share: step the effect, thread the state
42
+ * through the handler's transition, resume with the command's output.
43
+ *
44
+ * @type {<O extends Operation, S>(
45
+ * next: <O1 extends O, T, E>(e: Effect<O1, T, E>) => MatchResult<O1, T, E, (state: S) => readonly[S, any]>
46
+ * ) => RunInstance<O, S>}
47
+ */
48
+ const _loop = next => state => effect => {
17
49
  let s = state
18
50
  let e = effect
19
51
  while (true) {
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * @module
5
5
  */
6
+ import type { Result } from "../../types/result/types.ts";
6
7
  import type { Effect, Operation, Pr } from "../types.ts";
7
8
  /**
8
9
  * A synchronous, state-threading operation map. An entry takes the command's
@@ -12,4 +13,12 @@ import type { Effect, Operation, Pr } from "../types.ts";
12
13
  export type MemOperationMap<O extends Operation, S> = {
13
14
  readonly [K in O[0]]: (...payload: Pr<O, K>[0]) => (state: S) => readonly [S, Pr<O, K>[1]];
14
15
  };
15
- export type RunInstance<O extends Operation, S> = (state: S) => <O1 extends O, T>(effect: Effect<O1, T>) => readonly [S, T];
16
+ /**
17
+ * A {@link MemOperationMap} a runner may leave holes in — the state-threading
18
+ * counterpart of `PartialOperationMap`. An absent handler is an operation this
19
+ * runner does not implement, answered with `error(notImplemented)`.
20
+ */
21
+ export type PartialMemOperationMap<O extends Operation, S> = {
22
+ readonly [K in O[0]]?: (...payload: Pr<O, K>[0]) => (state: S) => readonly [S, Pr<O, K>[1]];
23
+ };
24
+ export type RunInstance<O extends Operation, S> = (state: S) => <O1 extends O, T, E>(effect: Effect<O1, T, E>) => readonly [S, Result<T, E>];
@@ -5,11 +5,13 @@
5
5
  * @module
6
6
  *
7
7
  * @import { Effect, Operation, ToAsyncOperationMap } from './types.ts'
8
+ * @import { Result } from '../types/result/types.ts'
8
9
  */
9
10
  import type { Effect, Operation, ToAsyncOperationMap } from './types.ts';
11
+ import type { Result } from '../types/result/types.ts';
10
12
  /**
11
13
  * @template {Operation} O
12
14
  * @param {ToAsyncOperationMap<O>} map
13
- * @returns {<T>(effect: Effect<O, T>) => Promise<T>}
15
+ * @returns {<T, E>(effect: Effect<O, T, E>) => Promise<Result<T, E>>}
14
16
  */
15
- export declare const asyncRun: <O extends Operation>(map: ToAsyncOperationMap<O>) => <T>(effect: Effect<O, T>) => Promise<T>;
17
+ export declare const asyncRun: <O extends Operation>(map: ToAsyncOperationMap<O>) => <T, E>(effect: Effect<O, T, E>) => Promise<Result<T, E>>;