functionalscript 0.45.0 → 0.46.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 (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/rtti/validate/module.f.d.mts +81 -19
  274. package/fjs/types/rtti/validate/module.f.mjs +107 -61
  275. package/fjs/types/rtti/validate/proof.f.d.mts +13 -10
  276. package/fjs/types/rtti/validate/proof.f.mjs +186 -197
  277. package/fjs/types/sorted_set/module.f.d.mts +18 -0
  278. package/fjs/types/sorted_set/module.f.mjs +22 -0
  279. package/fjs/types/sorted_set/proof.f.d.mts +1 -0
  280. package/fjs/types/sorted_set/proof.f.mjs +16 -1
  281. package/fjs/types/uint8array/module.f.d.mts +1 -1
  282. package/fjs/types/uint8array/module.f.mjs +1 -1
  283. package/fjs/website/module.f.d.mts +3 -3
  284. package/fjs/website/module.f.mjs +4 -7
  285. package/fjs/website/proof.f.mjs +2 -1
  286. package/package.json +2 -2
  287. package/fjs/dev/package_json/module.f.d.mts +0 -39
  288. package/fjs/dev/package_json/module.f.mjs +0 -40
  289. package/fjs/dev/package_json/proof.f.d.mts +0 -6
  290. package/fjs/dev/package_json/proof.f.mjs +0 -32
  291. package/fjs/effects/eff/module.f.d.mts +0 -20
  292. package/fjs/effects/eff/module.f.mjs +0 -70
  293. package/fjs/effects/eff/proof.f.d.mts +0 -15
  294. package/fjs/effects/eff/proof.f.mjs +0 -69
  295. package/fjs/effects/eff/types.d.ts +0 -71
  296. package/fjs/types/rtti/validate/types.d.ts +0 -6
package/README.md CHANGED
@@ -5,13 +5,15 @@
5
5
  FunctionalScript is a safe, purely functional programming language and a strict subset of
6
6
  [ECMAScript](https://en.wikipedia.org/wiki/ECMAScript)/[JavaScript](https://en.wikipedia.org/wiki/JavaScript). It's inspired by
7
7
 
8
- - [JSON](https://en.wikipedia.org/wiki/JSON) and [JSON5](https://json5.org/) as subsets of JavaScript.
9
- JSON is also a subset of FunctionalScript.
8
+ - [JSON](https://en.wikipedia.org/wiki/JSON) and [JSON5](https://json5.org/) as subsets of JavaScript values.
9
+ JSON is also a subset of FunctionalScript values.
10
10
  - [asm.JS](https://en.wikipedia.org/wiki/Asm.js) (a precursor of [WebAssembly](https://en.wikipedia.org/wiki/WebAssembly)),
11
11
  as a subset of JavaScript.
12
12
  - [TypeScript](https://en.wikipedia.org/wiki/TypeScript), as a superset of JavaScript.
13
13
 
14
- [A working draft of the FunctionalScript specification](./todo/lang/README.md).
14
+ [The FunctionalScript specification](./spec/README.md) describes the language
15
+ the compiler accepts today; features not implemented yet are in
16
+ [`spec/todo/`](./spec/todo/README.md).
15
17
 
16
18
  Learn more about
17
19
 
@@ -19,6 +19,7 @@ import {
19
19
  vec,
20
20
  vec8,
21
21
  } from '../types/bit_vec/module.f.mjs'
22
+ import { assert } from '../asserts/module.f.mjs'
22
23
  import { identity } from '../types/function/module.f.mjs'
23
24
  import { max } from '../types/function/compare/module.f.mjs'
24
25
  import { encode as b128encode, decode as b128decode } from '../basen/base128/module.f.mjs'
@@ -65,7 +66,13 @@ const parsedTagEncode = ([classPc, number]) => {
65
66
  /** @type {(v: Vec) => readonly[_ParsedTag, Vec]} */
66
67
  const parsedTagDecode = v => {
67
68
  const [firstByte, rest] = pop8(v)
68
- const classPc = /** @type {_ClassPc} */(firstByte & classPcMask)
69
+ const classPc = firstByte & classPcMask
70
+ // `classPcMask` is the top three bits, so the result is one of eight values;
71
+ // the assert is what narrows `bigint` to `_ClassPc`.
72
+ assert(classPc === 0b000_00000n || classPc === 0b001_00000n
73
+ || classPc === 0b010_00000n || classPc === 0b011_00000n
74
+ || classPc === 0b100_00000n || classPc === 0b101_00000n
75
+ || classPc === 0b110_00000n || classPc === 0b111_00000n, classPc)
69
76
  const firstByteNumber = firstByte & tagNumberMask
70
77
  const [number, rest1] = firstByteNumber < tagNumberMask
71
78
  ? [firstByteNumber, rest]
@@ -49,5 +49,15 @@ export declare const proof: {
49
49
  withArc: () => void;
50
50
  };
51
51
  unknownTag: () => void;
52
+ tagClass: {
53
+ universalPrimitive: () => void;
54
+ universalConstructed: () => void;
55
+ applicationPrimitive: () => void;
56
+ applicationConstructed: () => void;
57
+ contextPrimitive: () => void;
58
+ contextConstructed: () => void;
59
+ privatePrimitive: () => void;
60
+ privateConstructed: () => void;
61
+ };
52
62
  raw: (() => void)[];
53
63
  };
@@ -296,6 +296,22 @@ export const proof = {
296
296
  // Re-encoding an UnsupportedRecord returns it unchanged (it is already the TLV bytes)
297
297
  assertEq(encode(decoded), raw, 'encode should round-trip UnsupportedRecord')
298
298
  },
299
+ // parsedTagDecode narrows the top three bits of the tag's first byte
300
+ // (class + primitive/constructed) to one of exactly eight values via an
301
+ // 8-way `||` assert. Every other test in this file only ever exercises
302
+ // the universal-primitive tag (top bits 000), so each of the other seven
303
+ // comparisons has never had a case where it's the one that turns the
304
+ // assert true — one round trip per class×P/C combination covers them all.
305
+ tagClass: {
306
+ universalPrimitive: () => check(0x02n, vec8(0x42n), empty),
307
+ universalConstructed: () => check(0x22n, vec8(0x42n), empty),
308
+ applicationPrimitive: () => check(0x42n, vec8(0x42n), empty),
309
+ applicationConstructed: () => check(0x62n, vec8(0x42n), empty),
310
+ contextPrimitive: () => check(0x82n, vec8(0x42n), empty),
311
+ contextConstructed: () => check(0xA2n, vec8(0x42n), empty),
312
+ privatePrimitive: () => check(0xC2n, vec8(0x42n), empty),
313
+ privateConstructed: () => check(0xE2n, vec8(0x42n), empty),
314
+ },
299
315
  raw: [
300
316
  () => {
301
317
  const e = encodeRaw([0x00n, vec8(0x23n)])
@@ -6,12 +6,27 @@
6
6
  * @import { Vec } from '../../types/bit_vec/types.ts'
7
7
  */
8
8
 
9
+ import { mask } from '../../types/bigint/module.f.mjs'
9
10
  import { vec8, msb, empty } from '../../types/bit_vec/module.f.mjs'
10
11
 
11
12
  const { concat, popFront } = msb
12
13
 
13
14
  const pop8 = popFront(8n)
14
15
 
16
+ /**
17
+ * The varint layout both halves below agree on, stated once: each byte carries
18
+ * seven payload bits in its low end, and its top bit is set on every byte
19
+ * except the last.
20
+ *
21
+ * `encode` and `decode` are exact inverses, so the two must agree bit for bit.
22
+ * The masks are derived from `payloadBits` rather than written as `0x7f` and
23
+ * `0x80` so that agreement is structural rather than a pair of literals a
24
+ * reader has to match up.
25
+ */
26
+ const payloadBits = 7n
27
+ const payloadMask = mask(payloadBits)
28
+ const continuationFlag = 1n << payloadBits
29
+
15
30
  /**
16
31
  * Encodes a bigint into an MSB Base128 vector.
17
32
  *
@@ -22,10 +37,12 @@ export const encode = uint => {
22
37
  /** @type {Vec} */
23
38
  let result = empty
24
39
  while (true) {
25
- const item = uint & 0x7Fn
26
- const flag = result === empty ? 0n : 0x80n
40
+ const item = uint & payloadMask
41
+ // The first byte built is the last one emitted, so it is the only one
42
+ // without the continuation flag.
43
+ const flag = result === empty ? 0n : continuationFlag
27
44
  result = concat(vec8(flag | item))(result)
28
- uint >>= 7n
45
+ uint >>= payloadBits
29
46
  if (uint === 0n) {
30
47
  return result
31
48
  }
@@ -42,8 +59,8 @@ export const decode = v => {
42
59
  let result = 0n
43
60
  while (true) {
44
61
  const [byte, rest] = pop8(v)
45
- result = (result << 7n) | (byte & 0x7Fn)
46
- if (byte < 0x80n) {
62
+ result = (result << payloadBits) | (byte & payloadMask)
63
+ if ((byte & continuationFlag) === 0n) {
47
64
  return [result, rest]
48
65
  }
49
66
  v = rest
@@ -3,10 +3,11 @@
3
3
  * {@link toData} conversion from the functional grammar.
4
4
  *
5
5
  * This module is the pure, parser-agnostic substrate: it defines the
6
- * {@link RuleSet} data form (`Rule = Variant | Sequence | TerminalRange`) and
7
- * converts a functional grammar into it. The automaton builders that consume a
8
- * {@link RuleSet} live in their own sibling modules (`fjs/bnf/ll1`,
9
- * `fjs/bnf/descent`, …), so the IR stays free of any one parser's machinery.
6
+ * {@link RuleSet} data form (`Rule = Variant | Sequence | TerminalRange |
7
+ * Repeat`) and converts a functional grammar into it. The automaton builders
8
+ * that consume a {@link RuleSet} live in their own sibling modules
9
+ * (`fjs/bnf/ll1`, `fjs/bnf/descent`, …), so the IR stays free of any one
10
+ * parser's machinery.
10
11
  *
11
12
  * See `./types.ts` for the type-level API.
12
13
  *
@@ -14,11 +15,23 @@
14
15
  *
15
16
  * @import { DataRule, Rule as FRule, Sequence as FSequence } from '../types.ts'
16
17
  * @import { StringMap } from '../../types/object/types.ts'
17
- * @import { EmptyTag, Rule, RuleSet, Sequence, Variant } from './types.ts'
18
+ * @import { StringSet } from '../../types/string_set/types.ts'
19
+ * @import { EmptyTag, Repeat, Rule, RuleSet, Sequence, Variant } from './types.ts'
18
20
  */
19
21
  import type { Rule as FRule } from '../types.ts';
20
22
  import type { StringMap } from '../../types/object/types.ts';
21
- import type { EmptyTag, Rule, RuleSet } from './types.ts';
23
+ import type { EmptyTag, Repeat, Rule, RuleSet } from './types.ts';
24
+ /**
25
+ * Whether a data rule is a {@link Repeat}.
26
+ *
27
+ * Every rule-dispatch site asks this instead of testing for a string inline, so
28
+ * the repetition rule kind has exactly one discriminator to move when the
29
+ * surrounding rule model changes.
30
+ *
31
+ * @param {Rule} rule
32
+ * @returns {rule is Repeat}
33
+ */
34
+ export declare const isRepeat: (rule: Rule) => rule is Repeat;
22
35
  export type _EmptyTagMap = StringMap<EmptyTag>;
23
36
  /**
24
37
  * Computes, for every rule in the set, whether it can match empty input, by
@@ -38,6 +51,19 @@ export type _EmptyTagMap = StringMap<EmptyTag>;
38
51
  export declare const emptyTagMap: (ruleSet: RuleSet) => _EmptyTagMap;
39
52
  export type _FRuleMap = StringMap<FRule>;
40
53
  export type _NewRule = (m: _FRuleMap) => readonly [_FRuleMap, RuleSet, Rule];
54
+ /**
55
+ * Rewrites every right-recursive 0-or-more rule of a {@link RuleSet} into a
56
+ * {@link Repeat}, and drops the rules that the rewrite orphans.
57
+ *
58
+ * The dropped rules are the recursive branch and, unless something else still
59
+ * refers to it, the empty one: both are reachable only through the variant that
60
+ * the {@link Repeat} replaces. Pruning them keeps the invariant that every rule
61
+ * of a generated set is reachable from its entry, so the serialized form holds
62
+ * no dead grammar.
63
+ *
64
+ * @type {(ruleSet: RuleSet, entry: string) => RuleSet}
65
+ */
66
+ export declare const detectRepeat: (ruleSet: RuleSet, entry: string) => RuleSet;
41
67
  /**
42
68
  * Converts a functional grammar rule into serializable BNF data and returns
43
69
  * the generated rule set with the entry rule identifier.
@@ -3,10 +3,11 @@
3
3
  * {@link toData} conversion from the functional grammar.
4
4
  *
5
5
  * This module is the pure, parser-agnostic substrate: it defines the
6
- * {@link RuleSet} data form (`Rule = Variant | Sequence | TerminalRange`) and
7
- * converts a functional grammar into it. The automaton builders that consume a
8
- * {@link RuleSet} live in their own sibling modules (`fjs/bnf/ll1`,
9
- * `fjs/bnf/descent`, …), so the IR stays free of any one parser's machinery.
6
+ * {@link RuleSet} data form (`Rule = Variant | Sequence | TerminalRange |
7
+ * Repeat`) and converts a functional grammar into it. The automaton builders
8
+ * that consume a {@link RuleSet} live in their own sibling modules
9
+ * (`fjs/bnf/ll1`, `fjs/bnf/descent`, …), so the IR stays free of any one
10
+ * parser's machinery.
10
11
  *
11
12
  * See `./types.ts` for the type-level API.
12
13
  *
@@ -14,13 +15,27 @@
14
15
  *
15
16
  * @import { DataRule, Rule as FRule, Sequence as FSequence } from '../types.ts'
16
17
  * @import { StringMap } from '../../types/object/types.ts'
17
- * @import { EmptyTag, Rule, RuleSet, Sequence, Variant } from './types.ts'
18
+ * @import { StringSet } from '../../types/string_set/types.ts'
19
+ * @import { EmptyTag, Repeat, Rule, RuleSet, Sequence, Variant } from './types.ts'
18
20
  */
19
21
 
20
22
  import { stringToCodePointList } from '../../text/utf16/module.f.mjs'
21
23
  import { map, toArray } from '../../types/list/module.f.mjs'
22
24
  import { oneEncode } from '../module.f.mjs'
23
- import { definedEntries } from '../../types/object/module.f.mjs'
25
+ import { definedEntries, definedValues } from '../../types/object/module.f.mjs'
26
+ import { contains, set } from '../../types/string_set/module.f.mjs'
27
+
28
+ /**
29
+ * Whether a data rule is a {@link Repeat}.
30
+ *
31
+ * Every rule-dispatch site asks this instead of testing for a string inline, so
32
+ * the repetition rule kind has exactly one discriminator to move when the
33
+ * surrounding rule model changes.
34
+ *
35
+ * @param {Rule} rule
36
+ * @returns {rule is Repeat}
37
+ */
38
+ export const isRepeat = rule => typeof rule === 'string'
24
39
 
25
40
  /** @typedef {StringMap<EmptyTag>} _EmptyTagMap */
26
41
 
@@ -30,6 +45,10 @@ const emptyTagOf = map => rule => {
30
45
  return undefined
31
46
  } else if (rule instanceof Array) {
32
47
  return rule.every(item => map[item] !== undefined) ? true : undefined
48
+ } else if (isRepeat(rule)) {
49
+ // Zero repetitions is a match whatever the body does, and it carries no
50
+ // tag of its own — a repetition is a sequence of items, not a choice.
51
+ return true
33
52
  } else {
34
53
  /** @type {EmptyTag} */
35
54
  let tag = undefined
@@ -176,6 +195,92 @@ const toDataAdd = map => fr => {
176
195
  return [map2, { ...set, [id]: rule }, id]
177
196
  }
178
197
 
198
+ //
199
+
200
+ const { fromEntries } = Object
201
+
202
+ /** @type {(rule: Rule) => Sequence} */
203
+ const refs = rule => {
204
+ if (typeof rule === 'number') {
205
+ return []
206
+ } else if (rule instanceof Array) {
207
+ return rule
208
+ } else if (isRepeat(rule)) {
209
+ return [rule]
210
+ } else {
211
+ return definedValues(rule)
212
+ }
213
+ }
214
+
215
+ /** @type {(ruleSet: RuleSet) => (visited: StringSet, name: string) => StringSet} */
216
+ const visit = ruleSet => (visited, name) =>
217
+ contains(name)(visited)
218
+ ? visited
219
+ : refs(ruleSet[name]).reduce(visit(ruleSet), set(name)(visited))
220
+
221
+ /**
222
+ * Every rule the entry rule can reach, itself included.
223
+ *
224
+ * @type {(ruleSet: RuleSet) => (entry: string) => StringSet}
225
+ */
226
+ const reachable = ruleSet => entry => visit(ruleSet)(null, entry)
227
+
228
+ /** @type {(rule: Rule) => boolean} */
229
+ const isNone = rule => rule instanceof Array && rule.length === 0
230
+
231
+ /**
232
+ * The {@link Repeat} — the name of the item to repeat — that `name` encodes as
233
+ * right-recursion, or `undefined` when it encodes something else.
234
+ *
235
+ * The shape recognized is exactly the unambiguous 0-or-more list: a two-branch
236
+ * variant whose branches are an empty sequence and `[item, name]`, in either
237
+ * order. Everything looser stays as it is — an operator-style tree, a separated
238
+ * list, or a 1-or-more chain all reach `name` again, but their extra items make
239
+ * the grouping a real choice rather than a list, so folding them into a flat
240
+ * sequence would discard structure no rule name is left to recover.
241
+ *
242
+ * Two further conditions keep the fold sound rather than merely plausible:
243
+ * `item` must not lead back to `name`, so `name`'s only self-reference is the
244
+ * tail one, and `item` must not match empty, since a body that can consume
245
+ * nothing has infinitely many parses of the same input.
246
+ *
247
+ * @type {(ruleSet: RuleSet, emptyTags: _EmptyTagMap) => (name: string) => Repeat | undefined}
248
+ */
249
+ const repeatOf = (ruleSet, emptyTags) => name => {
250
+ const rule = ruleSet[name]
251
+ if (typeof rule === 'number' || rule instanceof Array || isRepeat(rule)) { return undefined }
252
+ const branches = definedValues(rule)
253
+ if (branches.length !== 2) { return undefined }
254
+ const [a, b] = branches
255
+ const step = isNone(ruleSet[a]) ? b : isNone(ruleSet[b]) ? a : undefined
256
+ if (step === undefined) { return undefined }
257
+ const stepRule = ruleSet[step]
258
+ if (!(stepRule instanceof Array) || stepRule.length !== 2 || stepRule[1] !== name) { return undefined }
259
+ const [item] = stepRule
260
+ if (emptyTags[item] !== undefined || contains(name)(reachable(ruleSet)(item))) { return undefined }
261
+ return item
262
+ }
263
+
264
+ /**
265
+ * Rewrites every right-recursive 0-or-more rule of a {@link RuleSet} into a
266
+ * {@link Repeat}, and drops the rules that the rewrite orphans.
267
+ *
268
+ * The dropped rules are the recursive branch and, unless something else still
269
+ * refers to it, the empty one: both are reachable only through the variant that
270
+ * the {@link Repeat} replaces. Pruning them keeps the invariant that every rule
271
+ * of a generated set is reachable from its entry, so the serialized form holds
272
+ * no dead grammar.
273
+ *
274
+ * @type {(ruleSet: RuleSet, entry: string) => RuleSet}
275
+ */
276
+ export const detectRepeat = (ruleSet, entry) => {
277
+ const repeat = repeatOf(ruleSet, emptyTagMap(ruleSet))
278
+ /** @type {RuleSet} */
279
+ const next = fromEntries(entries(ruleSet).map(([k, v]) => [k, repeat(k) ?? v]))
280
+ const live = reachable(next)(entry)
281
+ return fromEntries(entries(next).filter(([k]) => contains(k)(live)))
282
+ }
283
+
179
284
  /**
180
285
  * Converts a functional grammar rule into serializable BNF data and returns
181
286
  * the generated rule set with the entry rule identifier.
@@ -184,5 +289,5 @@ const toDataAdd = map => fr => {
184
289
  */
185
290
  export const toData = fr => {
186
291
  const [, ruleSet, id] = toDataAdd({})(fr)
187
- return [ruleSet, id]
292
+ return [detectRepeat(ruleSet, id), id]
188
293
  }
@@ -7,6 +7,8 @@ export declare const proof: {
7
7
  rangeDecode: () => void;
8
8
  rangeEncode: () => void;
9
9
  toData: (() => void)[];
10
+ isRepeat: () => void;
11
+ detectRepeat: (() => void)[];
10
12
  variantTest: () => void;
11
13
  emptyTagMap: (() => void)[];
12
14
  example: () => void;
@@ -6,8 +6,8 @@
6
6
 
7
7
  import { identity } from '../../types/function/module.f.mjs'
8
8
  import { sort } from '../../types/object/module.f.mjs'
9
- import { oneEncode, option, range, rangeDecode, repeat0Plus, set } from '../module.f.mjs'
10
- import { emptyTagMap, toData } from './module.f.mjs'
9
+ import { none, oneEncode, option, range, rangeDecode, repeat0Plus, set } from '../module.f.mjs'
10
+ import { detectRepeat, emptyTagMap, isRepeat, toData } from './module.f.mjs'
11
11
  import { assertEq } from '../../asserts/module.f.mjs'
12
12
  import { stringify } from '../../media/json/module.f.mjs'
13
13
  import { classic, deterministic } from '../testlib.f.mjs'
@@ -88,11 +88,82 @@ export const proof = {
88
88
  if (result !== '[{"0":{"some":"1","none":"3"},"1":["2"],"2":1627390049,"3":[],"":["0","r"],"r":{"some":"","none":"3"}},"r"]') { throw result }
89
89
  },
90
90
  () => {
91
+ // The item is not nullable, so this one folds into a `repeat`, and
92
+ // the recursive and empty branches it replaced are pruned.
91
93
  const repeatRule = repeat0Plus(set(' \n\r\t'))
92
94
  const result = stringify(identity)(toData(repeatRule))
93
- if (result !== '[{"0":{" ":"1","\\n":"2","\\r":"3","\\t":"4"},"1":536870944,"2":167772170,"3":218103821,"4":150994953,"5":[],"":["0","r"],"r":{"some":"","none":"5"}},"r"]') { throw result }
95
+ const expected = '[{"0":{" ":"1","\\n":"2","\\r":"3","\\t":"4"},"1":536870944,"2":167772170,"3":218103821,"4":150994953,"r":"0"},"r"]'
96
+ assertEq(result, expected, [result, expected])
94
97
  }
95
98
  ],
99
+ isRepeat: () => {
100
+ assertEq(isRepeat('a'), true)
101
+ // Nothing else in a rule set is a string, so the four rule kinds are
102
+ // told apart by JavaScript type alone — no shape has to be probed.
103
+ assertEq(isRepeat(['a', 'b']), false)
104
+ assertEq(isRepeat({ some: 'a' }), false)
105
+ assertEq(isRepeat(oneEncode(0x41)), false)
106
+ },
107
+ detectRepeat: [
108
+ () => {
109
+ const result = stringify(identity)(toData(repeat0Plus(range('AF'))))
110
+ const expected = '[{"0":1090519110,"r":"0"},"r"]'
111
+ assertEq(result, expected, [result, expected])
112
+ },
113
+ () => {
114
+ // Nothing about the fold depends on `repeat0Plus`: a hand-written
115
+ // 0-or-more list is the same shape and folds the same way. `classic`
116
+ // spells one out as `characters`.
117
+ const [ruleSet] = toData(classic())
118
+ const repeats = Object.entries(ruleSet).filter(([, v]) => isRepeat(v))
119
+ assertEq(JSON.stringify(repeats), '[["characters","character"]]')
120
+ },
121
+ () => {
122
+ // Already folded: a `repeat` is not itself a variant to fold again.
123
+ const [ruleSet, entry] = toData(repeat0Plus(range('AF')))
124
+ assertEq(
125
+ stringify(identity)(detectRepeat(ruleSet, entry)),
126
+ stringify(identity)(ruleSet))
127
+ },
128
+ () => {
129
+ // 1-or-more: the base branch is the item, not the empty rule.
130
+ const digit = range('09')
131
+ const digits = () => ({ digit, digits: [digit, digits] })
132
+ const result = stringify(identity)(toData(digits))
133
+ const expected = '[{"0":["","digits"],"":805306425,"digits":{"digit":"","digits":"0"}},"digits"]'
134
+ assertEq(result, expected, [result, expected])
135
+ },
136
+ () => {
137
+ // A separated list repeats `[item, separator, self]`; which of the
138
+ // three items are the list's elements is not something the shape
139
+ // says, so it stays a variant.
140
+ const sep = () => ({ none, list: [range('09'), ',', sep] })
141
+ const result = stringify(identity)(toData(sep))
142
+ const expected = '[{"0":["1","2","sep"],"1":805306425,"2":["3"],"3":738197548,"":[],"sep":{"none":"","list":"0"}},"sep"]'
143
+ assertEq(result, expected, [result, expected])
144
+ },
145
+ () => {
146
+ // The tail is not the rule's only self-reference: the item leads back
147
+ // into it, so the recursion is a tree rather than a list.
148
+ const nested = () => ({ none, some: [inner, nested] })
149
+ const inner = () => ({ leaf: range('AA'), group: ['(', nested, ')'] })
150
+ const [ruleSet] = toData(nested)
151
+ assertEq(JSON.stringify(ruleSet.nested), '{"none":"","some":"0"}')
152
+ },
153
+ () => {
154
+ // A nullable item gives the same input infinitely many parses, so
155
+ // the repetition is not the unambiguous one this fold is limited to.
156
+ const [ruleSet, entry] = toData(repeat0Plus(option('a')))
157
+ assertEq(JSON.stringify(ruleSet[entry]), '{"some":"","none":"3"}')
158
+ },
159
+ () => {
160
+ // Two branches, an empty one and a terminal: the non-empty branch is
161
+ // not a sequence at all.
162
+ const result = stringify(identity)(toData({ e: '', a: range('AA') }))
163
+ const expected = '[{"0":[],"1":1090519105,"":{"e":"0","a":"1"}},""]'
164
+ assertEq(result, expected, [result, expected])
165
+ },
166
+ ],
96
167
  variantTest: () => {
97
168
  const varintRule = { a: 'a', b: 'b'}
98
169
  const result = stringify(sort)(toData(varintRule))
@@ -16,15 +16,33 @@ export type TerminalRange = number;
16
16
  export type Sequence = readonly string[];
17
17
  /** A variant of rule names. */
18
18
  export type Variant = StringMap<string>;
19
+ /**
20
+ * Zero or more repetitions of the named rule.
21
+ *
22
+ * The functional grammar has no repetition primitive — `repeat0Plus(x)` expands
23
+ * to a right-recursive variant — so this is the one rule kind `toData` derives
24
+ * rather than transcribes: it recognizes the unambiguous 0-or-more shape and
25
+ * emits this instead, which is what lets a parser backend match the body
26
+ * iteratively and produce one flat node for the whole repetition.
27
+ *
28
+ * A bare rule name keeps the four rule kinds disjoint by JavaScript type alone:
29
+ * a number is a {@link TerminalRange}, an array a {@link Sequence}, an object a
30
+ * {@link Variant}, and a string this. Nothing else in a {@link RuleSet} is a
31
+ * string, so no shape has to be probed to tell one kind from another. (The
32
+ * *functional* `DataRule` does have a string case — a Unicode literal — but
33
+ * that one never reaches here: `toData` expands it to terminals.)
34
+ */
35
+ export type Repeat = string;
19
36
  /**
20
37
  * Grammar rule definition.
21
38
  *
22
39
  * It can be one of:
23
40
  * - a tagged variant map,
24
41
  * - a sequence of referenced rule names,
25
- * - an encoded terminal range.
42
+ * - an encoded terminal range,
43
+ * - the name of a rule to repeat zero or more times.
26
44
  */
27
- export type Rule = Variant | Sequence | TerminalRange;
45
+ export type Rule = Variant | Sequence | TerminalRange | Repeat;
28
46
  /** The full grammar */
29
47
  export type RuleSet = Readonly<Record<string, Rule>>;
30
48
  /**
@@ -4,39 +4,53 @@
4
4
  * Built from the serializable IR in `fjs/bnf/data`, this is a sibling of the
5
5
  * LL(1) dispatch builder (`fjs/bnf/ll1`). It walks the grammar by recursive
6
6
  * descent and preserves per-code-point metadata, producing a metadata-aware
7
- * AST ({@link AstRuleMeta}). Nullability (which rule can match empty input) is
8
- * computed once by {@link emptyTagMap} in `fjs/bnf/data`.
7
+ * AST over leaves that carry it `Ast<CodePointMeta<T>>`, built with the
8
+ * shared layer in `fjs/bnf/matcher`. Nullability (which rule can match empty
9
+ * input) is computed once by {@link emptyTagMap} in `fjs/bnf/data`.
9
10
  *
10
11
  * The caller passes physical symbols only; the matcher synthesizes the one
11
- * logical EOF ({@link eofSymbol}) after them, so a grammar can require the end
12
- * of input with the `eof` terminal.
12
+ * logical EOF after them, so a grammar can require the end of input with the
13
+ * `eof` terminal.
13
14
  *
14
15
  * A failed result also carries a {@link DescentFailure}: the furthest position a
15
16
  * terminal was rejected at, which — unlike the result's own index — never
16
17
  * rewinds and is what diagnostics should be built from.
17
18
  *
19
+ * A `Repeat` rule is matched iteratively rather than by descending into itself
20
+ * once per item, so a repetition produces one AST node holding a flat sequence
21
+ * of the items it matched instead of the right-recursive chain its functional
22
+ * spelling would otherwise build.
23
+ *
18
24
  * See `./types.ts` for the type-level API.
19
25
  *
20
26
  * @module
21
27
  *
22
28
  * @import { TerminalRange } from '../types.ts'
23
- * @import { Rule as DataRule, Sequence } from '../data/types.ts'
29
+ * @import { Rule as DataRule, RuleSet, Sequence } from '../data/types.ts'
24
30
  * @import { Rule as FRule } from '../types.ts'
25
- * @import { AstRuleMeta, AstTag, AstSequenceMeta, CodePointMeta, DescentFailure, DescentMatch, DescentMatchResult, DescentMatchRule } from './types.ts'
31
+ * @import { List } from '../../types/list/types.ts'
32
+ * @import { Ast, AstResult, AstSequence, AstTag, Cursor } from '../matcher/types.ts'
33
+ * @import { CodePointMeta, DescentFailure, DescentMatch, DescentMatchResult, DescentMatchRule } from './types.ts'
26
34
  */
27
35
  import type { TerminalRange } from '../types.ts';
36
+ import type { RuleSet } from '../data/types.ts';
28
37
  import type { Rule as FRule } from '../types.ts';
29
- import type { AstRuleMeta, DescentMatch } from './types.ts';
30
- export type _Cursor = number;
38
+ import type { AstResult, Cursor } from '../matcher/types.ts';
39
+ import type { CodePointMeta, DescentMatch } from './types.ts';
31
40
  export type _Failure = {
32
- readonly pos: _Cursor;
41
+ readonly pos: Cursor;
33
42
  readonly expected: readonly TerminalRange[];
34
43
  };
35
- export type _Result<T> = {
36
- readonly ast: AstRuleMeta<T>;
37
- readonly success: boolean;
38
- readonly pos: _Cursor;
39
- };
44
+ export type _Result<T> = AstResult<CodePointMeta<T>, Cursor>;
45
+ /**
46
+ * Creates a recursive descent parser from an already materialized
47
+ * {@link RuleSet}, preserving metadata for each consumed code point.
48
+ *
49
+ * @template T
50
+ * @param {RuleSet} ruleSet
51
+ * @returns {DescentMatch<T>}
52
+ */
53
+ export declare const descentParserRuleSet: <T>(ruleSet: RuleSet) => DescentMatch<T>;
40
54
  /**
41
55
  * Creates a recursive descent parser that preserves metadata for each consumed
42
56
  * code point.