tarsec 0.0.17 → 0.0.19

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.
package/README.md CHANGED
@@ -19,14 +19,14 @@ npm install tarsec
19
19
  ## Hello world
20
20
 
21
21
  ```ts
22
- import { getResults, str, seq, space } from "tarsec";
22
+ import { str, seqR, space } from "tarsec";
23
23
 
24
24
  // define a parser
25
- const parser = seq([
25
+ const parser = seqR(
26
26
  str("hello"),
27
27
  space,
28
28
  str("world")
29
- ], getResults);
29
+ );
30
30
 
31
31
  // then use it
32
32
  parser("hello world"); // success
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,359 @@
1
+ import { CaptureParser, GeneralParser, InferManyReturnType, MergedCaptures, MergedResults, Parser, ParserResult, PickParserType, PlainObject } from "./types.js";
2
+ /**
3
+ * Takes a parser and runs it zero or more times, returning the results as an array.
4
+ * If the parser is a capture parser, it returns the captures as an array in this form:
5
+ *
6
+ * ```ts
7
+ * { captures: <array of captures> }
8
+ * ```
9
+ *
10
+ * @param parser - parser to run
11
+ * @returns - parser that runs the given parser zero to many times,
12
+ * and returns the result as an array
13
+ */
14
+ export declare function many<const T extends GeneralParser<any, any>>(parser: T): InferManyReturnType<T>;
15
+ /**
16
+ * Same as `many`, but fails if the parser doesn't match at least once.
17
+ *
18
+ * @param parser - parser to run
19
+ * @returns a parser that runs the given parser one to many times,
20
+ */
21
+ export declare function many1<const T extends GeneralParser<any, any>>(parser: T): InferManyReturnType<T>;
22
+ /**
23
+ * Takes a parser, runs it, and returns the number of times it succeeded.
24
+ * @param parser - parser to run
25
+ * @returns - the number of times the parser succeeded.
26
+ */
27
+ export declare function count<T>(parser: Parser<T>): Parser<number>;
28
+ /**
29
+ * Takes a parser, runs it n times, and returns the results as an array.
30
+ * If it cannot run the parser n times, it fails without consuming input.
31
+ * @param num - number of times to run the parser
32
+ * @param parser - parser to run
33
+ * @returns - parser that runs the given parser `num` times and returns an array of the results
34
+ */
35
+ export declare function exactly<T>(num: number, parser: Parser<T>): Parser<T[]>;
36
+ /**
37
+ * Same as `many`, but joins the results into a single string.
38
+ *
39
+ * @param parser - parser to run. The parser must return a string as its result.
40
+ * @returns - parser that runs the given parser zero to many times,
41
+ * and returns the result as a single string
42
+ */
43
+ export declare function manyWithJoin<const T extends GeneralParser<string, any>>(parser: T): GeneralParser<string, any>;
44
+ /**
45
+ * Same as `many1`, but joins the results into a single string.
46
+ *
47
+ * @param parser - parser to run. The parser must return a string as its result.
48
+ * @returns - parser that runs the given parser one to many times,
49
+ * and returns the result as a single string
50
+ */
51
+ export declare function many1WithJoin(parser: Parser<string>): Parser<string>;
52
+ /**
53
+ * `or` takes an array of parsers and runs them sequentially.
54
+ * It returns the results of the first parser that succeeds.
55
+ * You can use `capture` in an `or`:
56
+ *
57
+ * ```ts
58
+ * const parser = or(capture(digit, "num"), capture(word, "name"));
59
+ * ```
60
+ *
61
+ * `or` supports backtracking by returning a `nextParser`:
62
+ *
63
+ * ```ts
64
+ * const parser = or(str("hello"), str("hello!"));
65
+ *
66
+ * // this will match the first parser
67
+ * const result = parser("hello");
68
+ *
69
+ * // but or returns the untried parsers as a new parser
70
+ * result.nextParser("hello!"); // works
71
+ *
72
+ * // result.nextParser is the same as or(str("hello!"))
73
+ * ```
74
+ *
75
+ * @param parsers - parsers to try
76
+ * @returns - a parser that tries each parser in order. Returns the result of the first parser that succeeds.
77
+ */
78
+ export declare function or<const T extends readonly GeneralParser<any, any>[]>(...parsers: T): PickParserType<T>;
79
+ /**
80
+ * Takes a parser and runs it. If the parser fails,
81
+ * optional returns a success with a null result.
82
+ *
83
+ * @param parser - parser to run
84
+ * @returns - a parser that runs the given parser.
85
+ * If it fails, returns a success with a null result.
86
+ */
87
+ export declare function optional<T>(parser: Parser<T>): Parser<T | null>;
88
+ /**
89
+ * Takes a parser and runs it. If the parser fails,
90
+ * `not` returns a success with a `null` result.
91
+ * If the parser succeeds, `not` returns a failure.
92
+ *
93
+ * @param parser - parser to run
94
+ * @returns - a parser that runs the given parser.
95
+ * If it fails, returns a success with a `null` result.
96
+ * If it succeeds, returns a failure.
97
+ */
98
+ export declare function not(parser: Parser<any>): Parser<null>;
99
+ /**
100
+ * Takes three parsers, `open`, `close`, and `parser`.
101
+ * `between` matches something that matches `parser`,
102
+ * surrounded by `open` and `close`. It returns the result of `parser`.
103
+ * If any of the parsers fail, `between` fails.
104
+ *
105
+ * @param open - parser for the opening delimiter
106
+ * @param close - parser for the closing delimiter
107
+ * @param parser - parser for the content
108
+ * @returns a parser that returns the result of `parser`.
109
+ */
110
+ export declare function between<O, C, P>(open: Parser<O>, close: Parser<C>, parser: Parser<P>): Parser<P>;
111
+ /**
112
+ * Parses many instances of the parser separated by separator.
113
+ * @param separator
114
+ * @param parser
115
+ * @returns a parser that runs the given parser zero to many times, separated by the separator parser.
116
+ */
117
+ export declare function sepBy<S, P>(separator: Parser<S>, parser: Parser<P>): Parser<P[]>;
118
+ /**
119
+ * Convenience function to use as the second argument to `seq` to get all the results from `seq`
120
+ * @param results
121
+ * @param captures
122
+ * @returns `results`
123
+ */
124
+ export declare function getResults<R, C>(results: R, captures: C): R;
125
+ /**
126
+ * Convenience function to use as the second argument to seq to get all the captures.
127
+ * @param results
128
+ * @param captures
129
+ * @returns `captures`
130
+ */
131
+ export declare function getCaptures<R, C>(results: R, captures: C): C;
132
+ /**
133
+ * `capture` is the only way to create a capture. Given a parser and a name,
134
+ * `capture` runs the parser and saves its result in a captures object
135
+ * with the given name as the key. It returns the result from the parser,
136
+ * and attaches the captures object along with it.
137
+ *
138
+ * @param parser - parser to run
139
+ * @param name - name of the capture
140
+ * @returns - the results of the parser, with the captures object attached.
141
+ */
142
+ export declare function capture<T, const S extends string>(parser: Parser<T>, name: S): CaptureParser<T, Record<S, T>>;
143
+ /**
144
+ * `captureCaptures` lifts your captures up a level. Suppose you have a parser like this:
145
+ *
146
+ * ```ts
147
+ * const greeting = seqC(
148
+ * str("hello"),
149
+ * spaces,
150
+ * capture(word, "name"),
151
+ * str("!"),
152
+ * spaces,
153
+ * capture(manynTillStr("?"), "secondPart")
154
+ * )
155
+ *
156
+ * This parses a greeting like "hello Adit! How was your day?" into:
157
+ *
158
+ * ```ts
159
+ * {
160
+ * name: "Adit",
161
+ * secondPart: "How was your day?"
162
+ * }
163
+ * ```
164
+ *
165
+ * Now, suppose you decide to refactor this parser into two parsers:
166
+ *
167
+ * ```ts
168
+ * const firstPart = seqC(
169
+ * str("hello"),
170
+ * spaces,
171
+ * capture(word, "name"),
172
+ * str("!")
173
+ * )
174
+ *
175
+ * const secondPart = seqC(
176
+ * spaces,
177
+ * capture(manyTillStr("?"), "secondPart")
178
+ * )
179
+ * ```
180
+ *
181
+ * And put them together:
182
+ *
183
+ * ```ts
184
+ * const greeting = seqC(
185
+ * firstPart,
186
+ * secondPart
187
+ * )
188
+ * ```
189
+ *
190
+ * Unfortunately, this will no longer return an object in that shape,
191
+ * because it's not actually capturing anything. Captures in `firstPart`
192
+ * and `secondPart` won't get propagated up. Suppose you try to use `capture` like this:
193
+ * ```ts
194
+ * const greeting = seqC(
195
+ * capture(firstPart, "firstPart"),
196
+ * capture(secondPart, "secondPart")
197
+ * )
198
+ * ```
199
+ * Now you'll get an object that looks like this instead:
200
+ *
201
+ * ```ts
202
+ * {
203
+ * firstPart: {
204
+ * name: "Adit"
205
+ * },
206
+ * secondPart: {
207
+ * secondPart: "How was your day?"
208
+ * }
209
+ * }
210
+ * ```
211
+ *
212
+ * What you want is for the captures in the child parsers to get merged up to the parent parser. For that, use `captureCaptures`:
213
+ *
214
+ * ```ts
215
+ * const greeting = seqC(
216
+ * captureCaptures(firstPart),
217
+ * captureCaptures(secondPart)
218
+ * )
219
+ * ```
220
+ * @param parser - parser to capture captures from
221
+ * @returns - the parser's result set as the captures object
222
+ */
223
+ export declare function captureCaptures<T extends PlainObject>(parser: Parser<T>): CaptureParser<T, T>;
224
+ /**
225
+ * Returns a parser that consumes input till the given parser succeeds.
226
+ * @param parser - the stop parser
227
+ * @returns a parser that consumes the input string until the stop parser succeeds.
228
+ * Then it returns the consumed input as a string.
229
+ * The stop parser's match is not included in the result.
230
+ */
231
+ export declare function manyTill<T>(parser: Parser<T>): Parser<string>;
232
+ /**
233
+ * Just like `manyTill`, but fails unless at least one character of input is consumed.
234
+ * @param parser - the stop parser
235
+ * @returns a parser that consumes the input string until the stop parser succeeds.
236
+ */
237
+ export declare function many1Till<T>(parser: Parser<T>): Parser<string>;
238
+ /**
239
+ * `manyTillOneOf` is an optimized version of `manyTill`.
240
+ * The `manyTill` combinator is slow because it runs the given parser
241
+ * on every character of the string until it succeeds. However, if you
242
+ * just want to consume input until you get to a substring,
243
+ * use `manyTillOneOf`. It uses `indexOf`, which is significantly faster
244
+ * than running a parser over every character.
245
+ *
246
+ * Given an array of strings, this parser consumes input until it hits one of those strings.
247
+ * If none of the strings is found, the parser will consume all input and return success.
248
+ *
249
+ * @param str - the string to stop at
250
+ * @param options - object of optional parameters. { insensitive: boolean }
251
+ * @returns a parser that consumes the input string until one of the given strings is found.
252
+ */
253
+ export declare function manyTillOneOf(stops: string[], { insensitive }?: {
254
+ insensitive?: boolean;
255
+ }): Parser<string>;
256
+ /**
257
+ * `manyTillStr` is an optimized version of `manyTill`.
258
+ * The `manyTill` combinator is slow because it runs the given parser
259
+ * on every character of the string until it succeeds. However, if you
260
+ * just want to consume input until you get to a substring,
261
+ * use `manyTillStr`. It uses `indexOf`, which is significantly faster
262
+ * than running a parser over every character.
263
+ *
264
+ * @param str - the string to stop at
265
+ * @param options - object of optional parameters. { insensitive: boolean }
266
+ * @returns a parser that consumes the input string until the given string is found.
267
+ */
268
+ export declare function manyTillStr(str: string, { insensitive }?: {
269
+ insensitive?: boolean;
270
+ }): Parser<string>;
271
+ /**
272
+ * Like `manyTillStr`, but case insensitive.
273
+ * @param str - the string to stop at
274
+ * @returns a parser that consumes the input string until the given string is found.
275
+ */
276
+ export declare function iManyTillStr(str: string): Parser<string>;
277
+ /**
278
+ * `map` is a parser combinator that takes a parser and a mapper function.
279
+ * If the parser succeeds, it maps its result using the mapper function.
280
+ * You can think of map as a general `map`, like for functors, applied to a parser.
281
+ * Since `map` itself is a parser, you can use it in `seq` or other combinators.
282
+ *
283
+ * @param parser - parser to run
284
+ * @param mapperFunc - function to map the result of the parser
285
+ * @returns
286
+ */
287
+ export declare function map<R, C extends PlainObject, X>(parser: GeneralParser<R, C>, mapperFunc: (x: R) => X): GeneralParser<X, C>;
288
+ /**
289
+ * Given a parser that returns a string, `search` looks for all substrings in a string that match that parser.
290
+ * For example, given a parser that matches quoted strings, `search` will return an array of all the quoted strings
291
+ * it finds in the input, as an array.
292
+ *
293
+ * The rest of the input that isn't part of the result is simply joined together and returned as a string.
294
+ * If you need a more structured result + rest, you can use `within` instead.
295
+ *
296
+ * @param parser - a parser that returns a string
297
+ * @returns - a parser that returns an array of strings
298
+ */
299
+ export declare function search(parser: Parser<string>): Parser<string[]>;
300
+ /**
301
+ * seq takes an array of parsers and runs them sequentially.
302
+ * If any of the parsers fail, seq fails without consuming any input.
303
+ *
304
+ * The second argument to seq is a function.
305
+ * The first argument of that function is an array of results:
306
+ * one result from each of the parsers you gave to seq.
307
+ * The second is an object containing any captures.
308
+ * You can use this second argument, the transformer function,
309
+ * to transform these however you want and return a result
310
+ *
311
+ * Tarsec includes the utility functions `getResults` and `getCaptures`
312
+ * to just return the results array or captures object respectively for you.
313
+ *
314
+ * Finally, you don't need to use seq at all. You can just hand write the logic.
315
+ * But you'll need to do the error handling
316
+ * and pass the remaining input to the next parser yourself.
317
+ * seq also does some backtracking for you that you will need to do yourself.
318
+ *
319
+ * Also see `seqR` and `seqC` for convenience functions that return the results or captures respectively.
320
+ *
321
+ * @param parsers - parsers to run sequentially
322
+ * @param transform - function to transform the results and captures. The params are the results and captures
323
+ * @param debugName - optional name for trace debugging
324
+ * @returns
325
+ */
326
+ export declare function seq<const T extends readonly GeneralParser<any, any>[], U>(parsers: T, transform: (results: MergedResults<T>[], captures: MergedCaptures<T>) => U, debugName?: string): Parser<U>;
327
+ /** Just like seq except it returns the results.
328
+ * It's like using `seq([parsers], getResults)`.
329
+ */
330
+ export declare function seqR<const T extends readonly GeneralParser<any, any>[]>(...parsers: T): Parser<MergedResults<T>[]>;
331
+ /** Just like seq except it returns the captures.
332
+ * It's like using `seq([parsers], getCaptures)`.
333
+ */
334
+ export declare function seqC<const T extends readonly GeneralParser<any, any>[]>(...parsers: T): Parser<MergedCaptures<T>>;
335
+ /**
336
+ * Match takes an input string and a parser. If the parser matches the input string
337
+ * and consumes the entire input string, `match` returns `true`. Otherwise it returns `false`.
338
+ *
339
+ * @param input - input string
340
+ * @param parser - parser to match input against
341
+ * @returns - true if the parser matches the input and consumes all input, false otherwise
342
+ */
343
+ export declare function match(input: string, parser: GeneralParser<any, any>): boolean;
344
+ export declare function ifElse<const IF extends GeneralParser<any, any>, const ELSE extends GeneralParser<any, any>, I = string>(condition: boolean, ifParser: IF, elseParser: ELSE): IF | ELSE;
345
+ /**
346
+ * Apply multiple parsers to the same input and collect all the results.
347
+ * Consumes no input.
348
+ *
349
+ * @param parsers - parsers to try
350
+ * @returns
351
+ */
352
+ export declare function manyParsers<const T extends readonly GeneralParser<any, any>[]>(...parsers: T): Parser<ParserResult<MergedResults<T>>[]>;
353
+ /**
354
+ * Runs all the given parsers. If they all succeed, returns their results as an array.
355
+ * Otherwise fails. Consumes no input.
356
+ * @param parsers - parsers to try
357
+ * @returns - An array of results, or a failure.
358
+ */
359
+ export declare function and<const T extends readonly GeneralParser<any, any>[]>(...parsers: T): PickParserType<T>;