@thomasfosterau/effect-parse 0.1.0 → 0.3.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 (161) hide show
  1. package/README.md +291 -231
  2. package/dist/Ascii.d.ts +32 -53
  3. package/dist/Ascii.d.ts.map +1 -1
  4. package/dist/Ascii.js +576 -571
  5. package/dist/Ascii.js.map +1 -1
  6. package/dist/Binary.d.ts +6 -29
  7. package/dist/Binary.d.ts.map +1 -1
  8. package/dist/Binary.js +129 -116
  9. package/dist/Binary.js.map +1 -1
  10. package/dist/Bits.d.ts +4 -2
  11. package/dist/Bits.d.ts.map +1 -1
  12. package/dist/Bits.js +121 -123
  13. package/dist/Bits.js.map +1 -1
  14. package/dist/Compiler.d.ts +39 -0
  15. package/dist/Compiler.d.ts.map +1 -0
  16. package/dist/Compiler.js +48 -0
  17. package/dist/Compiler.js.map +1 -0
  18. package/dist/Encoding.d.ts +29 -46
  19. package/dist/Encoding.d.ts.map +1 -1
  20. package/dist/Encoding.js +76 -75
  21. package/dist/Encoding.js.map +1 -1
  22. package/dist/Expression.d.ts +15 -49
  23. package/dist/Expression.d.ts.map +1 -1
  24. package/dist/Expression.js +151 -132
  25. package/dist/Expression.js.map +1 -1
  26. package/dist/Input.d.ts +251 -177
  27. package/dist/Input.d.ts.map +1 -1
  28. package/dist/Input.js +409 -299
  29. package/dist/Input.js.map +1 -1
  30. package/dist/Nom.d.ts +45 -85
  31. package/dist/Nom.d.ts.map +1 -1
  32. package/dist/Nom.js +423 -453
  33. package/dist/Nom.js.map +1 -1
  34. package/dist/ParseError.d.ts +54 -49
  35. package/dist/ParseError.d.ts.map +1 -1
  36. package/dist/ParseError.js +232 -275
  37. package/dist/ParseError.js.map +1 -1
  38. package/dist/Parser.d.ts +345 -313
  39. package/dist/Parser.d.ts.map +1 -1
  40. package/dist/Parser.js +2034 -1802
  41. package/dist/Parser.js.map +1 -1
  42. package/dist/ParserSchema.d.ts +206 -7
  43. package/dist/ParserSchema.d.ts.map +1 -1
  44. package/dist/ParserSchema.js +678 -49
  45. package/dist/ParserSchema.js.map +1 -1
  46. package/dist/ParserStream.d.ts +26 -20
  47. package/dist/ParserStream.d.ts.map +1 -1
  48. package/dist/ParserStream.js +267 -255
  49. package/dist/ParserStream.js.map +1 -1
  50. package/dist/Syntax.d.ts +401 -0
  51. package/dist/Syntax.d.ts.map +1 -0
  52. package/dist/Syntax.js +717 -0
  53. package/dist/Syntax.js.map +1 -0
  54. package/dist/Text.d.ts +98 -134
  55. package/dist/Text.d.ts.map +1 -1
  56. package/dist/Text.js +534 -496
  57. package/dist/Text.js.map +1 -1
  58. package/dist/Token.d.ts +60 -42
  59. package/dist/Token.d.ts.map +1 -1
  60. package/dist/Token.js +331 -265
  61. package/dist/Token.js.map +1 -1
  62. package/dist/index.d.ts +16 -17
  63. package/dist/index.js +16 -17
  64. package/dist/internal/compiler/closure.d.ts +14 -16
  65. package/dist/internal/compiler/closure.d.ts.map +1 -1
  66. package/dist/internal/compiler/closure.js +1458 -1637
  67. package/dist/internal/compiler/closure.js.map +1 -1
  68. package/dist/internal/compiler/entries.d.ts +11 -11
  69. package/dist/internal/compiler/entries.d.ts.map +1 -1
  70. package/dist/internal/compiler/entries.js +36 -26
  71. package/dist/internal/compiler/entries.js.map +1 -1
  72. package/dist/internal/compiler/first.d.ts +19 -19
  73. package/dist/internal/compiler/first.d.ts.map +1 -1
  74. package/dist/internal/compiler/first.js +251 -227
  75. package/dist/internal/compiler/first.js.map +1 -1
  76. package/dist/internal/compiler/jit.d.ts +6 -17
  77. package/dist/internal/compiler/jit.d.ts.map +1 -1
  78. package/dist/internal/compiler/jit.js +860 -988
  79. package/dist/internal/compiler/jit.js.map +1 -1
  80. package/dist/internal/compiler/registry.d.ts +20 -21
  81. package/dist/internal/compiler/registry.d.ts.map +1 -1
  82. package/dist/internal/compiler/registry.js +21 -41
  83. package/dist/internal/compiler/registry.js.map +1 -1
  84. package/dist/internal/compiler/sets.d.ts +9 -13
  85. package/dist/internal/compiler/sets.d.ts.map +1 -1
  86. package/dist/internal/compiler/sets.js +76 -73
  87. package/dist/internal/compiler/sets.js.map +1 -1
  88. package/dist/internal/entries.d.ts +3 -3
  89. package/dist/internal/entries.d.ts.map +1 -1
  90. package/dist/internal/entries.js +38 -30
  91. package/dist/internal/entries.js.map +1 -1
  92. package/dist/internal/node.d.ts +177 -173
  93. package/dist/internal/node.d.ts.map +1 -1
  94. package/dist/internal/node.js +77 -66
  95. package/dist/internal/node.js.map +1 -1
  96. package/dist/internal/numbers.d.ts +7 -8
  97. package/dist/internal/numbers.d.ts.map +1 -1
  98. package/dist/internal/numbers.js +246 -276
  99. package/dist/internal/numbers.js.map +1 -1
  100. package/dist/internal/resume.d.ts +6 -24
  101. package/dist/internal/resume.d.ts.map +1 -1
  102. package/dist/internal/resume.js +30 -29
  103. package/dist/internal/resume.js.map +1 -1
  104. package/dist/internal/run.d.ts +15 -0
  105. package/dist/internal/run.d.ts.map +1 -0
  106. package/dist/internal/run.js +36 -0
  107. package/dist/internal/run.js.map +1 -0
  108. package/dist/internal/stack.d.ts +16 -0
  109. package/dist/internal/stack.d.ts.map +1 -0
  110. package/dist/internal/stack.js +36 -0
  111. package/dist/internal/stack.js.map +1 -0
  112. package/dist/internal/syntax.d.ts +147 -0
  113. package/dist/internal/syntax.d.ts.map +1 -0
  114. package/dist/internal/syntax.js +309 -0
  115. package/dist/internal/syntax.js.map +1 -0
  116. package/dist/internal/text.d.ts +10 -2
  117. package/dist/internal/text.d.ts.map +1 -1
  118. package/dist/internal/text.js +295 -345
  119. package/dist/internal/text.js.map +1 -1
  120. package/dist/internal/ties.d.ts +30 -0
  121. package/dist/internal/ties.d.ts.map +1 -0
  122. package/dist/internal/ties.js +67 -0
  123. package/dist/internal/ties.js.map +1 -0
  124. package/dist/internal/tokens.d.ts +25 -30
  125. package/dist/internal/tokens.d.ts.map +1 -1
  126. package/dist/internal/tokens.js +369 -363
  127. package/dist/internal/tokens.js.map +1 -1
  128. package/package.json +42 -28
  129. package/src/Ascii.ts +278 -187
  130. package/src/Binary.ts +150 -44
  131. package/src/Bits.ts +6 -3
  132. package/src/Compiler.ts +98 -0
  133. package/src/Expression.ts +24 -16
  134. package/src/Input.ts +210 -35
  135. package/src/Nom.ts +4 -3
  136. package/src/ParseError.ts +49 -52
  137. package/src/Parser.ts +1199 -799
  138. package/src/ParserSchema.ts +982 -23
  139. package/src/ParserStream.ts +104 -80
  140. package/src/Syntax.ts +900 -0
  141. package/src/Text.ts +272 -187
  142. package/src/Token.ts +180 -87
  143. package/src/index.ts +2 -0
  144. package/src/internal/compiler/closure.ts +121 -88
  145. package/src/internal/compiler/entries.ts +21 -8
  146. package/src/internal/compiler/first.ts +17 -15
  147. package/src/internal/compiler/jit.ts +360 -157
  148. package/src/internal/compiler/registry.ts +12 -33
  149. package/src/internal/compiler/sets.ts +17 -11
  150. package/src/internal/entries.ts +4 -2
  151. package/src/internal/node.ts +51 -37
  152. package/src/internal/numbers.ts +22 -20
  153. package/src/internal/resume.ts +8 -4
  154. package/src/internal/run.ts +41 -0
  155. package/src/internal/stack.ts +41 -0
  156. package/src/internal/syntax.ts +426 -0
  157. package/src/internal/text.ts +32 -25
  158. package/src/internal/ties.ts +83 -0
  159. package/src/internal/tokens.ts +96 -51
  160. package/dist/index.d.ts.map +0 -1
  161. package/dist/index.js.map +0 -1
package/dist/Syntax.js ADDED
@@ -0,0 +1,717 @@
1
+ import * as Predicate from "effect/Predicate";
2
+ import { Fail, fromSource } from "./Input.js";
3
+ import { described, isParser } from "./Parser.js";
4
+ import * as Option from "effect/Option";
5
+ import { dual } from "effect/Function";
6
+ import * as ParseError from "./ParseError.js";
7
+ import * as Stack from "./internal/stack.js";
8
+ import { nodeOf } from "./internal/node.js";
9
+ import { SyntaxState, absolute, errorKind } from "./internal/syntax.js";
10
+ //#region src/Syntax.ts
11
+ /**
12
+ * Concrete syntax trees and incremental parsing, in the spirit of
13
+ * [Tree-sitter](https://tree-sitter.github.io).
14
+ *
15
+ * Mark the rules of a grammar that should appear in the tree with
16
+ * {@link node} (and, optionally, {@link token} and {@link field}). Outside
17
+ * this module the marks change nothing: `Parser.parse` returns the same
18
+ * values, and compiled parsers compile them away. {@link parse} runs the
19
+ * grammar and returns a {@link Tree}: a tree of {@link SyntaxNode}s with
20
+ * spans, parents and siblings, to search by position (`descendantAt`) or walk
21
+ * with a {@link TreeCursor}. Each node also carries the value its parser
22
+ * returned.
23
+ *
24
+ * Like Tree-sitter, a syntax parse always produces a tree. Failures handled
25
+ * by `Parser.resumeAfter` and `Parser.retryAfter` become `ERROR` nodes over
26
+ * the input they skipped, and so does any input after a fatal failure.
27
+ *
28
+ * After an edit, {@link reparse} (or {@link replace}) parses the new input
29
+ * reusing every node of the old tree whose input is unchanged: only the
30
+ * nodes that enclose the edit, or looked at the edited input, are parsed
31
+ * again, and each reused node is stepped over whole.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * import { Ascii, Parser, Syntax, Token } from "@thomasfosterau/effect-parse"
36
+ *
37
+ * const ws = Ascii.multispace0
38
+ * const number = Syntax.node(Ascii.decInt, "number")
39
+ * const list = Syntax.node(
40
+ * Parser.delimited(
41
+ * Token.literal("["),
42
+ * Parser.separated(Parser.delimited(ws, number, ws), Token.literal(",")),
43
+ * Token.literal("]")
44
+ * ),
45
+ * "list"
46
+ * )
47
+ *
48
+ * const tree = Syntax.parse(list, "[1, 2, 3]")
49
+ * String(tree.root) // "(list (number) (number) (number))"
50
+ * tree.root.descendantAt(4)?.text // "2"
51
+ *
52
+ * const edited = Syntax.replace(tree, 4, 5, "20") // "[1, 20, 3]"
53
+ * edited.root.namedChild(1)?.value // 20
54
+ * edited.reused // 2: only "20" was parsed again
55
+ * ```
56
+ *
57
+ * @since 0.2.0
58
+ */
59
+ const syntaxNode = (self, kind, named) => {
60
+ const step = self.step;
61
+ const key = {};
62
+ return described((state) => {
63
+ const builder = state.syntax;
64
+ return builder === void 0 ? step(state) : builder.node(state, step, key, kind, named);
65
+ }, self.name, {
66
+ _tag: "Syntax",
67
+ self,
68
+ kind,
69
+ named
70
+ });
71
+ };
72
+ /**
73
+ * Marks a parser as a rule of the syntax tree: in a {@link parse}, each
74
+ * match becomes a named node of the given kind, spanning the input it
75
+ * consumed, with the nodes built inside it as children and its output as
76
+ * its `value`. Outside {@link parse}, the parser is unchanged.
77
+ *
78
+ * A match that consumes nothing adds no node (as in Tree-sitter, where rules
79
+ * can't match the empty string).
80
+ *
81
+ * For {@link reparse} to reuse a node, its parser's output must depend only
82
+ * on the input from where the node starts: not on services, on state kept
83
+ * in closures, or on absolute offsets (`Parser.location`, `Parser.span`),
84
+ * which are not updated when the node moves. Use the node's `start` and
85
+ * `end` instead.
86
+ *
87
+ * @since 0.2.0
88
+ * @category annotations
89
+ */
90
+ const node = /*#__PURE__*/ dual(2, (self, kind) => syntaxNode(self, kind, true));
91
+ /**
92
+ * Like {@link node}, but builds an *anonymous* node, Tree-sitter's name for
93
+ * punctuation and keywords: anonymous nodes are left out of
94
+ * `namedChildren` and of the tree's printed form. The kind defaults to the
95
+ * literal for a `Token.literal` of a string, and to the parser's name
96
+ * otherwise.
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * import { Syntax, Token } from "@thomasfosterau/effect-parse"
101
+ *
102
+ * const comma = Syntax.token(Token.literal(",")) // kind ","
103
+ * ```
104
+ *
105
+ * @since 0.2.0
106
+ * @category annotations
107
+ */
108
+ const token = /*#__PURE__*/ dual((args) => isParser(args[0]), (self, kind) => syntaxNode(self, kind ?? defaultTokenKind(self), false));
109
+ const defaultTokenKind = (self) => {
110
+ const n = nodeOf(self);
111
+ if (n._tag === "Literal" && Predicate.isString(n.literal) && !n.caseless) return n.literal;
112
+ return self.name ?? "token";
113
+ };
114
+ /**
115
+ * Gives the nodes built by a parser a field name in their parent, like
116
+ * Tree-sitter's `field(name, rule)`: find them with `childByField` and
117
+ * `childrenByField`. Outside {@link parse}, the parser is unchanged.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * import { Ascii, Parser, Syntax, Token } from "@thomasfosterau/effect-parse"
122
+ *
123
+ * const name = Syntax.node(Ascii.alpha1, "name")
124
+ * const number = Syntax.node(Ascii.decInt, "number")
125
+ * const pair = Syntax.node(
126
+ * Parser.separatedPair(Syntax.field(name, "key"), Token.literal("="), Syntax.field(number, "value")),
127
+ * "pair"
128
+ * )
129
+ * Syntax.parse(pair, "x=1").root.childByField("value")?.value // 1
130
+ * ```
131
+ *
132
+ * @since 0.2.0
133
+ * @category annotations
134
+ */
135
+ const field = /*#__PURE__*/ dual(2, (self, name) => {
136
+ const step = self.step;
137
+ return described((state) => {
138
+ const builder = state.syntax;
139
+ return builder === void 0 ? step(state) : builder.field(state, step, name);
140
+ }, self.name, {
141
+ _tag: "Syntax",
142
+ self,
143
+ kind: void 0,
144
+ named: false
145
+ });
146
+ });
147
+ /**
148
+ * The kind of the nodes that stand for input that could not be parsed.
149
+ *
150
+ * @since 0.2.0
151
+ * @category models
152
+ */
153
+ const ERROR = errorKind;
154
+ /**
155
+ * The result of a {@link parse}: a syntax tree over the whole input, the
156
+ * grammar's output, and the errors met on the way.
157
+ *
158
+ * @since 0.2.0
159
+ * @category models
160
+ */
161
+ var Tree = class {
162
+ input;
163
+ value;
164
+ reused;
165
+ green;
166
+ config;
167
+ encoding;
168
+ /** The root node. It always spans the whole input. */
169
+ root;
170
+ lines;
171
+ errorList;
172
+ /** @internal */
173
+ constructor(input, value, reused, green, config, encoding) {
174
+ this.input = input;
175
+ this.value = value;
176
+ this.reused = reused;
177
+ this.green = green;
178
+ this.config = config;
179
+ this.encoding = encoding;
180
+ this.root = new SyntaxNode(this, green, 0, void 0, 0);
181
+ }
182
+ /**
183
+ * Every error of the parse, in input order: the failures recovered by
184
+ * `Parser.resumeAfter` and `Parser.retryAfter`, then the fatal one, if
185
+ * the parse failed. Each one belongs to an `ERROR` node.
186
+ */
187
+ get errors() {
188
+ if (this.errorList === void 0) {
189
+ const out = [];
190
+ const visit = (green, start) => {
191
+ if (!green.hasError) return;
192
+ if (green.error !== void 0) out.push(this.toError(green.error, start));
193
+ for (let i = 0; i < green.children.length; i++) visit(green.children[i], start + green.offsets[i]);
194
+ };
195
+ visit(this.green, 0);
196
+ this.errorList = out;
197
+ }
198
+ return this.errorList;
199
+ }
200
+ /** Whether the tree has any `ERROR` node. */
201
+ get hasErrors() {
202
+ return this.green.hasError;
203
+ }
204
+ /** The smallest node containing `[start, end)` (see {@link SyntaxNode.descendantAt}). */
205
+ descendantAt(start, end) {
206
+ return this.root.descendantAt(start, end);
207
+ }
208
+ /** A cursor at the root. */
209
+ walk() {
210
+ return new TreeCursor(this.root);
211
+ }
212
+ /**
213
+ * The 1-based line and column (in code points) of an offset, as in
214
+ * `ParseError`. Lines of a string input are indexed once, so lookups take
215
+ * logarithmic time.
216
+ */
217
+ lineColumn(offset) {
218
+ const input = this.input;
219
+ if (!Predicate.isString(input)) return ParseError.lineColumn(input, offset, this.encoding);
220
+ let lines = this.lines;
221
+ if (lines === void 0) {
222
+ lines = [0];
223
+ for (let i = input.indexOf("\n"); i >= 0; i = input.indexOf("\n", i + 1)) lines.push(i + 1);
224
+ this.lines = lines;
225
+ }
226
+ const at = Math.max(0, Math.min(offset, input.length));
227
+ let lo = 0;
228
+ let hi = lines.length - 1;
229
+ while (lo < hi) {
230
+ const mid = lo + hi + 1 >> 1;
231
+ if (lines[mid] <= at) lo = mid;
232
+ else hi = mid - 1;
233
+ }
234
+ const lineStart = lines[lo];
235
+ return {
236
+ line: lo + 1,
237
+ column: ParseError.lineColumn(input.slice(lineStart, at), at - lineStart).column
238
+ };
239
+ }
240
+ /** The root's S-expression (see {@link SyntaxNode.toString}). */
241
+ toString() {
242
+ return this.root.toString();
243
+ }
244
+ /** @internal */
245
+ toError(error, start) {
246
+ return ParseError.fromFailure(this.input, absolute(error.failure, start), error.mode, this.encoding);
247
+ }
248
+ };
249
+ /**
250
+ * A node of a syntax tree: its kind, span and value, and its place in the
251
+ * tree. Nodes are views built on demand; two views of the same node are
252
+ * different objects but have the same `start`, `end` and `kind`.
253
+ *
254
+ * @since 0.2.0
255
+ * @category models
256
+ */
257
+ var SyntaxNode = class SyntaxNode {
258
+ tree;
259
+ green;
260
+ start;
261
+ parent;
262
+ index;
263
+ childList;
264
+ /** @internal */
265
+ constructor(tree, green, start, parent, index) {
266
+ this.tree = tree;
267
+ this.green = green;
268
+ this.start = start;
269
+ this.parent = parent;
270
+ this.index = index;
271
+ }
272
+ /** The node's kind: the name given to {@link node} or {@link token}, or `"ERROR"`. */
273
+ get kind() {
274
+ return this.green.kind;
275
+ }
276
+ /** `false` for the anonymous nodes built by {@link token}. */
277
+ get named() {
278
+ return this.green.named;
279
+ }
280
+ /** The field name given by {@link field}, if any. */
281
+ get field() {
282
+ return this.parent?.green.fields?.[this.index];
283
+ }
284
+ /** The offset where the node ends (exclusive). */
285
+ get end() {
286
+ return this.start + this.green.width;
287
+ }
288
+ /** The number of input units the node spans. */
289
+ get length() {
290
+ return this.green.width;
291
+ }
292
+ /** The output of the node's parser (`undefined` for `ERROR` nodes, and for a root that failed). */
293
+ get value() {
294
+ return this.green.value;
295
+ }
296
+ /** The input the node spans. */
297
+ get text() {
298
+ const input = this.tree.input;
299
+ return input instanceof Uint8Array ? input.subarray(this.start, this.end) : input.slice(this.start, this.end);
300
+ }
301
+ /** Whether this is an `ERROR` node. */
302
+ get isError() {
303
+ return this.green.error !== void 0;
304
+ }
305
+ /** Whether this node or a descendant is an `ERROR` node. */
306
+ get hasError() {
307
+ return this.green.hasError;
308
+ }
309
+ /** For an `ERROR` node, the error it stands for. */
310
+ get error() {
311
+ const error = this.green.error;
312
+ return error === void 0 ? void 0 : this.tree.toError(error, this.start);
313
+ }
314
+ /** The child nodes, named and anonymous, in input order. */
315
+ get children() {
316
+ if (this.childList === void 0) {
317
+ const green = this.green;
318
+ const out = new Array(green.children.length);
319
+ for (let i = 0; i < out.length; i++) out[i] = this.makeChild(i);
320
+ this.childList = out;
321
+ }
322
+ return this.childList;
323
+ }
324
+ /** The number of children. */
325
+ get childCount() {
326
+ return this.green.children.length;
327
+ }
328
+ /** The child at `index` (negative indices count from the end). */
329
+ child(index) {
330
+ const n = this.green.children.length;
331
+ const i = index < 0 ? n + index : index;
332
+ return i >= 0 && i < n ? this.children[i] : void 0;
333
+ }
334
+ /** The named children. */
335
+ get namedChildren() {
336
+ return this.children.filter((c) => c.named);
337
+ }
338
+ /** The named child at `index`. */
339
+ namedChild(index) {
340
+ return this.namedChildren[index];
341
+ }
342
+ /** The first child with the given field name. */
343
+ childByField(name) {
344
+ const fields = this.green.fields;
345
+ if (fields === void 0) return void 0;
346
+ const i = fields.indexOf(name);
347
+ return i < 0 ? void 0 : this.children[i];
348
+ }
349
+ /** The children with the given field name. */
350
+ childrenByField(name) {
351
+ const fields = this.green.fields;
352
+ if (fields === void 0) return [];
353
+ return this.children.filter((_, i) => fields[i] === name);
354
+ }
355
+ /** The next sibling, named or anonymous. */
356
+ get nextSibling() {
357
+ return this.parent?.children[this.index + 1];
358
+ }
359
+ /** The previous sibling, named or anonymous. */
360
+ get previousSibling() {
361
+ return this.index > 0 ? this.parent?.children[this.index - 1] : void 0;
362
+ }
363
+ /** The next named sibling. */
364
+ get nextNamedSibling() {
365
+ const siblings = this.parent?.children;
366
+ if (siblings === void 0) return void 0;
367
+ for (let i = this.index + 1; i < siblings.length; i++) if (siblings[i].named) return siblings[i];
368
+ }
369
+ /** The previous named sibling. */
370
+ get previousNamedSibling() {
371
+ const siblings = this.parent?.children;
372
+ if (siblings === void 0) return void 0;
373
+ for (let i = this.index - 1; i >= 0; i--) if (siblings[i].named) return siblings[i];
374
+ }
375
+ /**
376
+ * The index of the child containing the input unit at `offset`, or -1.
377
+ * Takes logarithmic time.
378
+ */
379
+ childIndexAt(offset) {
380
+ const green = this.green;
381
+ const offsets = green.offsets;
382
+ const rel = offset - this.start;
383
+ let lo = 0;
384
+ let hi = offsets.length - 1;
385
+ let found = -1;
386
+ while (lo <= hi) {
387
+ const mid = lo + hi >> 1;
388
+ if (offsets[mid] <= rel) {
389
+ found = mid;
390
+ lo = mid + 1;
391
+ } else hi = mid - 1;
392
+ }
393
+ while (found >= 0 && green.children[found].width === 0 && offsets[found] === rel) found--;
394
+ return found >= 0 && rel < offsets[found] + green.children[found].width ? found : -1;
395
+ }
396
+ /** The child containing the input unit at `offset`. */
397
+ childAt(offset) {
398
+ const i = this.childIndexAt(offset);
399
+ return i < 0 ? void 0 : this.children[i];
400
+ }
401
+ /**
402
+ * The smallest node, this one or a descendant, that contains
403
+ * `[start, end)` (Tree-sitter's `descendant_for_byte_range`). With only
404
+ * `start`, the deepest node containing the input unit at `start`. Takes
405
+ * time proportional to the depth of the tree times the logarithm of the
406
+ * number of children.
407
+ */
408
+ descendantAt(start, end = start + 1) {
409
+ return descendantOf(this, start, end);
410
+ }
411
+ /** Like {@link descendantAt}, but only stops at named nodes. */
412
+ namedDescendantAt(start, end = start + 1) {
413
+ let node = this.descendantAt(start, end);
414
+ while (!node.named && node !== this) node = node.parent ?? this;
415
+ return node;
416
+ }
417
+ /** This node and its descendants, in pre-order. */
418
+ *descendants() {
419
+ const cursor = this.walk();
420
+ while (true) {
421
+ yield cursor.node;
422
+ if (cursor.gotoFirstChild()) continue;
423
+ while (!cursor.gotoNextSibling()) if (!cursor.gotoParent()) return;
424
+ }
425
+ }
426
+ /** The descendants of the given kind, in pre-order. */
427
+ *descendantsOfKind(kind) {
428
+ for (const n of this.descendants()) if (n.kind === kind) yield n;
429
+ }
430
+ /** A cursor at this node, which cannot move above it. */
431
+ walk() {
432
+ return new TreeCursor(this);
433
+ }
434
+ /**
435
+ * The node as an S-expression of its named descendants, with field
436
+ * names, as Tree-sitter prints it: `(pair key: (name) value: (number))`.
437
+ */
438
+ toString() {
439
+ let out = "";
440
+ const visit = (green, field) => {
441
+ if (green.named || green === this.green) {
442
+ if (out.length > 0) out += " ";
443
+ if (field !== void 0) out += `${field}: `;
444
+ out += `(${green.kind}`;
445
+ for (let i = 0; i < green.children.length; i++) visit(green.children[i], green.fields?.[i]);
446
+ out += ")";
447
+ } else for (let i = 0; i < green.children.length; i++) visit(green.children[i], green.fields?.[i]);
448
+ };
449
+ visit(this.green, this.field);
450
+ return out;
451
+ }
452
+ toJSON() {
453
+ return {
454
+ kind: this.kind,
455
+ start: this.start,
456
+ end: this.end
457
+ };
458
+ }
459
+ makeChild(i) {
460
+ const green = this.green;
461
+ return new SyntaxNode(this.tree, green.children[i], this.start + green.offsets[i], this, i);
462
+ }
463
+ };
464
+ /** The smallest node, `root` or a descendant, that contains `[start, end)` (see `SyntaxNode.descendantAt`). */
465
+ const descendantOf = (root, start, end) => {
466
+ let node = root;
467
+ while (true) {
468
+ const i = node.childIndexAt(start);
469
+ if (i < 0) return node;
470
+ const child = node.children[i];
471
+ if (end > child.end) return node;
472
+ node = child;
473
+ }
474
+ };
475
+ /**
476
+ * A cursor for walking a tree, as Tree-sitter's `TreeCursor`. It starts at
477
+ * a node and cannot move above it.
478
+ *
479
+ * @since 0.2.0
480
+ * @category models
481
+ */
482
+ var TreeCursor = class {
483
+ current;
484
+ depth = 0;
485
+ /** @internal */
486
+ constructor(node) {
487
+ this.current = node;
488
+ }
489
+ /** The node at the cursor. */
490
+ get node() {
491
+ return this.current;
492
+ }
493
+ /** The field name of the node at the cursor, if any. */
494
+ get field() {
495
+ return this.depth === 0 ? void 0 : this.current.field;
496
+ }
497
+ /** Moves to the first child; `false` if there is none. */
498
+ gotoFirstChild() {
499
+ return this.goto(this.current.child(0));
500
+ }
501
+ /** Moves to the last child; `false` if there is none. */
502
+ gotoLastChild() {
503
+ return this.goto(this.current.child(-1));
504
+ }
505
+ /** Moves to the child containing the input unit at `offset`; `false` if there is none. */
506
+ gotoFirstChildForOffset(offset) {
507
+ return this.goto(this.current.childAt(offset));
508
+ }
509
+ /** Moves to the next sibling; `false` if there is none. */
510
+ gotoNextSibling() {
511
+ if (this.depth === 0) return false;
512
+ const next = this.current.nextSibling;
513
+ if (next === void 0) return false;
514
+ this.current = next;
515
+ return true;
516
+ }
517
+ /** Moves to the previous sibling; `false` if there is none. */
518
+ gotoPreviousSibling() {
519
+ if (this.depth === 0) return false;
520
+ const previous = this.current.previousSibling;
521
+ if (previous === void 0) return false;
522
+ this.current = previous;
523
+ return true;
524
+ }
525
+ /** Moves to the parent; `false` at the node the cursor started at. */
526
+ gotoParent() {
527
+ const parent = this.current.parent;
528
+ if (this.depth === 0 || parent === void 0) return false;
529
+ this.current = parent;
530
+ this.depth--;
531
+ return true;
532
+ }
533
+ /** Moves to the deepest node containing the input unit at `offset`. */
534
+ gotoDescendantAt(offset) {
535
+ while (this.gotoFirstChildForOffset(offset));
536
+ }
537
+ /** Starts again at `node`. */
538
+ reset(node) {
539
+ this.current = node;
540
+ this.depth = 0;
541
+ }
542
+ goto(node) {
543
+ if (node === void 0) return false;
544
+ this.current = node;
545
+ this.depth++;
546
+ return true;
547
+ }
548
+ };
549
+ const expectedEof = ["end of input"];
550
+ const run = (config, input, previous) => {
551
+ const state = new SyntaxState(input, { context: config.context }, previous);
552
+ const a = Stack.run(config.inner.step, state);
553
+ if (state.encoding === void 0 && previous !== void 0) state.encoding = previous.encoding;
554
+ let fatal;
555
+ let value = Option.none();
556
+ if (a === Fail) fatal = {
557
+ failure: state.reportedFailure(),
558
+ mode: state.mode
559
+ };
560
+ else if (state.pos < state.end) {
561
+ state.backtrack("Eof", expectedEof);
562
+ fatal = {
563
+ failure: state.reportedFailure(),
564
+ mode: "Backtrack"
565
+ };
566
+ } else value = Option.some(a);
567
+ const green = state.finish(config.kind, Option.getOrUndefined(value), fatal, state.pos);
568
+ return new Tree(input, value, state.reused, green, config, state.encoding);
569
+ };
570
+ /**
571
+ * Parses an input into a syntax {@link Tree}. The grammar's output is the
572
+ * tree's `value`, and its {@link node}s are the tree's nodes. When the
573
+ * grammar is itself a {@link node}, that node is the root; otherwise the
574
+ * root is a node of kind `options.kind` (by default `"document"`).
575
+ *
576
+ * The parse never fails: recovered failures (see `Parser.resumeAfter`), a
577
+ * fatal failure and unparsed input at the end all become `ERROR` nodes, and
578
+ * are listed in `tree.errors`. The parse is interpreted, never compiled.
579
+ *
580
+ * @since 0.2.0
581
+ * @category parsing
582
+ */
583
+ const parse = (grammar, input, options) => {
584
+ const n = nodeOf(grammar);
585
+ const isRoot = n._tag === "Syntax" && n.kind !== void 0 && n.named;
586
+ const config = {
587
+ kind: isRoot ? n.kind : options?.kind ?? "document",
588
+ inner: isRoot ? n.self : grammar,
589
+ lookahead: options?.lookahead ?? 0,
590
+ context: options?.context
591
+ };
592
+ return run(config, fromSource(input), void 0);
593
+ };
594
+ /**
595
+ * Parses the new version of a tree's input, reusing the nodes of the tree
596
+ * that the edits leave unchanged (Tree-sitter's `ts_tree_edit` followed by
597
+ * `ts_parser_parse` with the old tree). The result is the tree a fresh
598
+ * {@link parse} of `input` would build, but only the parts of the tree
599
+ * around the edits are parsed again. `tree.reused` says how many nodes were
600
+ * reused.
601
+ *
602
+ * `edits` describe how the old input became the new one, applied in order,
603
+ * each in the coordinates of the input as the previous edits left it. When
604
+ * they are omitted, the edit is found by comparing the inputs (their common
605
+ * prefix and suffix), which takes time linear in their length but much less
606
+ * than parsing.
607
+ *
608
+ * Errors in the new tree are those a fresh parse reports, except that an
609
+ * error just after a reused node may list fewer expected alternatives.
610
+ *
611
+ * @example
612
+ * ```ts
613
+ * import { Ascii, Syntax } from "@thomasfosterau/effect-parse"
614
+ *
615
+ * const number = Syntax.node(Ascii.decInt, "number")
616
+ * const tree = Syntax.parse(number, "12")
617
+ * Syntax.reparse(tree, "123", [{ start: 2, oldEnd: 2, newEnd: 3 }]).root.value // 123
618
+ * ```
619
+ *
620
+ * @since 0.2.0
621
+ * @category parsing
622
+ */
623
+ const reparse = (tree, input, edits) => {
624
+ const next = fromSource(input);
625
+ const list = edits === void 0 ? diffList(tree.input, next) : "start" in edits ? [edits] : edits;
626
+ const previous = {
627
+ root: tree.green,
628
+ oldLength: tree.input.length,
629
+ newLength: next.length,
630
+ segments: segmentsOf(tree.input.length, next.length, list),
631
+ input: tree.input,
632
+ extra: tree.config.lookahead,
633
+ encoding: tree.encoding
634
+ };
635
+ return run(tree.config, next, previous);
636
+ };
637
+ /**
638
+ * Replaces `[start, end)` of a tree's string input with `text` and parses
639
+ * the result incrementally (see {@link reparse}).
640
+ *
641
+ * @since 0.2.0
642
+ * @category parsing
643
+ */
644
+ const replace = (tree, start, end, text) => {
645
+ const input = tree.input;
646
+ if (start < 0 || end < start || end > input.length) throw new RangeError(`invalid range [${start}, ${end}) of an input of length ${input.length}`);
647
+ return reparse(tree, input.slice(0, start) + text + input.slice(end), {
648
+ start,
649
+ oldEnd: end,
650
+ newEnd: start + text.length
651
+ });
652
+ };
653
+ /**
654
+ * Finds the edit that turns `before` into `after`: the part between their
655
+ * longest common prefix and suffix. `undefined` when they are equal.
656
+ *
657
+ * @since 0.2.0
658
+ * @category parsing
659
+ */
660
+ const diff = (before, after) => {
661
+ const a = before;
662
+ const b = after;
663
+ const at = Predicate.isString(a) ? (s, i) => s.charCodeAt(i) : (s, i) => s[i];
664
+ const max = Math.min(a.length, b.length);
665
+ let prefix = 0;
666
+ while (prefix < max && at(a, prefix) === at(b, prefix)) prefix++;
667
+ if (prefix === a.length && prefix === b.length) return void 0;
668
+ let suffix = 0;
669
+ while (suffix < max - prefix && at(a, a.length - 1 - suffix) === at(b, b.length - 1 - suffix)) suffix++;
670
+ return {
671
+ start: prefix,
672
+ oldEnd: a.length - suffix,
673
+ newEnd: b.length - suffix
674
+ };
675
+ };
676
+ const diffList = (before, after) => {
677
+ const edit = diff(before, after);
678
+ return edit === void 0 ? [] : [edit];
679
+ };
680
+ /** The stretches of the new input copied unchanged from the old one. */
681
+ const segmentsOf = (oldLength, newLength, edits) => {
682
+ let segments = oldLength > 0 ? [{
683
+ newStart: 0,
684
+ oldStart: 0,
685
+ length: oldLength
686
+ }] : [];
687
+ let length = oldLength;
688
+ for (const { newEnd, oldEnd, start } of edits) {
689
+ if (!(start >= 0 && oldEnd >= start && oldEnd <= length && newEnd >= start)) throw new RangeError(`invalid edit { start: ${start}, oldEnd: ${oldEnd}, newEnd: ${newEnd} } of an input of length ${length}`);
690
+ const delta = newEnd - oldEnd;
691
+ const out = [];
692
+ for (const s of segments) {
693
+ const end = s.newStart + s.length;
694
+ if (s.newStart < start) out.push({
695
+ newStart: s.newStart,
696
+ oldStart: s.oldStart,
697
+ length: Math.min(end, start) - s.newStart
698
+ });
699
+ if (end > oldEnd) {
700
+ const from = Math.max(s.newStart, oldEnd);
701
+ out.push({
702
+ newStart: from + delta,
703
+ oldStart: s.oldStart + (from - s.newStart),
704
+ length: end - from
705
+ });
706
+ }
707
+ }
708
+ segments = out;
709
+ length += delta;
710
+ }
711
+ if (length !== newLength) throw new RangeError(`the edits give an input of length ${length}, but the new input has length ${newLength}`);
712
+ return segments;
713
+ };
714
+ //#endregion
715
+ export { ERROR, SyntaxNode, Tree, TreeCursor, diff, field, node, parse, reparse, replace, token };
716
+
717
+ //# sourceMappingURL=Syntax.js.map