@thomasfosterau/effect-parse 0.4.1 → 0.5.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 (143) hide show
  1. package/README.md +37 -13
  2. package/dist/Ascii.d.ts +11 -4
  3. package/dist/Ascii.d.ts.map +1 -1
  4. package/dist/Ascii.js +7 -1
  5. package/dist/Ascii.js.map +1 -1
  6. package/dist/Binary.d.ts.map +1 -1
  7. package/dist/Binary.js +64 -35
  8. package/dist/Binary.js.map +1 -1
  9. package/dist/Bits.d.ts.map +1 -1
  10. package/dist/Bits.js +7 -4
  11. package/dist/Bits.js.map +1 -1
  12. package/dist/Compiler.d.ts +74 -2
  13. package/dist/Compiler.d.ts.map +1 -1
  14. package/dist/Compiler.js +78 -1
  15. package/dist/Compiler.js.map +1 -1
  16. package/dist/Expression.d.ts.map +1 -1
  17. package/dist/Expression.js +86 -74
  18. package/dist/Expression.js.map +1 -1
  19. package/dist/Input.d.ts +37 -4
  20. package/dist/Input.d.ts.map +1 -1
  21. package/dist/Input.js +42 -0
  22. package/dist/Input.js.map +1 -1
  23. package/dist/Nom.d.ts +5 -15
  24. package/dist/Nom.d.ts.map +1 -1
  25. package/dist/Nom.js.map +1 -1
  26. package/dist/ParseError.d.ts.map +1 -1
  27. package/dist/ParseError.js.map +1 -1
  28. package/dist/Parser.d.ts +366 -26
  29. package/dist/Parser.d.ts.map +1 -1
  30. package/dist/Parser.js +390 -19
  31. package/dist/Parser.js.map +1 -1
  32. package/dist/ParserSchema.js +1 -1
  33. package/dist/ParserStream.d.ts +3 -2
  34. package/dist/ParserStream.d.ts.map +1 -1
  35. package/dist/ParserStream.js +13 -9
  36. package/dist/ParserStream.js.map +1 -1
  37. package/dist/Syntax.d.ts +23 -5
  38. package/dist/Syntax.d.ts.map +1 -1
  39. package/dist/Syntax.js.map +1 -1
  40. package/dist/Text.d.ts.map +1 -1
  41. package/dist/Text.js +9 -9
  42. package/dist/Text.js.map +1 -1
  43. package/dist/Token.d.ts +55 -10
  44. package/dist/Token.d.ts.map +1 -1
  45. package/dist/Token.js +59 -21
  46. package/dist/Token.js.map +1 -1
  47. package/dist/internal/compiler/closure.d.ts.map +1 -1
  48. package/dist/internal/compiler/closure.js +257 -97
  49. package/dist/internal/compiler/closure.js.map +1 -1
  50. package/dist/internal/compiler/entries.d.ts +3 -1
  51. package/dist/internal/compiler/entries.d.ts.map +1 -1
  52. package/dist/internal/compiler/entries.js +3 -2
  53. package/dist/internal/compiler/entries.js.map +1 -1
  54. package/dist/internal/compiler/first.d.ts.map +1 -1
  55. package/dist/internal/compiler/first.js +7 -1
  56. package/dist/internal/compiler/first.js.map +1 -1
  57. package/dist/internal/compiler/graph.d.ts +17 -0
  58. package/dist/internal/compiler/graph.d.ts.map +1 -0
  59. package/dist/internal/compiler/graph.js +56 -0
  60. package/dist/internal/compiler/graph.js.map +1 -0
  61. package/dist/internal/compiler/jit.d.ts +5 -0
  62. package/dist/internal/compiler/jit.d.ts.map +1 -1
  63. package/dist/internal/compiler/jit.js +185 -96
  64. package/dist/internal/compiler/jit.js.map +1 -1
  65. package/dist/internal/compiler/registry.d.ts +10 -2
  66. package/dist/internal/compiler/registry.d.ts.map +1 -1
  67. package/dist/internal/compiler/registry.js.map +1 -1
  68. package/dist/internal/compiler/search.d.ts +32 -0
  69. package/dist/internal/compiler/search.d.ts.map +1 -0
  70. package/dist/internal/compiler/search.js +68 -0
  71. package/dist/internal/compiler/search.js.map +1 -0
  72. package/dist/internal/compiler/sets.d.ts.map +1 -1
  73. package/dist/internal/compiler/sets.js +1 -1
  74. package/dist/internal/compiler/sets.js.map +1 -1
  75. package/dist/internal/compiler/wasm.d.ts +8 -0
  76. package/dist/internal/compiler/wasm.d.ts.map +1 -0
  77. package/dist/internal/compiler/wasm.js +2769 -0
  78. package/dist/internal/compiler/wasm.js.map +1 -0
  79. package/dist/internal/compiler/wasmAsm.d.ts +199 -0
  80. package/dist/internal/compiler/wasmAsm.d.ts.map +1 -0
  81. package/dist/internal/compiler/wasmAsm.js +427 -0
  82. package/dist/internal/compiler/wasmAsm.js.map +1 -0
  83. package/dist/internal/entries.d.ts +3 -1
  84. package/dist/internal/entries.d.ts.map +1 -1
  85. package/dist/internal/entries.js.map +1 -1
  86. package/dist/internal/node.d.ts +58 -2
  87. package/dist/internal/node.d.ts.map +1 -1
  88. package/dist/internal/node.js +13 -3
  89. package/dist/internal/node.js.map +1 -1
  90. package/dist/internal/numbers.d.ts.map +1 -1
  91. package/dist/internal/numbers.js.map +1 -1
  92. package/dist/internal/run.d.ts +12 -0
  93. package/dist/internal/run.d.ts.map +1 -1
  94. package/dist/internal/run.js +51 -11
  95. package/dist/internal/run.js.map +1 -1
  96. package/dist/internal/stack.d.ts +6 -0
  97. package/dist/internal/stack.d.ts.map +1 -1
  98. package/dist/internal/stack.js +8 -2
  99. package/dist/internal/stack.js.map +1 -1
  100. package/dist/internal/syntax.d.ts +4 -4
  101. package/dist/internal/syntax.d.ts.map +1 -1
  102. package/dist/internal/syntax.js +18 -10
  103. package/dist/internal/syntax.js.map +1 -1
  104. package/dist/internal/text.d.ts +32 -0
  105. package/dist/internal/text.d.ts.map +1 -1
  106. package/dist/internal/text.js +68 -14
  107. package/dist/internal/text.js.map +1 -1
  108. package/dist/internal/tokens.d.ts +13 -0
  109. package/dist/internal/tokens.d.ts.map +1 -1
  110. package/dist/internal/tokens.js +59 -39
  111. package/dist/internal/tokens.js.map +1 -1
  112. package/package.json +5 -4
  113. package/src/Ascii.ts +42 -9
  114. package/src/Binary.ts +151 -71
  115. package/src/Bits.ts +12 -6
  116. package/src/Compiler.ts +101 -10
  117. package/src/Expression.ts +94 -81
  118. package/src/Input.ts +65 -6
  119. package/src/Nom.ts +15 -5
  120. package/src/ParseError.ts +3 -0
  121. package/src/Parser.ts +678 -127
  122. package/src/ParserStream.ts +37 -18
  123. package/src/Syntax.ts +60 -36
  124. package/src/Text.ts +16 -15
  125. package/src/Token.ts +138 -29
  126. package/src/internal/compiler/closure.ts +362 -135
  127. package/src/internal/compiler/entries.ts +4 -2
  128. package/src/internal/compiler/first.ts +10 -0
  129. package/src/internal/compiler/graph.ts +68 -0
  130. package/src/internal/compiler/jit.ts +284 -154
  131. package/src/internal/compiler/registry.ts +10 -2
  132. package/src/internal/compiler/search.ts +68 -0
  133. package/src/internal/compiler/sets.ts +7 -3
  134. package/src/internal/compiler/wasm.ts +3203 -0
  135. package/src/internal/compiler/wasmAsm.ts +484 -0
  136. package/src/internal/entries.ts +8 -2
  137. package/src/internal/node.ts +54 -4
  138. package/src/internal/numbers.ts +3 -1
  139. package/src/internal/run.ts +71 -12
  140. package/src/internal/stack.ts +8 -1
  141. package/src/internal/syntax.ts +39 -18
  142. package/src/internal/text.ts +97 -9
  143. package/src/internal/tokens.ts +96 -14
@@ -1 +1 @@
1
- {"version":3,"file":"Binary.js","names":["Token"],"sources":["../src/Binary.ts"],"sourcesContent":["/**\n * Parsers for binary formats: fixed-width integers and floats in either\n * byte order, and length-prefixed data (winnow's `binary` module, nom's\n * `number` and `multi::length_*` parsers).\n *\n * Integers up to 32 bits are returned as `number`, wider integers as\n * `bigint`.\n *\n * @example\n * ```ts\n * import { Binary, Parser } from \"@thomasfosterau/effect-parse\"\n *\n * // A length-prefixed (u16 big-endian) payload\n * const frame = Binary.lengthTake(Binary.beU16)\n * Parser.parse(frame, new Uint8Array([0, 2, 0xca, 0xfe])) // Uint8Array [0xca, 0xfe]\n * ```\n *\n * @since 0.1.0\n */\nimport * as Predicate from \"effect/Predicate\"\nimport type { Input, Slice, State } from \"./Input.js\"\nimport { Fail } from \"./Input.js\"\nimport type { Parser } from \"./Parser.js\"\nimport * as P from \"./Parser.js\"\nimport * as Token from \"./Token.js\"\n\nexport {\n /**\n * Runs a bit-level parser on byte input. See the `Bits` module.\n *\n * @since 0.1.0\n * @category bits\n */\n bits\n} from \"./Bits.js\"\n\n/**\n * A byte order. `\"native\"` is the byte order of the current platform.\n *\n * @since 0.1.0\n * @category models\n */\nexport type Endianness = \"big\" | \"little\" | \"native\"\n\nconst nativeLittle = /*#__PURE__*/ new Uint8Array(/*#__PURE__*/ new Uint16Array([1]).buffer)[0] === 1\n\nconst fixed = <A>(\n size: number,\n name: string,\n read: (view: DataView, offset: number) => A\n): Parser<A, never, never, Uint8Array> => {\n const expected = [`${size} byte${size === 1 ? \"\" : \"s\"}`]\n return P.make((state: State<Uint8Array>) => {\n const pos = state.pos\n const avail = state.end - pos\n if (avail < size) return state.eoi(\"Token\", expected, size - avail)\n const bytes = state.input\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n state.pos = pos + size\n return read(view, pos)\n }, name)\n}\n\nconst readU24 = (little: boolean) => (v: DataView, o: number) =>\n little\n ? v.getUint8(o) | (v.getUint8(o + 1) << 8) | (v.getUint8(o + 2) << 16)\n : (v.getUint8(o) << 16) | (v.getUint8(o + 1) << 8) | v.getUint8(o + 2)\n\nconst readI24 = (little: boolean) => {\n const u = readU24(little)\n return (v: DataView, o: number) => {\n const x = u(v, o)\n return x & 0x800000 ? x - 0x1000000 : x\n }\n}\n\nconst readU128 = (little: boolean) => (v: DataView, o: number) => {\n const a = v.getBigUint64(o, little)\n const b = v.getBigUint64(o + 8, little)\n return little ? (b << 64n) | a : (a << 64n) | b\n}\n\nconst readI128 = (little: boolean) => {\n const u = readU128(little)\n return (v: DataView, o: number) => BigInt.asIntN(128, u(v, o))\n}\n\n/**\n * An unsigned byte.\n *\n * @since 0.1.0\n * @category integers\n */\nexport const u8: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(1, \"u8\", (v, o) => v.getUint8(o))\n\n/**\n * A signed byte.\n *\n * @since 0.1.0\n * @category integers\n */\nexport const i8: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(1, \"i8\", (v, o) => v.getInt8(o))\n\n/** @since 0.1.0 @category integers */\nexport const beU16: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(2, \"beU16\", (v, o) =>\n v.getUint16(o, false)\n)\n/** @since 0.1.0 @category integers */\nexport const leU16: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(2, \"leU16\", (v, o) =>\n v.getUint16(o, true)\n)\n/** @since 0.1.0 @category integers */\nexport const beI16: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(2, \"beI16\", (v, o) =>\n v.getInt16(o, false)\n)\n/** @since 0.1.0 @category integers */\nexport const leI16: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(2, \"leI16\", (v, o) =>\n v.getInt16(o, true)\n)\n/** @since 0.1.0 @category integers */\nexport const beU24: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 3,\n \"beU24\",\n /*#__PURE__*/ readU24(false)\n)\n/** @since 0.1.0 @category integers */\nexport const leU24: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 3,\n \"leU24\",\n /*#__PURE__*/ readU24(true)\n)\n/** @since 0.1.0 @category integers */\nexport const beI24: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 3,\n \"beI24\",\n /*#__PURE__*/ readI24(false)\n)\n/** @since 0.1.0 @category integers */\nexport const leI24: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 3,\n \"leI24\",\n /*#__PURE__*/ readI24(true)\n)\n/** @since 0.1.0 @category integers */\nexport const beU32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(4, \"beU32\", (v, o) =>\n v.getUint32(o, false)\n)\n/** @since 0.1.0 @category integers */\nexport const leU32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(4, \"leU32\", (v, o) =>\n v.getUint32(o, true)\n)\n/** @since 0.1.0 @category integers */\nexport const beI32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(4, \"beI32\", (v, o) =>\n v.getInt32(o, false)\n)\n/** @since 0.1.0 @category integers */\nexport const leI32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(4, \"leI32\", (v, o) =>\n v.getInt32(o, true)\n)\n/** @since 0.1.0 @category integers */\nexport const beU64: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(8, \"beU64\", (v, o) =>\n v.getBigUint64(o, false)\n)\n/** @since 0.1.0 @category integers */\nexport const leU64: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(8, \"leU64\", (v, o) =>\n v.getBigUint64(o, true)\n)\n/** @since 0.1.0 @category integers */\nexport const beI64: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(8, \"beI64\", (v, o) =>\n v.getBigInt64(o, false)\n)\n/** @since 0.1.0 @category integers */\nexport const leI64: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(8, \"leI64\", (v, o) =>\n v.getBigInt64(o, true)\n)\n/** @since 0.1.0 @category integers */\nexport const beU128: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 16,\n \"beU128\",\n /*#__PURE__*/ readU128(false)\n)\n/** @since 0.1.0 @category integers */\nexport const leU128: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 16,\n \"leU128\",\n /*#__PURE__*/ readU128(true)\n)\n/** @since 0.1.0 @category integers */\nexport const beI128: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 16,\n \"beI128\",\n /*#__PURE__*/ readI128(false)\n)\n/** @since 0.1.0 @category integers */\nexport const leI128: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 16,\n \"leI128\",\n /*#__PURE__*/ readI128(true)\n)\n\n/** @since 0.1.0 @category floats */\nexport const beF32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(4, \"beF32\", (v, o) =>\n v.getFloat32(o, false)\n)\n/** @since 0.1.0 @category floats */\nexport const leF32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(4, \"leF32\", (v, o) =>\n v.getFloat32(o, true)\n)\n/** @since 0.1.0 @category floats */\nexport const beF64: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(8, \"beF64\", (v, o) =>\n v.getFloat64(o, false)\n)\n/** @since 0.1.0 @category floats */\nexport const leF64: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(8, \"leF64\", (v, o) =>\n v.getFloat64(o, true)\n)\n\nconst byEndian =\n <A>(big: A, little: A) =>\n (endian: Endianness): A =>\n endian === \"big\" ? big : endian === \"little\" ? little : nativeLittle ? little : big\n\n/**\n * An unsigned 16-bit integer in the given byte order (winnow's `u16`).\n *\n * @since 0.1.0\n * @category integers\n */\nexport const u16: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beU16,\n leU16\n)\n/** @since 0.1.0 @category integers */\nexport const i16: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beI16,\n leI16\n)\n/** @since 0.1.0 @category integers */\nexport const u24: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beU24,\n leU24\n)\n/** @since 0.1.0 @category integers */\nexport const i24: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beI24,\n leI24\n)\n/** @since 0.1.0 @category integers */\nexport const u32: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beU32,\n leU32\n)\n/** @since 0.1.0 @category integers */\nexport const i32: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beI32,\n leI32\n)\n/** @since 0.1.0 @category integers */\nexport const u64: (endian: Endianness) => Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beU64,\n leU64\n)\n/** @since 0.1.0 @category integers */\nexport const i64: (endian: Endianness) => Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beI64,\n leI64\n)\n/** @since 0.1.0 @category integers */\nexport const u128: (endian: Endianness) => Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beU128,\n leU128\n)\n/** @since 0.1.0 @category integers */\nexport const i128: (endian: Endianness) => Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beI128,\n leI128\n)\n/** @since 0.1.0 @category floats */\nexport const f32: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beF32,\n leF32\n)\n/** @since 0.1.0 @category floats */\nexport const f64: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beF64,\n leF64\n)\n\nconst toCount = (n: number | bigint): number => (Predicate.isBigInt(n) ? Number(n) : n)\n\n/**\n * Parses a length with `count`, then takes that many tokens (winnow's\n * `length_take`, nom's `length_data`).\n *\n * @since 0.1.0\n * @category length-prefixed\n */\nexport const lengthTake = <E, R, I extends Input = Uint8Array>(\n count: Parser<number | bigint, E, R, I>\n): Parser<Slice<I>, E, R, I> => {\n const countStep = count.step\n return P.make((state: State<I>) => {\n const n = countStep(state)\n if (n === Fail) return Fail\n return (Token.take<I>(toCount(n)).step as any)(state)\n }, \"lengthTake\")\n}\n\n/**\n * Parses a length with `count`, then applies `parser` that many times\n * (winnow's `length_repeat`, nom's `length_count`).\n *\n * @since 0.1.0\n * @category length-prefixed\n */\nexport const lengthRepeat = <E, R, I extends Input, A, E2, R2, I2 extends Input>(\n count: Parser<number | bigint, E, R, I>,\n parser: Parser<A, E2, R2, I2>\n): Parser<Array<A>, E | E2, R | R2, I & I2> =>\n P.flatMap(count, (n) => P.repeat(parser, toCount(n)) as Parser<Array<A>, E2, R2, I2>)\n\n/**\n * Parses a length with `count`, takes that many tokens, and applies\n * `parser` to them (winnow's `length_and_then`, nom's `length_value`).\n * `parser` does not need to consume the whole slice.\n *\n * @since 0.1.0\n * @category length-prefixed\n */\nexport const lengthAndThen = <E, R, I extends Input, A, E2, R2>(\n count: Parser<number | bigint, E, R, I>,\n parser: Parser<A, E2, R2, Slice<I> & Input>\n): Parser<A, E | E2, R | R2, I> =>\n P.mapParser(lengthTake(count) as Parser<Slice<I> & Input, E, R, I>, P.complete(parser))\n"],"mappings":"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"}
1
+ {"version":3,"file":"Binary.js","names":["Token"],"sources":["../src/Binary.ts"],"sourcesContent":["/**\n * Parsers for binary formats: fixed-width integers and floats in either\n * byte order, and length-prefixed data (winnow's `binary` module, nom's\n * `number` and `multi::length_*` parsers).\n *\n * Integers up to 32 bits are returned as `number`, wider integers as\n * `bigint`.\n *\n * @example\n * ```ts\n * import { Binary, Parser } from \"@thomasfosterau/effect-parse\"\n *\n * // A length-prefixed (u16 big-endian) payload\n * const frame = Binary.lengthTake(Binary.beU16)\n * Parser.parse(frame, new Uint8Array([0, 2, 0xca, 0xfe])) // Uint8Array [0xca, 0xfe]\n * ```\n *\n * @since 0.1.0\n */\nimport * as Predicate from \"effect/Predicate\"\nimport type { Input, Slice, State } from \"./Input.js\"\nimport { Fail } from \"./Input.js\"\nimport type { Parser } from \"./Parser.js\"\nimport * as P from \"./Parser.js\"\nimport * as Token from \"./Token.js\"\n\nexport {\n /**\n * Runs a bit-level parser on byte input. See the `Bits` module.\n *\n * @since 0.1.0\n * @category bits\n */\n bits\n} from \"./Bits.js\"\n\n/**\n * A byte order. `\"native\"` is the byte order of the current platform.\n *\n * @since 0.1.0\n * @category models\n */\nexport type Endianness = \"big\" | \"little\" | \"native\"\n\nconst nativeLittle = /*#__PURE__*/ new Uint8Array(/*#__PURE__*/ new Uint16Array([1]).buffer)[0] === 1\n\n/** Reads a number at an offset of a state's bytes. */\ntype Read<A> = (bytes: Uint8Array, offset: number, state: State<Uint8Array>) => A\n\n/**\n * A `DataView` of a state's bytes, for the numbers integer arithmetic can't\n * read: created once per state (whose input never changes), as one per\n * read cost most of a number's time.\n */\nconst viewOf = (state: State<Uint8Array>): DataView => {\n const b = state.input\n return (state.view ??= new DataView(b.buffer, b.byteOffset, b.byteLength))\n}\n\n/** A {@link Read} through the state's view. */\nconst viewed =\n <A>(read: (view: DataView, offset: number) => A): Read<A> =>\n (_, o, s) =>\n read(viewOf(s), o)\n\nconst fixed = <A>(size: number, name: string, read: Read<A>): Parser<A, never, never, Uint8Array> => {\n const expected = [`${size} byte${size === 1 ? \"\" : \"s\"}`]\n return P.described(\n (state: State<Uint8Array>) => {\n const pos = state.pos\n const avail = state.end - pos\n if (avail < size) return state.eoi(\"Token\", expected, size - avail)\n state.pos = pos + size\n return read(state.input, pos, state)\n },\n name,\n { _tag: \"Fixed\", size, read }\n )\n}\n\n// Integers of up to 32 bits are read from the bytes; the rest through a view\nconst readU24 =\n (little: boolean): Read<number> =>\n (b, o) =>\n little ? b[o] | (b[o + 1] << 8) | (b[o + 2] << 16) : (b[o] << 16) | (b[o + 1] << 8) | b[o + 2]\n\nconst readI24 = (little: boolean): Read<number> => {\n const u = readU24(little)\n return (b, o, s) => (u(b, o, s) << 8) >> 8\n}\n\nconst readU128 = (little: boolean): Read<bigint> =>\n viewed((v, o) => {\n const a = v.getBigUint64(o, little)\n const b = v.getBigUint64(o + 8, little)\n return little ? (b << 64n) | a : (a << 64n) | b\n })\n\nconst readI128 = (little: boolean): Read<bigint> => {\n const u = readU128(little)\n return (b, o, s) => BigInt.asIntN(128, u(b, o, s))\n}\n\n/**\n * An unsigned byte.\n *\n * @since 0.1.0\n * @category integers\n */\nexport const u8: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(1, \"u8\", (b, o) => b[o])\n\n/**\n * A signed byte.\n *\n * @since 0.1.0\n * @category integers\n */\nexport const i8: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(1, \"i8\", (b, o) => (b[o] << 24) >> 24)\n\n/** @since 0.1.0 @category integers */\nexport const beU16: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 2,\n \"beU16\",\n (b, o) => (b[o] << 8) | b[o + 1]\n)\n/** @since 0.1.0 @category integers */\nexport const leU16: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 2,\n \"leU16\",\n (b, o) => b[o] | (b[o + 1] << 8)\n)\n/** @since 0.1.0 @category integers */\nexport const beI16: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 2,\n \"beI16\",\n (b, o) => (((b[o] << 8) | b[o + 1]) << 16) >> 16\n)\n/** @since 0.1.0 @category integers */\nexport const leI16: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 2,\n \"leI16\",\n (b, o) => ((b[o] | (b[o + 1] << 8)) << 16) >> 16\n)\n/** @since 0.1.0 @category integers */\nexport const beU24: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 3,\n \"beU24\",\n /*#__PURE__*/ readU24(false)\n)\n/** @since 0.1.0 @category integers */\nexport const leU24: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 3,\n \"leU24\",\n /*#__PURE__*/ readU24(true)\n)\n/** @since 0.1.0 @category integers */\nexport const beI24: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 3,\n \"beI24\",\n /*#__PURE__*/ readI24(false)\n)\n/** @since 0.1.0 @category integers */\nexport const leI24: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 3,\n \"leI24\",\n /*#__PURE__*/ readI24(true)\n)\n/** @since 0.1.0 @category integers */\nexport const beU32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 4,\n \"beU32\",\n (b, o) => ((b[o] << 24) | (b[o + 1] << 16) | (b[o + 2] << 8) | b[o + 3]) >>> 0\n)\n/** @since 0.1.0 @category integers */\nexport const leU32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 4,\n \"leU32\",\n (b, o) => (b[o] | (b[o + 1] << 8) | (b[o + 2] << 16) | (b[o + 3] << 24)) >>> 0\n)\n/** @since 0.1.0 @category integers */\nexport const beI32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 4,\n \"beI32\",\n (b, o) => (b[o] << 24) | (b[o + 1] << 16) | (b[o + 2] << 8) | b[o + 3]\n)\n/** @since 0.1.0 @category integers */\nexport const leI32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 4,\n \"leI32\",\n (b, o) => b[o] | (b[o + 1] << 8) | (b[o + 2] << 16) | (b[o + 3] << 24)\n)\n/** @since 0.1.0 @category integers */\nexport const beU64: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 8,\n \"beU64\",\n /*#__PURE__*/ viewed((v, o) => v.getBigUint64(o, false))\n)\n/** @since 0.1.0 @category integers */\nexport const leU64: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 8,\n \"leU64\",\n /*#__PURE__*/ viewed((v, o) => v.getBigUint64(o, true))\n)\n/** @since 0.1.0 @category integers */\nexport const beI64: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 8,\n \"beI64\",\n /*#__PURE__*/ viewed((v, o) => v.getBigInt64(o, false))\n)\n/** @since 0.1.0 @category integers */\nexport const leI64: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 8,\n \"leI64\",\n /*#__PURE__*/ viewed((v, o) => v.getBigInt64(o, true))\n)\n/** @since 0.1.0 @category integers */\nexport const beU128: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 16,\n \"beU128\",\n /*#__PURE__*/ readU128(false)\n)\n/** @since 0.1.0 @category integers */\nexport const leU128: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 16,\n \"leU128\",\n /*#__PURE__*/ readU128(true)\n)\n/** @since 0.1.0 @category integers */\nexport const beI128: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 16,\n \"beI128\",\n /*#__PURE__*/ readI128(false)\n)\n/** @since 0.1.0 @category integers */\nexport const leI128: Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 16,\n \"leI128\",\n /*#__PURE__*/ readI128(true)\n)\n\n/** @since 0.1.0 @category floats */\nexport const beF32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 4,\n \"beF32\",\n /*#__PURE__*/ viewed((v, o) => v.getFloat32(o, false))\n)\n/** @since 0.1.0 @category floats */\nexport const leF32: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 4,\n \"leF32\",\n /*#__PURE__*/ viewed((v, o) => v.getFloat32(o, true))\n)\n/** @since 0.1.0 @category floats */\nexport const beF64: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 8,\n \"beF64\",\n /*#__PURE__*/ viewed((v, o) => v.getFloat64(o, false))\n)\n/** @since 0.1.0 @category floats */\nexport const leF64: Parser<number, never, never, Uint8Array> = /*#__PURE__*/ fixed(\n 8,\n \"leF64\",\n /*#__PURE__*/ viewed((v, o) => v.getFloat64(o, true))\n)\n\nconst byEndian =\n <A>(big: A, little: A) =>\n (endian: Endianness): A =>\n endian === \"big\" ? big : endian === \"little\" ? little : nativeLittle ? little : big\n\n/**\n * An unsigned 16-bit integer in the given byte order (winnow's `u16`).\n *\n * @since 0.1.0\n * @category integers\n */\nexport const u16: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beU16,\n leU16\n)\n/** @since 0.1.0 @category integers */\nexport const i16: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beI16,\n leI16\n)\n/** @since 0.1.0 @category integers */\nexport const u24: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beU24,\n leU24\n)\n/** @since 0.1.0 @category integers */\nexport const i24: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beI24,\n leI24\n)\n/** @since 0.1.0 @category integers */\nexport const u32: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beU32,\n leU32\n)\n/** @since 0.1.0 @category integers */\nexport const i32: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beI32,\n leI32\n)\n/** @since 0.1.0 @category integers */\nexport const u64: (endian: Endianness) => Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beU64,\n leU64\n)\n/** @since 0.1.0 @category integers */\nexport const i64: (endian: Endianness) => Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beI64,\n leI64\n)\n/** @since 0.1.0 @category integers */\nexport const u128: (endian: Endianness) => Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beU128,\n leU128\n)\n/** @since 0.1.0 @category integers */\nexport const i128: (endian: Endianness) => Parser<bigint, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beI128,\n leI128\n)\n/** @since 0.1.0 @category floats */\nexport const f32: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beF32,\n leF32\n)\n/** @since 0.1.0 @category floats */\nexport const f64: (endian: Endianness) => Parser<number, never, never, Uint8Array> = /*#__PURE__*/ byEndian(\n beF64,\n leF64\n)\n\nconst toCount = (n: number | bigint): number => (Predicate.isBigInt(n) ? Number(n) : n)\n\n/** How many counts {@link byCount} keeps the parsers of. */\nconst CountCache = 256\n\n/**\n * `build`, keeping the parsers it built for the first {@link CountCache}\n * counts seen: length-prefixed data repeats a few lengths, and building a\n * parser per value cost several times the parse.\n */\nconst byCount = <A>(build: (n: number) => A): ((n: number | bigint) => A) => {\n const built = new Map<number, A>()\n return (n) => {\n const count = toCount(n)\n let a = built.get(count)\n if (a === undefined) {\n a = build(count)\n if (built.size < CountCache) built.set(count, a)\n }\n return a\n }\n}\n\n/**\n * Parses a length with `count`, then takes that many tokens (winnow's\n * `length_take`, nom's `length_data`).\n *\n * @since 0.1.0\n * @category length-prefixed\n */\nexport const lengthTake = <E, R, I extends Input = Uint8Array>(\n count: Parser<number | bigint, E, R, I>\n): Parser<Slice<I>, E, R, I> => {\n const take = byCount((n) => Token.take<I>(n).step)\n // The count compiles with the grammar: the step is built from its (see `Parser.combinator`)\n return P.combinator(\n [count],\n ([countStep]) =>\n (state: State<I>) => {\n // SAFETY: the count parser's step, interpreted or compiled, returns its output (a number or bigint) or `Fail`\n const n = countStep(state) as number | bigint | Fail\n if (n === Fail) return Fail\n return take(n)(state)\n },\n \"lengthTake\"\n )\n}\n\n/**\n * Parses a length with `count`, then applies `parser` that many times\n * (winnow's `length_repeat`, nom's `length_count`).\n *\n * @since 0.1.0\n * @category length-prefixed\n */\nexport const lengthRepeat = <E, R, I extends Input, A, E2, R2, I2 extends Input>(\n count: Parser<number | bigint, E, R, I>,\n parser: Parser<A, E2, R2, I2>\n): Parser<Array<A>, E | E2, R | R2, I & I2> =>\n P.flatMap(\n count,\n byCount((n) => P.repeat(parser, n))\n )\n\n/**\n * Parses a length with `count`, takes that many tokens, and applies\n * `parser` to them (winnow's `length_and_then`, nom's `length_value`).\n * `parser` does not need to consume the whole slice.\n *\n * @since 0.1.0\n * @category length-prefixed\n */\nexport const lengthAndThen = <E, R, I extends Input, A, E2, R2>(\n count: Parser<number | bigint, E, R, I>,\n parser: Parser<A, E2, R2, Slice<I> & Input>\n): Parser<A, E | E2, R | R2, I> =>\n // SAFETY: a slice of an input is itself an input (a string, a `Uint8Array` or an array), so `Slice<I>` is an `Input`\n P.mapParser(lengthTake(count) as Parser<Slice<I> & Input, E, R, I>, P.complete(parser))\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Bits.d.ts","names":[],"sources":["../src/Bits.ts"],"mappings":";cA2Bc;;;;;;;;iBASG,iBAAiB;YACtB;;;;;;;;;qBAyDC,OAAQ,GAAG,GAAG,GAAG,MAAM,OAAO,GAAG,GAAG,GAAG,cAAY,OAAO,GAAG,GAAG,GAAG;;;;;;;;qBAYnE,QAAS,GAAG,GAAG,GAAG,MAAM,OAAO,GAAG,GAAG,GAAG,gBAAc,OAAO,GAAG,GAAG,GAAG;;;;;;;;qBAyBtE,OAAQ,kBAAgB,6BAA6B;;;;;;;qBAgBrD,UAAW,kBAAgB,6BAA6B;;;;;;;;qBAuBxD,UAAW,iBAAiB,kBAAgB,6BAA6B;;;;;;;qBAqBzE,MAAM,8BAA8B"}
1
+ {"version":3,"file":"Bits.d.ts","names":[],"sources":["../src/Bits.ts"],"mappings":";cA2Bc;;;;;;;;iBASG,iBAAiB;YACtB;;;;;;;;;qBAyDC,OAAQ,GAAG,GAAG,GAAG,MAAM,OAAO,GAAG,GAAG,GAAG,cAAY,OAAO,GAAG,GAAG,GAAG;;;;;;;;qBAYnE,QAAS,GAAG,GAAG,GAAG,MAAM,OAAO,GAAG,GAAG,GAAG,gBAAc,OAAO,GAAG,GAAG,GAAG;;;;;;;;qBA+BtE,OAAQ,kBAAgB,6BAA6B;;;;;;;qBAgBrD,UAAW,kBAAgB,6BAA6B;;;;;;;;qBAuBxD,UAAW,iBAAiB,kBAAgB,6BAA6B;;;;;;;qBAqBzE,MAAM,8BAA8B"}
package/dist/Bits.js CHANGED
@@ -60,10 +60,13 @@ const readBits = (state, count) => {
60
60
  const input = state.input;
61
61
  let pos = state.pos;
62
62
  let value = 0;
63
- for (let i = 0; i < count; i++) {
64
- const byte = input[pos >>> 3];
65
- value = value * 2 + (byte >>> 7 - (pos & 7) & 1);
66
- pos++;
63
+ let left = count;
64
+ while (left > 0) {
65
+ const avail = 8 - (pos & 7);
66
+ const n = left < avail ? left : avail;
67
+ value = value * (1 << n) + (input[pos >>> 3] >>> avail - n & (1 << n) - 1);
68
+ pos += n;
69
+ left -= n;
67
70
  }
68
71
  state.pos = pos;
69
72
  return value;
package/dist/Bits.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Bits.js","names":[],"sources":["../src/Bits.ts"],"sourcesContent":["/**\n * Bit-level parsing (winnow's `binary::bits`, nom's `bits` module).\n *\n * Bit parsers run inside {@link bits}, which switches a byte parser into\n * bit mode. Bits are read most-significant first. When `bits` finishes, any\n * remaining bits of a partly consumed byte are skipped.\n *\n * Inside `bits`, offsets count bits, so the general combinators (`alt`,\n * `repeat`, `opt`, ...) backtrack at bit granularity.\n *\n * @example\n * ```ts\n * import { Binary, Bits, Parser } from \"@thomasfosterau/effect-parse\"\n *\n * // An IPv4 header starts with a 4-bit version and a 4-bit header length\n * const versionAndLength = Bits.bits(Parser.seq(Bits.take(4), Bits.take(4)))\n *\n * Parser.parse(versionAndLength, new Uint8Array([0x45])) // Result.succeed([4, 5])\n * ```\n *\n * @since 0.1.0\n */\nimport type { State } from \"./Input.js\"\nimport { Fail, Failure } from \"./Input.js\"\nimport type { Parser } from \"./Parser.js\"\nimport { make } from \"./Parser.js\"\n\ndeclare const BitInputBrand: unique symbol\n\n/**\n * The input type of bit-level parsers. A `Parser<A, E, R, BitInput>` can\n * only be run inside {@link bits}.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface BitInput extends ReadonlyArray<never> {\n readonly [BitInputBrand]: true\n}\n\nconst scale = (f: Failure, factor: number): Failure =>\n new Failure(\n factor < 1 ? Math.floor(f.offset * factor) : f.offset * factor,\n f.kind,\n f.expected,\n f.context,\n f.hasCause,\n f.cause,\n f.message,\n factor < 1 ? Math.ceil(f.needed * factor) : f.needed * factor\n )\n\n/**\n * Runs `step` with offsets measured in different units (bits vs bytes),\n * converting failure offsets back to the outer units afterwards.\n */\nconst inUnits = <A>(state: State<any>, factor: number, step: (state: State<any>) => A | Fail): A | Fail => {\n const end = state.end\n const deepest = state.deepest\n state.deepest = undefined\n state.pos = factor > 1 ? state.pos * factor : Math.ceil(state.pos * factor)\n state.end = end * factor\n const a = step(state)\n state.end = end\n const inner = state.deepest\n state.deepest = deepest\n if (a === Fail) {\n state.pos = factor > 1 ? Math.floor(state.pos / factor) : state.pos / factor\n const f = state.failure\n state.failure = scale(f, 1 / factor)\n // A committed failure keeps only the failures recorded after the commit\n // (see `Parser.cut`), so none from before these units\n if (state.mode === \"Cut\") state.deepest = undefined\n if (inner !== undefined) {\n const d = inner === f ? state.failure : scale(inner, 1 / factor)\n if (state.deepest === undefined || d.offset >= state.deepest.offset) state.deepest = d\n }\n return Fail\n }\n state.pos = factor > 1 ? Math.ceil(state.pos / factor) : state.pos / factor\n if (inner !== undefined) {\n const d = scale(inner, 1 / factor)\n if (deepest === undefined || d.offset >= deepest.offset) state.deepest = d\n }\n return a\n}\n\n/**\n * Runs a bit-level parser on byte input (winnow's and nom's `bits`). After\n * success, the input advances to the next byte boundary.\n *\n * @since 0.1.0\n * @category combinators\n */\nexport const bits = <A, E, R>(self: Parser<A, E, R, BitInput>): Parser<A, E, R, Uint8Array> => {\n const step = self.step as unknown as (state: State<any>) => A | Fail\n return make((state) => inUnits(state, 8, step), \"bits\")\n}\n\n/**\n * Runs a byte-level parser from within a bit-level parser (winnow's and\n * nom's `bytes`). The partly consumed byte, if any, is skipped first.\n *\n * @since 0.1.0\n * @category combinators\n */\nexport const bytes = <A, E, R>(self: Parser<A, E, R, Uint8Array>): Parser<A, E, R, BitInput> => {\n const step = self.step as (state: State<any>) => A | Fail\n return make((state: State<any>) => inUnits(state, 1 / 8, step), \"bytes\")\n}\n\nconst readBits = (state: State<any>, count: number): number => {\n const input = state.input as Uint8Array\n let pos = state.pos\n let value = 0\n for (let i = 0; i < count; i++) {\n const byte = input[pos >>> 3]\n value = value * 2 + ((byte >>> (7 - (pos & 7))) & 1)\n pos++\n }\n state.pos = pos\n return value\n}\n\n/**\n * Takes `count` bits (at most 53) as an unsigned number (winnow's and nom's\n * bit-level `take`).\n *\n * @since 0.1.0\n * @category parsers\n */\nexport const take = (count: number): Parser<number, never, never, BitInput> => {\n if (count > 53) throw new RangeError(\"Bits.take: use Bits.takeBig for more than 53 bits\")\n const expected = [`${count} bits`]\n return make((state: State<any>) => {\n const avail = state.end - state.pos\n if (avail < count) return state.eoi(\"Bits\", expected, count - avail)\n return readBits(state, count)\n }, \"take\")\n}\n\n/**\n * Takes `count` bits as an unsigned `bigint`.\n *\n * @since 0.1.0\n * @category parsers\n */\nexport const takeBig = (count: number): Parser<bigint, never, never, BitInput> => {\n const expected = [`${count} bits`]\n return make((state: State<any>) => {\n const avail = state.end - state.pos\n if (avail < count) return state.eoi(\"Bits\", expected, count - avail)\n let value = 0n\n let remaining = count\n while (remaining > 0) {\n const n = Math.min(remaining, 32)\n value = (value << BigInt(n)) | BigInt(readBits(state, n))\n remaining -= n\n }\n return value\n }, \"takeBig\")\n}\n\n/**\n * Matches `count` bits equal to `pattern` (winnow's `pattern`, nom's bit\n * `tag`).\n *\n * @since 0.1.0\n * @category parsers\n */\nexport const pattern = (pattern: number, count: number): Parser<number, never, never, BitInput> => {\n const expected = [`bit pattern ${pattern.toString(2).padStart(count, \"0\")}`]\n return make((state: State<any>) => {\n const start = state.pos\n const avail = state.end - start\n if (avail < count) return state.eoi(\"Bits\", expected, count - avail)\n const value = readBits(state, count)\n if (value !== pattern) {\n state.rewind(start)\n return state.backtrack(\"Bits\", expected)\n }\n return value\n }, \"pattern\")\n}\n\n/**\n * Takes one bit as a boolean (winnow's and nom's `bool`).\n *\n * @since 0.1.0\n * @category parsers\n */\nexport const bool: Parser<boolean, never, never, BitInput> = /*#__PURE__*/ make((state: State<any>) => {\n if (state.pos >= state.end) return state.eoi(\"Bits\", [\"1 bit\"], 1)\n return readBits(state, 1) === 1\n}, \"bool\")\n"],"mappings":"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"}
1
+ {"version":3,"file":"Bits.js","names":[],"sources":["../src/Bits.ts"],"sourcesContent":["/**\n * Bit-level parsing (winnow's `binary::bits`, nom's `bits` module).\n *\n * Bit parsers run inside {@link bits}, which switches a byte parser into\n * bit mode. Bits are read most-significant first. When `bits` finishes, any\n * remaining bits of a partly consumed byte are skipped.\n *\n * Inside `bits`, offsets count bits, so the general combinators (`alt`,\n * `repeat`, `opt`, ...) backtrack at bit granularity.\n *\n * @example\n * ```ts\n * import { Binary, Bits, Parser } from \"@thomasfosterau/effect-parse\"\n *\n * // An IPv4 header starts with a 4-bit version and a 4-bit header length\n * const versionAndLength = Bits.bits(Parser.seq(Bits.take(4), Bits.take(4)))\n *\n * Parser.parse(versionAndLength, new Uint8Array([0x45])) // Result.succeed([4, 5])\n * ```\n *\n * @since 0.1.0\n */\nimport type { State } from \"./Input.js\"\nimport { Fail, Failure } from \"./Input.js\"\nimport type { Parser } from \"./Parser.js\"\nimport { make } from \"./Parser.js\"\n\ndeclare const BitInputBrand: unique symbol\n\n/**\n * The input type of bit-level parsers. A `Parser<A, E, R, BitInput>` can\n * only be run inside {@link bits}.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface BitInput extends ReadonlyArray<never> {\n readonly [BitInputBrand]: true\n}\n\nconst scale = (f: Failure, factor: number): Failure =>\n new Failure(\n factor < 1 ? Math.floor(f.offset * factor) : f.offset * factor,\n f.kind,\n f.expected,\n f.context,\n f.hasCause,\n f.cause,\n f.message,\n factor < 1 ? Math.ceil(f.needed * factor) : f.needed * factor\n )\n\n/**\n * Runs `step` with offsets measured in different units (bits vs bytes),\n * converting failure offsets back to the outer units afterwards.\n */\nconst inUnits = <A>(state: State<any>, factor: number, step: (state: State<any>) => A | Fail): A | Fail => {\n const end = state.end\n const deepest = state.deepest\n state.deepest = undefined\n state.pos = factor > 1 ? state.pos * factor : Math.ceil(state.pos * factor)\n state.end = end * factor\n const a = step(state)\n state.end = end\n const inner = state.deepest\n state.deepest = deepest\n if (a === Fail) {\n state.pos = factor > 1 ? Math.floor(state.pos / factor) : state.pos / factor\n const f = state.failure\n state.failure = scale(f, 1 / factor)\n // A committed failure keeps only the failures recorded after the commit\n // (see `Parser.cut`), so none from before these units\n if (state.mode === \"Cut\") state.deepest = undefined\n if (inner !== undefined) {\n const d = inner === f ? state.failure : scale(inner, 1 / factor)\n if (state.deepest === undefined || d.offset >= state.deepest.offset) state.deepest = d\n }\n return Fail\n }\n state.pos = factor > 1 ? Math.ceil(state.pos / factor) : state.pos / factor\n if (inner !== undefined) {\n const d = scale(inner, 1 / factor)\n if (deepest === undefined || d.offset >= deepest.offset) state.deepest = d\n }\n return a\n}\n\n/**\n * Runs a bit-level parser on byte input (winnow's and nom's `bits`). After\n * success, the input advances to the next byte boundary.\n *\n * @since 0.1.0\n * @category combinators\n */\nexport const bits = <A, E, R>(self: Parser<A, E, R, BitInput>): Parser<A, E, R, Uint8Array> => {\n const step = self.step\n return make((state) => inUnits(state, 8, step), \"bits\")\n}\n\n/**\n * Runs a byte-level parser from within a bit-level parser (winnow's and\n * nom's `bytes`). The partly consumed byte, if any, is skipped first.\n *\n * @since 0.1.0\n * @category combinators\n */\nexport const bytes = <A, E, R>(self: Parser<A, E, R, Uint8Array>): Parser<A, E, R, BitInput> => {\n const step = self.step\n return make((state: State<any>) => inUnits(state, 1 / 8, step), \"bytes\")\n}\n\nconst readBits = (state: State<any>, count: number): number => {\n // SAFETY: bit-level parsers run inside `bits`, on the `Uint8Array` it was given (`BitInput` only re-indexes it in bits)\n const input = state.input as Uint8Array\n let pos = state.pos\n let value = 0\n let left = count\n // As many bits as the current byte holds at once, not one at a time\n while (left > 0) {\n const avail = 8 - (pos & 7)\n const n = left < avail ? left : avail\n // Multiplying, not shifting: the value can have up to 53 bits\n value = value * (1 << n) + ((input[pos >>> 3] >>> (avail - n)) & ((1 << n) - 1))\n pos += n\n left -= n\n }\n state.pos = pos\n return value\n}\n\n/**\n * Takes `count` bits (at most 53) as an unsigned number (winnow's and nom's\n * bit-level `take`).\n *\n * @since 0.1.0\n * @category parsers\n */\nexport const take = (count: number): Parser<number, never, never, BitInput> => {\n if (count > 53) throw new RangeError(\"Bits.take: use Bits.takeBig for more than 53 bits\")\n const expected = [`${count} bits`]\n return make((state: State<any>) => {\n const avail = state.end - state.pos\n if (avail < count) return state.eoi(\"Bits\", expected, count - avail)\n return readBits(state, count)\n }, \"take\")\n}\n\n/**\n * Takes `count` bits as an unsigned `bigint`.\n *\n * @since 0.1.0\n * @category parsers\n */\nexport const takeBig = (count: number): Parser<bigint, never, never, BitInput> => {\n const expected = [`${count} bits`]\n return make((state: State<any>) => {\n const avail = state.end - state.pos\n if (avail < count) return state.eoi(\"Bits\", expected, count - avail)\n let value = 0n\n let remaining = count\n while (remaining > 0) {\n const n = Math.min(remaining, 32)\n value = (value << BigInt(n)) | BigInt(readBits(state, n))\n remaining -= n\n }\n return value\n }, \"takeBig\")\n}\n\n/**\n * Matches `count` bits equal to `pattern` (winnow's `pattern`, nom's bit\n * `tag`).\n *\n * @since 0.1.0\n * @category parsers\n */\nexport const pattern = (pattern: number, count: number): Parser<number, never, never, BitInput> => {\n const expected = [`bit pattern ${pattern.toString(2).padStart(count, \"0\")}`]\n return make((state: State<any>) => {\n const start = state.pos\n const avail = state.end - start\n if (avail < count) return state.eoi(\"Bits\", expected, count - avail)\n const value = readBits(state, count)\n if (value !== pattern) {\n state.rewind(start)\n return state.backtrack(\"Bits\", expected)\n }\n return value\n }, \"pattern\")\n}\n\n/**\n * Takes one bit as a boolean (winnow's and nom's `bool`).\n *\n * @since 0.1.0\n * @category parsers\n */\nexport const bool: Parser<boolean, never, never, BitInput> = /*#__PURE__*/ make((state: State<any>) => {\n if (state.pos >= state.end) return state.eoi(\"Bits\", [\"1 bit\"], 1)\n return readBits(state, 1) === 1\n}, \"bool\")\n"],"mappings":"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"}
@@ -1,5 +1,34 @@
1
- import { Input } from "./Input.js";
2
- import { Parser } from "./Parser.js";
1
+ import { Fail, Input, State } from "./Input.js";
2
+ import { Parser, RunOptions } from "./Parser.js";
3
+ /**
4
+ * Compiles a parser with the WebAssembly compiler. Returns the same parser.
5
+ *
6
+ * The input is copied into WebAssembly memory and scanned there, by code
7
+ * generated from the grammar; a JavaScript function generated with
8
+ * `new Function` then builds the value from what the scan recorded, with
9
+ * the same callbacks and the same objects as the JIT. Parts of the grammar
10
+ * with no WebAssembly form (such as `Parser.make`, `flatMap`, or `filter`
11
+ * on a value) run their JIT-compiled code from inside the scan.
12
+ *
13
+ * It uses the JIT (see {@link jit}) for array input, for the streaming build
14
+ * of `Parser.parsePartial` and `ParserStream`, and where `WebAssembly` or
15
+ * `new Function` is unavailable: a Content Security Policy needs both
16
+ * `'wasm-unsafe-eval'` and `'unsafe-eval'` for it. Short strings with the
17
+ * same characters may be returned as one string, which no program can tell
18
+ * apart from two.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { Ascii, Compiler, Parser, Token } from "@thomasfosterau/effect-parse"
23
+ *
24
+ * const list = Compiler.wasm(Parser.separated(Ascii.decInt, Token.literal(",")))
25
+ * Parser.parse(list, "1,2,3") // Result.succeed([1, 2, 3])
26
+ * ```
27
+ *
28
+ * @since 0.5.0
29
+ * @category compilation
30
+ */
31
+ export declare const wasm: <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>;
3
32
  /**
4
33
  * Compiles a parser with the JIT: generated code where `new Function` is
5
34
  * allowed, otherwise specialized closures (see {@link closure}). Returns the
@@ -34,4 +63,47 @@ export declare const jit: <A, E, R, I extends Input>(self: Parser<A, E, R, I>) =
34
63
  * @category compilation
35
64
  */
36
65
  export declare const closure: <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>;
66
+ /**
67
+ * Prepares a parser for running many times on states you own, as
68
+ * `Parser.run` does: for drivers that make one small run per token, such as
69
+ * a lexer over a buffer. `Parser.run` looks the parser's compiled form up
70
+ * on every run, which costs about a quarter of a small token's time; the
71
+ * function returned here looks it up once (again only when the input kind
72
+ * changes, or between complete and partial states) and calls the compiled
73
+ * code directly.
74
+ *
75
+ * It returns exactly what `Parser.run(self, state, options)` returns, and
76
+ * leaves the state as it would: the output with the cursor where the
77
+ * parser stopped, or `Fail` with the interpreter's failure (or, with
78
+ * `diagnostics: false`, only the mode). Compile the parser first with
79
+ * {@link jit} or {@link closure}; a parser that isn't compiled runs
80
+ * interpreted. The compiled form is looked up on the first run, so compile
81
+ * the parser before using the runner: compiling it again later doesn't
82
+ * reach a runner that has already run.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * import { Ascii, Compiler, Input, Parser, Token } from "@thomasfosterau/effect-parse"
87
+ *
88
+ * const token = Compiler.jit(Parser.preceded(Ascii.space0, Parser.alt(Ascii.alpha1, Token.oneOf("+-"))))
89
+ * const next = Compiler.runner(token)
90
+ *
91
+ * const tokens = (text: string): Array<string> => {
92
+ * const state = new Input.State(text)
93
+ * const out: Array<string> = []
94
+ * while (state.pos < state.end) {
95
+ * const t = next(state.reset(state.pos))
96
+ * if (t === Input.Fail) break
97
+ * out.push(t)
98
+ * }
99
+ * return out
100
+ * }
101
+ *
102
+ * tokens("a + b") // ["a", "+", "b"]
103
+ * ```
104
+ *
105
+ * @since 0.5.0
106
+ * @category running
107
+ */
108
+ export declare const runner: <A, E, R, I extends Input>(self: Parser<A, E, R, I>, options?: RunOptions) => ((state: State<I>) => A | Fail);
37
109
  //# sourceMappingURL=Compiler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Compiler.d.ts","names":[],"sources":["../src/Compiler.ts"],"mappings":";;;;;;;;;;;;;;;;;;qBAyEa,MAAO,GAAG,GAAG,GAAG,UAAU,OAAO,MAAM,OAAO,GAAG,GAAG,GAAG,OAAK,OAAO,GAAG,GAAG,GAAG;;;;;;;;;;;;;;;;;qBAqB5E,UAAW,GAAG,GAAG,GAAG,UAAU,OAAO,MAAM,OAAO,GAAG,GAAG,GAAG,OAAK,OAAO,GAAG,GAAG,GAAG"}
1
+ {"version":3,"file":"Compiler.d.ts","names":[],"sources":["../src/Compiler.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAgGa,OAAQ,GAAG,GAAG,GAAG,UAAU,OAAO,MAAM,OAAO,GAAG,GAAG,GAAG,OAAK,OAAO,GAAG,GAAG,GAAG;;;;;;;;;;;;;;;;;qBAqB7E,MAAO,GAAG,GAAG,GAAG,UAAU,OAAO,MAAM,OAAO,GAAG,GAAG,GAAG,OAAK,OAAO,GAAG,GAAG,GAAG;;;;;;;;;;;;;;;;;qBAqB5E,UAAW,GAAG,GAAG,GAAG,UAAU,OAAO,MAAM,OAAO,GAAG,GAAG,GAAG,OAAK,OAAO,GAAG,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA+ChF,SAAU,GAAG,GAAG,GAAG,UAAU,OACxC,MAAM,OAAO,GAAG,GAAG,GAAG,IACtB,UAAU,iBACP,OAAO,MAAM,OAAO,IAAI"}
package/dist/Compiler.js CHANGED
@@ -1,8 +1,42 @@
1
1
  import { backend } from "./internal/compiler/closure.js";
2
2
  import { backend as backend$1 } from "./internal/compiler/jit.js";
3
3
  import { register } from "./internal/compiler/registry.js";
4
+ import { backend as backend$2 } from "./internal/compiler/wasm.js";
5
+ import { prepare } from "./internal/run.js";
4
6
  // src/Compiler.ts
5
7
  /**
8
+ * Compiles a parser with the WebAssembly compiler. Returns the same parser.
9
+ *
10
+ * The input is copied into WebAssembly memory and scanned there, by code
11
+ * generated from the grammar; a JavaScript function generated with
12
+ * `new Function` then builds the value from what the scan recorded, with
13
+ * the same callbacks and the same objects as the JIT. Parts of the grammar
14
+ * with no WebAssembly form (such as `Parser.make`, `flatMap`, or `filter`
15
+ * on a value) run their JIT-compiled code from inside the scan.
16
+ *
17
+ * It uses the JIT (see {@link jit}) for array input, for the streaming build
18
+ * of `Parser.parsePartial` and `ParserStream`, and where `WebAssembly` or
19
+ * `new Function` is unavailable: a Content Security Policy needs both
20
+ * `'wasm-unsafe-eval'` and `'unsafe-eval'` for it. Short strings with the
21
+ * same characters may be returned as one string, which no program can tell
22
+ * apart from two.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { Ascii, Compiler, Parser, Token } from "@thomasfosterau/effect-parse"
27
+ *
28
+ * const list = Compiler.wasm(Parser.separated(Ascii.decInt, Token.literal(",")))
29
+ * Parser.parse(list, "1,2,3") // Result.succeed([1, 2, 3])
30
+ * ```
31
+ *
32
+ * @since 0.5.0
33
+ * @category compilation
34
+ */
35
+ const wasm = (self) => {
36
+ register(self, backend$2);
37
+ return self;
38
+ };
39
+ /**
6
40
  * Compiles a parser with the JIT: generated code where `new Function` is
7
41
  * allowed, otherwise specialized closures (see {@link closure}). Returns the
8
42
  * same parser.
@@ -42,6 +76,49 @@ const closure = (self) => {
42
76
  register(self, backend);
43
77
  return self;
44
78
  };
45
- export { closure, jit };
79
+ /**
80
+ * Prepares a parser for running many times on states you own, as
81
+ * `Parser.run` does: for drivers that make one small run per token, such as
82
+ * a lexer over a buffer. `Parser.run` looks the parser's compiled form up
83
+ * on every run, which costs about a quarter of a small token's time; the
84
+ * function returned here looks it up once (again only when the input kind
85
+ * changes, or between complete and partial states) and calls the compiled
86
+ * code directly.
87
+ *
88
+ * It returns exactly what `Parser.run(self, state, options)` returns, and
89
+ * leaves the state as it would: the output with the cursor where the
90
+ * parser stopped, or `Fail` with the interpreter's failure (or, with
91
+ * `diagnostics: false`, only the mode). Compile the parser first with
92
+ * {@link jit} or {@link closure}; a parser that isn't compiled runs
93
+ * interpreted. The compiled form is looked up on the first run, so compile
94
+ * the parser before using the runner: compiling it again later doesn't
95
+ * reach a runner that has already run.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * import { Ascii, Compiler, Input, Parser, Token } from "@thomasfosterau/effect-parse"
100
+ *
101
+ * const token = Compiler.jit(Parser.preceded(Ascii.space0, Parser.alt(Ascii.alpha1, Token.oneOf("+-"))))
102
+ * const next = Compiler.runner(token)
103
+ *
104
+ * const tokens = (text: string): Array<string> => {
105
+ * const state = new Input.State(text)
106
+ * const out: Array<string> = []
107
+ * while (state.pos < state.end) {
108
+ * const t = next(state.reset(state.pos))
109
+ * if (t === Input.Fail) break
110
+ * out.push(t)
111
+ * }
112
+ * return out
113
+ * }
114
+ *
115
+ * tokens("a + b") // ["a", "+", "b"]
116
+ * ```
117
+ *
118
+ * @since 0.5.0
119
+ * @category running
120
+ */
121
+ const runner = (self, options) => prepare(self, self.step, options?.diagnostics !== false);
122
+ export { closure, jit, runner, wasm };
46
123
 
47
124
  //# sourceMappingURL=Compiler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Compiler.js","names":["jitBackend","closureBackend"],"sources":["../src/Compiler.ts"],"sourcesContent":["/**\n * Compiles parsers into fused, specialized code. Grammars are written as\n * usual; compiling the root of a grammar only makes `Parser.parse`,\n * `Parser.parseSync`, `Parser.parsePeek`, `Parser.parsePartial` and\n * `Parser.parseEffect` faster, from any `offset`.\n *\n * There are two compilers, one function each, so a program bundles only the\n * one it uses, and a program that compiles nothing bundles neither:\n *\n * - {@link jit} generates code with `new Function` where it is allowed, and\n * otherwise uses the closure compiler. It is the fastest.\n * - {@link closure} builds specialized closures only. It never generates\n * code, and a bundle that uses only it contains no `new Function`, so it\n * is the choice under a Content Security Policy, where even probing for\n * `new Function` is reported as a violation.\n *\n * ```ts\n * import { Ascii, Compiler, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * export const list = Compiler.jit(\n * Parser.separated(Ascii.decInt, Token.literal(\",\"))\n * )\n * Parser.parse(list, \"1,2,3\") // Result.succeed([1, 2, 3]), compiled\n * ```\n *\n * Both return the same parser, so they also work in a pipe:\n * `p.pipe(Compiler.closure)`. The code is built lazily on the first run, for\n * each kind of input (string, bytes or array), and cached with the parser.\n * Compiling a parser again, with either function, replaces its compiled\n * form.\n *\n * **Results and errors are unchanged.** Compiled code records no\n * diagnostics. When it fails, the parser runs again, interpreted, from the\n * same offset, so every `ParseError` (offset, expected, context, cause and\n * message) is exactly the one the interpreter reports.\n *\n * **Callbacks should be pure.** On an input that fails, the callbacks given\n * to `map`, `filter`, `tryMap`, `tap`, `fold`, ... may run twice, once\n * compiled and once interpreted. Callbacks whose results are discarded\n * (a `map` inside `taken` or `preceded`, for example) may not run at all,\n * nor those of a branch that is certain to fail, and token-set predicates\n * may be called once per character code and cached.\n *\n * `Parser.parsePartial` and `ParserStream.parseAll` run a build that\n * handles partial input. `ParserStream.parseMany`, `Parser.parseRecoverable`\n * and runs with the `trace` option are always interpreted. Parsers that\n * can't be described, such as `Parser.make` and `Parser.gen`, run\n * interpreted inside compiled code.\n *\n * @since 0.2.0\n */\nimport type { Input } from \"./Input.js\"\nimport type { Parser } from \"./Parser.js\"\nimport { backend as closureBackend } from \"./internal/compiler/closure.js\"\nimport { backend as jitBackend } from \"./internal/compiler/jit.js\"\nimport { register } from \"./internal/compiler/registry.js\"\n\n/**\n * Compiles a parser with the JIT: generated code where `new Function` is\n * allowed, otherwise specialized closures (see {@link closure}). Returns the\n * same parser.\n *\n * @example\n * ```ts\n * import { Ascii, Compiler, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const list = Compiler.jit(Parser.separated(Ascii.decInt, Token.literal(\",\")))\n * Parser.parse(list, \"1,2,3\") // Result.succeed([1, 2, 3])\n * ```\n *\n * @since 0.2.0\n * @category compilation\n */\nexport const jit = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> => {\n register(self, jitBackend)\n return self\n}\n\n/**\n * Compiles a parser into specialized closures. Returns the same parser.\n * Nothing is generated, so it works under a Content Security Policy, and a\n * bundle that compiles only with `closure` contains no `new Function`.\n *\n * @example\n * ```ts\n * import { Ascii, Compiler, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const list = Compiler.closure(Parser.separated(Ascii.decInt, Token.literal(\",\")))\n * Parser.parse(list, \"1,2,3\") // Result.succeed([1, 2, 3])\n * ```\n *\n * @since 0.2.0\n * @category compilation\n */\nexport const closure = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> => {\n register(self, closureBackend)\n return self\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAyEA,MAAa,OAAiC,SAAiD;CAC7F,SAAS,MAAMA,SAAU;CACzB,OAAO;AACT;;;;;;;;;;;;;;;;;AAkBA,MAAa,WAAqC,SAAiD;CACjG,SAAS,MAAMC,OAAc;CAC7B,OAAO;AACT"}
1
+ {"version":3,"file":"Compiler.js","names":["wasmBackend","jitBackend","closureBackend"],"sources":["../src/Compiler.ts"],"sourcesContent":["/**\n * Compiles parsers into fused, specialized code. Grammars are written as\n * usual; compiling the root of a grammar only makes `Parser.parse`,\n * `Parser.parseSync`, `Parser.parsePeek`, `Parser.parsePartial` and\n * `Parser.parseEffect` faster, from any `offset`.\n *\n * There are three compilers, one function each, so a program bundles only\n * the ones it uses, and a program that compiles nothing bundles none:\n *\n * - {@link wasm} scans the input in WebAssembly and builds the value with\n * generated JavaScript. It is the fastest on strings and bytes, and uses\n * the JIT for array input and streaming, and where WebAssembly or\n * `new Function` is unavailable.\n * - {@link jit} generates code with `new Function` where it is allowed, and\n * otherwise uses the closure compiler.\n * - {@link closure} builds specialized closures only. It never generates\n * code, and a bundle that uses only it contains no `new Function`, so it\n * is the choice under a Content Security Policy, where even probing for\n * `new Function` is reported as a violation.\n *\n * ```ts\n * import { Ascii, Compiler, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * export const list = Compiler.jit(\n * Parser.separated(Ascii.decInt, Token.literal(\",\"))\n * )\n * Parser.parse(list, \"1,2,3\") // Result.succeed([1, 2, 3]), compiled\n * ```\n *\n * Both return the same parser, so they also work in a pipe:\n * `p.pipe(Compiler.closure)`. The code is built lazily on the first run, for\n * each kind of input (string, bytes or array), and cached with the parser.\n * Compiling a parser again, with either function, replaces its compiled\n * form.\n *\n * **Results and errors are unchanged.** Compiled code records no\n * diagnostics. When it fails, the parser runs again, interpreted, from the\n * same offset, so every `ParseError` (offset, expected, context, cause and\n * message) is exactly the one the interpreter reports. Running out of\n * partial input is not a failure that needs it: compiled code reports\n * `Incomplete` where the interpreter does, with the same `needed`.\n *\n * **Callbacks should be pure.** On an input that fails, the callbacks given\n * to `map`, `filter`, `tryMap`, `tap`, `fold`, ... may run twice, once\n * compiled and once interpreted. Callbacks whose results are discarded\n * (a `map` inside `taken` or `preceded`, for example) may not run at all,\n * nor those of a branch that is certain to fail, and token-set predicates\n * may be called once per character code and cached.\n *\n * `Parser.parsePartial`, `ParserStream.parseAll` and\n * `ParserStream.parseMany` run a build that handles partial input;\n * `parseMany` runs it once per value and parses a value again, interpreted,\n * only when it fails. `Parser.parseRecoverable`, `Syntax`\n * parses and runs with the `trace` option are always interpreted. Parsers that\n * can't be described, such as `Parser.make` and `Parser.gen`, run\n * interpreted inside compiled code; the parsers given to a\n * `Parser.combinator` compile, and its step is built from theirs.\n *\n * @since 0.2.0\n */\nimport type { Fail, Input, State } from \"./Input.js\"\nimport type { Parser, RunOptions } from \"./Parser.js\"\nimport { backend as closureBackend } from \"./internal/compiler/closure.js\"\nimport { backend as jitBackend } from \"./internal/compiler/jit.js\"\nimport { register } from \"./internal/compiler/registry.js\"\nimport { backend as wasmBackend } from \"./internal/compiler/wasm.js\"\nimport { prepare } from \"./internal/run.js\"\n\n/**\n * Compiles a parser with the WebAssembly compiler. Returns the same parser.\n *\n * The input is copied into WebAssembly memory and scanned there, by code\n * generated from the grammar; a JavaScript function generated with\n * `new Function` then builds the value from what the scan recorded, with\n * the same callbacks and the same objects as the JIT. Parts of the grammar\n * with no WebAssembly form (such as `Parser.make`, `flatMap`, or `filter`\n * on a value) run their JIT-compiled code from inside the scan.\n *\n * It uses the JIT (see {@link jit}) for array input, for the streaming build\n * of `Parser.parsePartial` and `ParserStream`, and where `WebAssembly` or\n * `new Function` is unavailable: a Content Security Policy needs both\n * `'wasm-unsafe-eval'` and `'unsafe-eval'` for it. Short strings with the\n * same characters may be returned as one string, which no program can tell\n * apart from two.\n *\n * @example\n * ```ts\n * import { Ascii, Compiler, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const list = Compiler.wasm(Parser.separated(Ascii.decInt, Token.literal(\",\")))\n * Parser.parse(list, \"1,2,3\") // Result.succeed([1, 2, 3])\n * ```\n *\n * @since 0.5.0\n * @category compilation\n */\nexport const wasm = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> => {\n register(self, wasmBackend)\n return self\n}\n\n/**\n * Compiles a parser with the JIT: generated code where `new Function` is\n * allowed, otherwise specialized closures (see {@link closure}). Returns the\n * same parser.\n *\n * @example\n * ```ts\n * import { Ascii, Compiler, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const list = Compiler.jit(Parser.separated(Ascii.decInt, Token.literal(\",\")))\n * Parser.parse(list, \"1,2,3\") // Result.succeed([1, 2, 3])\n * ```\n *\n * @since 0.2.0\n * @category compilation\n */\nexport const jit = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> => {\n register(self, jitBackend)\n return self\n}\n\n/**\n * Compiles a parser into specialized closures. Returns the same parser.\n * Nothing is generated, so it works under a Content Security Policy, and a\n * bundle that compiles only with `closure` contains no `new Function`.\n *\n * @example\n * ```ts\n * import { Ascii, Compiler, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const list = Compiler.closure(Parser.separated(Ascii.decInt, Token.literal(\",\")))\n * Parser.parse(list, \"1,2,3\") // Result.succeed([1, 2, 3])\n * ```\n *\n * @since 0.2.0\n * @category compilation\n */\nexport const closure = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> => {\n register(self, closureBackend)\n return self\n}\n\n/**\n * Prepares a parser for running many times on states you own, as\n * `Parser.run` does: for drivers that make one small run per token, such as\n * a lexer over a buffer. `Parser.run` looks the parser's compiled form up\n * on every run, which costs about a quarter of a small token's time; the\n * function returned here looks it up once (again only when the input kind\n * changes, or between complete and partial states) and calls the compiled\n * code directly.\n *\n * It returns exactly what `Parser.run(self, state, options)` returns, and\n * leaves the state as it would: the output with the cursor where the\n * parser stopped, or `Fail` with the interpreter's failure (or, with\n * `diagnostics: false`, only the mode). Compile the parser first with\n * {@link jit} or {@link closure}; a parser that isn't compiled runs\n * interpreted. The compiled form is looked up on the first run, so compile\n * the parser before using the runner: compiling it again later doesn't\n * reach a runner that has already run.\n *\n * @example\n * ```ts\n * import { Ascii, Compiler, Input, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const token = Compiler.jit(Parser.preceded(Ascii.space0, Parser.alt(Ascii.alpha1, Token.oneOf(\"+-\"))))\n * const next = Compiler.runner(token)\n *\n * const tokens = (text: string): Array<string> => {\n * const state = new Input.State(text)\n * const out: Array<string> = []\n * while (state.pos < state.end) {\n * const t = next(state.reset(state.pos))\n * if (t === Input.Fail) break\n * out.push(t)\n * }\n * return out\n * }\n *\n * tokens(\"a + b\") // [\"a\", \"+\", \"b\"]\n * ```\n *\n * @since 0.5.0\n * @category running\n */\nexport const runner = <A, E, R, I extends Input>(\n self: Parser<A, E, R, I>,\n options?: RunOptions\n): ((state: State<I>) => A | Fail) => prepare(self, self.step, options?.diagnostics !== false)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgGA,MAAa,QAAkC,SAAiD;CAC9F,SAAS,MAAMA,SAAW;CAC1B,OAAO;AACT;;;;;;;;;;;;;;;;;AAkBA,MAAa,OAAiC,SAAiD;CAC7F,SAAS,MAAMC,SAAU;CACzB,OAAO;AACT;;;;;;;;;;;;;;;;;AAkBA,MAAa,WAAqC,SAAiD;CACjG,SAAS,MAAMC,OAAc;CAC7B,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,MAAa,UACX,MACA,YACoC,QAAQ,MAAM,KAAK,MAAM,SAAS,gBAAgB,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"Expression.d.ts","names":[],"sources":["../src/Expression.ts"],"mappings":";;;;;;;;YAiDY,SAAS,GAAG,WAAW,WAAW,UAAU,kBACpD,OAAO,GAAG,GAAG,GAAG,KAChB,QAAQ,GAAG,GAAG,GAAG,KACjB,MAAM,GAAG,GAAG,GAAG;UAET,aAAa,GAAG,GAAG,UAAU;WAC5B,QAAQ,gBAAgB,GAAG,GAAG;WAC9B;;;;;;iBAOM,OAAO,GAAG,WAAW,WAAW,UAAU,wBAAwB,aAAa,GAAG,GAAG;WAC3F;WACA,OAAO,SAAS,SAAS,MAAM;;;;;;iBAOzB,QAAQ,GAAG,WAAW,WAAW,UAAU,wBAAwB,aAAa,GAAG,GAAG;WAC5F;WACA,OAAO,SAAS,GAAG,YAAY;;;;;;iBAOzB,MAAM,GAAG,WAAW,WAAW,UAAU,wBAAwB,aAAa,GAAG,GAAG;WAC1F;WACA;WACA,OAAO,MAAM,GAAG,SAAS,OAAO,MAAM;;;;;;;;qBASpC,SAAU,GAAG,GAAG,GAAG,UAAU,OAAO,GAC/C,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,IAAI,GAAG,SAAS,MAAM,MAC5B,OAAO,GAAG,GAAG,GAAG;;;;;;;qBAQN,UAAW,GAAG,GAAG,GAAG,UAAU,OAAO,GAChD,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,SAAS,GAAG,IAAI,MAAM,MAC5B,QAAQ,GAAG,GAAG,GAAG;;;;;;;qBAQP,YAAa,GAAG,GAAG,GAAG,UAAU,OAAO,GAClD,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,MAAM,GAAG,IAAI,GAAG,OAAO,MAAM,MACnC,MAAM,GAAG,GAAG,GAAG;;;;;;;qBAQL,aAAc,GAAG,GAAG,GAAG,UAAU,OAAO,GACnD,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,MAAM,GAAG,IAAI,GAAG,OAAO,MAAM,MACnC,MAAM,GAAG,GAAG,GAAG;KAEb,QAAQ,MAAM,WAAW,mBAAmB,SAAS,UAAU,MAAM;KACrE,WAAW,MAAM,WAAW,mBAAmB,UAAU,SAAS,MAAM;KACxE,QAAQ,OAAO,sBAAsB,SAAS,aAAa,mBAAmB,UAAU,UAAU,MAAM;;;;;;;;;;;;;;qBAehG,OAAQ,GAAG,GAAG,GAAG,UAAU,aAAa,YAAY,cAAc,SAAS,oBAAoB;WACjG,SAAS,OAAO,GAAG,GAAG,GAAG;WACzB,WAAW;MAClB,OAAO,GAAG,IAAI,QAAQ,cAAc,IAAI,WAAW,cAAc,IAAI,QAAQ"}
1
+ {"version":3,"file":"Expression.d.ts","names":[],"sources":["../src/Expression.ts"],"mappings":";;;;;;;;YAoDY,SAAS,GAAG,WAAW,WAAW,UAAU,kBACpD,OAAO,GAAG,GAAG,GAAG,KAChB,QAAQ,GAAG,GAAG,GAAG,KACjB,MAAM,GAAG,GAAG,GAAG;UAET,aAAa,GAAG,GAAG,UAAU;WAC5B,QAAQ,gBAAgB,GAAG,GAAG;WAC9B;;;;;;iBAOM,OAAO,GAAG,WAAW,WAAW,UAAU,wBAAwB,aAAa,GAAG,GAAG;WAC3F;WACA,OAAO,SAAS,SAAS,MAAM;;;;;;iBAOzB,QAAQ,GAAG,WAAW,WAAW,UAAU,wBAAwB,aAAa,GAAG,GAAG;WAC5F;WACA,OAAO,SAAS,GAAG,YAAY;;;;;;iBAOzB,MAAM,GAAG,WAAW,WAAW,UAAU,wBAAwB,aAAa,GAAG,GAAG;WAC1F;WACA;WACA,OAAO,MAAM,GAAG,SAAS,OAAO,MAAM;;;;;;;;qBASpC,SAAU,GAAG,GAAG,GAAG,UAAU,OAAO,GAC/C,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,IAAI,GAAG,SAAS,MAAM,MAC5B,OAAO,GAAG,GAAG,GAAG;;;;;;;qBAQN,UAAW,GAAG,GAAG,GAAG,UAAU,OAAO,GAChD,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,SAAS,GAAG,IAAI,MAAM,MAC5B,QAAQ,GAAG,GAAG,GAAG;;;;;;;qBAQP,YAAa,GAAG,GAAG,GAAG,UAAU,OAAO,GAClD,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,MAAM,GAAG,IAAI,GAAG,OAAO,MAAM,MACnC,MAAM,GAAG,GAAG,GAAG;;;;;;;qBAQL,aAAc,GAAG,GAAG,GAAG,UAAU,OAAO,GACnD,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,MAAM,GAAG,IAAI,GAAG,OAAO,MAAM,MACnC,MAAM,GAAG,GAAG,GAAG;KAEb,QAAQ,MAAM,WAAW,mBAAmB,SAAS,UAAU,MAAM;KACrE,WAAW,MAAM,WAAW,mBAAmB,UAAU,SAAS,MAAM;KACxE,QAAQ,OAAO,sBAAsB,SAAS,aAAa,mBAAmB,UAAU,UAAU,MAAM;;;;;;;;;;;;;;qBAehG,OAAQ,GAAG,GAAG,GAAG,UAAU,aAAa,YAAY,cAAc,SAAS,oBAAoB;WACjG,SAAS,OAAO,GAAG,GAAG,GAAG;WACzB,WAAW;MAClB,OAAO,GAAG,IAAI,QAAQ,cAAc,IAAI,WAAW,cAAc,IAAI,QAAQ"}
@@ -1,6 +1,6 @@
1
1
  import * as Predicate from "effect/Predicate";
2
2
  import { Fail } from "./Input.js";
3
- import { make as make$1 } from "./Parser.js";
3
+ import { combinator } from "./Parser.js";
4
4
  import { TiedFailures } from "./internal/ties.js";
5
5
  // src/Expression.ts
6
6
  /**
@@ -103,91 +103,103 @@ const infixRight = (parser, precedence, fold) => ({
103
103
  * @category constructors
104
104
  */
105
105
  const make = (options) => {
106
- const operand = options.operand.step;
107
106
  const prefixes = options.operators.filter((o) => Predicate.isTagged(o, "Prefix"));
108
107
  const postfixes = options.operators.filter((o) => Predicate.isTagged(o, "Postfix"));
109
108
  const infixes = options.operators.filter((o) => Predicate.isTagged(o, "Infix"));
110
- let matched;
111
- const failures = new TiedFailures();
112
- const tryOps = (state, ops, mustConsume) => {
113
- const start = state.pos;
114
- for (let i = 0; i < ops.length; i++) {
115
- const out = ops[i].parser.step(state);
116
- if (out !== Fail) {
117
- if (mustConsume && state.pos === start) {
118
- state.failMessage("Cut", "Assert", "prefix and postfix operators must always consume");
119
- return -2;
109
+ const operators = [
110
+ ...prefixes,
111
+ ...postfixes,
112
+ ...infixes
113
+ ];
114
+ const parsers = [options.operand, ...operators.map((o) => o.parser)];
115
+ const build = (steps) => {
116
+ const operand = steps[0];
117
+ const prefixSteps = steps.slice(1, 1 + prefixes.length);
118
+ const postfixSteps = steps.slice(1 + prefixes.length, 1 + prefixes.length + postfixes.length);
119
+ const infixSteps = steps.slice(1 + prefixes.length + postfixes.length);
120
+ let matched;
121
+ const failures = new TiedFailures();
122
+ const tryOps = (state, ops, mustConsume) => {
123
+ const start = state.pos;
124
+ for (let i = 0; i < ops.length; i++) {
125
+ const out = ops[i](state);
126
+ if (out !== Fail) {
127
+ if (mustConsume && state.pos === start) {
128
+ state.failMessage("Cut", "Assert", "prefix and postfix operators must always consume");
129
+ return -2;
130
+ }
131
+ matched = out;
132
+ return i;
120
133
  }
121
- matched = out;
122
- return i;
134
+ if (state.mode !== "Backtrack") return -2;
135
+ state.rewind(start);
136
+ failures.add(state);
123
137
  }
124
- if (state.mode !== "Backtrack") return -2;
125
- state.rewind(start);
126
- failures.add(state);
127
- }
128
- return -1;
129
- };
130
- const expr = (state, minPower) => {
131
- let lhs;
132
- failures.clear();
133
- const p = tryOps(state, prefixes, true);
134
- if (p === -2) return Fail;
135
- if (p >= 0) {
136
- const op = prefixes[p];
137
- const opOut = matched;
138
- const operandValue = expr(state, op.precedence * 2);
139
- if (operandValue === Fail) return Fail;
140
- lhs = op.fold(opOut, operandValue);
141
- } else {
142
- const prefixFailure = failures.failure;
143
- const prefixTie1 = failures.tie1;
144
- const prefixTie2 = failures.tie2;
145
- lhs = operand(state);
146
- if (lhs === Fail) {
147
- if (prefixFailure !== void 0 && state.mode === "Backtrack") {
148
- failures.failure = prefixFailure;
149
- failures.tie1 = prefixTie1;
150
- failures.tie2 = prefixTie2;
151
- failures.add(state);
152
- failures.fail(state);
138
+ return -1;
139
+ };
140
+ const expr = (state, minPower) => {
141
+ let lhs;
142
+ failures.clear();
143
+ const p = tryOps(state, prefixSteps, true);
144
+ if (p === -2) return Fail;
145
+ if (p >= 0) {
146
+ const op = prefixes[p];
147
+ const opOut = matched;
148
+ const operandValue = expr(state, op.precedence * 2);
149
+ if (operandValue === Fail) return Fail;
150
+ lhs = op.fold(opOut, operandValue);
151
+ } else {
152
+ const prefixFailure = failures.failure;
153
+ const prefixTie1 = failures.tie1;
154
+ const prefixTie2 = failures.tie2;
155
+ lhs = operand(state);
156
+ if (lhs === Fail) {
157
+ if (prefixFailure !== void 0 && state.mode === "Backtrack") {
158
+ failures.failure = prefixFailure;
159
+ failures.tie1 = prefixTie1;
160
+ failures.tie2 = prefixTie2;
161
+ failures.add(state);
162
+ failures.fail(state);
163
+ }
164
+ return Fail;
153
165
  }
154
- return Fail;
155
166
  }
156
- }
157
- while (true) {
158
- const start = state.pos;
159
- failures.clear();
160
- const q = tryOps(state, postfixes, true);
161
- if (q === -2) return Fail;
162
- if (q >= 0) {
163
- const op = postfixes[q];
164
- if (op.precedence * 2 < minPower) {
167
+ while (true) {
168
+ const start = state.pos;
169
+ failures.clear();
170
+ const q = tryOps(state, postfixSteps, true);
171
+ if (q === -2) return Fail;
172
+ if (q >= 0) {
173
+ const op = postfixes[q];
174
+ if (op.precedence * 2 < minPower) {
175
+ state.rewind(start);
176
+ break;
177
+ }
178
+ lhs = op.fold(lhs, matched);
179
+ continue;
180
+ }
181
+ const i = tryOps(state, infixSteps, false);
182
+ if (i === -2) return Fail;
183
+ if (i < 0) {
184
+ failures.hint(state);
185
+ break;
186
+ }
187
+ const op = infixes[i];
188
+ const leftPower = op.precedence * 2;
189
+ if (leftPower < minPower) {
165
190
  state.rewind(start);
166
191
  break;
167
192
  }
168
- lhs = op.fold(lhs, matched);
169
- continue;
170
- }
171
- const i = tryOps(state, infixes, false);
172
- if (i === -2) return Fail;
173
- if (i < 0) {
174
- failures.hint(state);
175
- break;
176
- }
177
- const op = infixes[i];
178
- const leftPower = op.precedence * 2;
179
- if (leftPower < minPower) {
180
- state.rewind(start);
181
- break;
193
+ const opOut = matched;
194
+ const rhs = expr(state, op.associativity === "left" ? leftPower + 1 : leftPower);
195
+ if (rhs === Fail) return Fail;
196
+ lhs = op.fold(lhs, opOut, rhs);
182
197
  }
183
- const opOut = matched;
184
- const rhs = expr(state, op.associativity === "left" ? leftPower + 1 : leftPower);
185
- if (rhs === Fail) return Fail;
186
- lhs = op.fold(lhs, opOut, rhs);
187
- }
188
- return lhs;
198
+ return lhs;
199
+ };
200
+ return (state) => expr(state, 0);
189
201
  };
190
- return make$1((state) => expr(state, 0), "expression");
202
+ return combinator(parsers, build, "expression");
191
203
  };
192
204
  export { infixLeft, infixRight, make, postfix, prefix };
193
205