tarsec 0.0.13 → 0.0.14

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
@@ -41,7 +41,11 @@ parser("hello there"); // failure
41
41
  ## Features
42
42
  - tarsec is entirely TypeScript. There's nothing to compile.
43
43
  - [Debug mode](/tutorials/debugging.md) that prints what's happening step-by-step
44
+ - Tools to debug your parser's [performance](/tutorials/performance.md)
44
45
  - Derived types: tarsec will generate TypeScript types for your parser
45
46
  - Partial [backtracking](/tutorials/backtracking.md) support
46
47
 
47
- Read more about [use cases for tarsec](/tutorials/use-case.md).
48
+ Read more about [use cases for tarsec](/tutorials/use-case.md).
49
+
50
+ ## Contributing
51
+ PRs for documentation, tests, and bug fixes are welcome.
@@ -7,7 +7,6 @@ import { CaptureParser, GeneralParser, InferManyReturnType, MergedCaptures, Merg
7
7
  * { captures: <array of captures> }
8
8
  * ```
9
9
  *
10
- * Fails on empty strings
11
10
  * @param parser - parser to run
12
11
  * @returns - parser that runs the given parser zero to many times,
13
12
  * and returns the result as an array
@@ -20,6 +19,12 @@ export declare function many<const T extends GeneralParser<any, any>>(parser: T)
20
19
  * @returns a parser that runs the given parser one to many times,
21
20
  */
22
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<T[]>;
23
28
  /**
24
29
  * Takes a parser, runs it n times, and returns the results as an array.
25
30
  * If it cannot run the parser n times, it fails without consuming input.
@@ -27,7 +32,7 @@ export declare function many1<const T extends GeneralParser<any, any>>(parser: T
27
32
  * @param parser - parser to run
28
33
  * @returns - parser that runs the given parser `num` times and returns an array of the results
29
34
  */
30
- export declare function count<T>(num: number, parser: Parser<T>): Parser<T[]>;
35
+ export declare function exactly<T>(num: number, parser: Parser<T>): Parser<T[]>;
31
36
  /**
32
37
  * Same as `many`, but joins the results into a single string.
33
38
  *
@@ -103,9 +108,37 @@ export declare function not(parser: Parser<any>): Parser<null>;
103
108
  * @returns a parser that returns the result of `parser`.
104
109
  */
105
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
+ */
106
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
+ */
107
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
+ */
108
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
+ */
109
142
  export declare function capture<T, const S extends string>(parser: Parser<T>, name: S): CaptureParser<T, Record<S, T>>;
110
143
  /**
111
144
  * Returns a parser that consumes input till the given parser succeeds.
@@ -115,9 +148,55 @@ export declare function capture<T, const S extends string>(parser: Parser<T>, na
115
148
  * The stop parser's match is not included in the result.
116
149
  */
117
150
  export declare function manyTill<T>(parser: Parser<T>): Parser<string>;
151
+ /**
152
+ * Just like `manyTill`, but fails unless at least one character of input is consumed.
153
+ * @param parser - the stop parser
154
+ * @returns a parser that consumes the input string until the stop parser succeeds.
155
+ */
118
156
  export declare function many1Till<T>(parser: Parser<T>): Parser<string>;
119
- export declare function manyTillStr(str: string): Parser<string>;
120
- export declare function transform<R, C extends PlainObject, X>(parser: GeneralParser<R, C>, transformerFunc: (x: R) => X): GeneralParser<X, C>;
157
+ /**
158
+ * `manyTillStr` is an optimized version of `manyTill`.
159
+ * The `manyTill` combinator is slow because it runs the given parser
160
+ * on every character of the string until it succeeds. However, if you
161
+ * just want to consume input until you get to a substring,
162
+ * use `manyTillStr`. It uses `indexOf`, which is significantly faster
163
+ * than running a parser over every character.
164
+ *
165
+ * @param str - the string to stop at
166
+ * @param options - object of optional parameters. { caseInsensitive: boolean }
167
+ * @returns a parser that consumes the input string until the given string is found.
168
+ */
169
+ export declare function manyTillStr(str: string, { caseInsensitive }?: {
170
+ caseInsensitive?: boolean;
171
+ }): Parser<string>;
172
+ /**
173
+ * Like `manyTillStr`, but case insensitive.
174
+ * @param str - the string to stop at
175
+ * @returns a parser that consumes the input string until the given string is found.
176
+ */
177
+ export declare function iManyTillStr(str: string): Parser<string>;
178
+ /**
179
+ * `map` is a parser combinator that takes a parser and a mapper function.
180
+ * If the parser succeeds, it maps its result using the mapper function.
181
+ * You can think of map as a general `map`, like for functors, applied to a parser.
182
+ * Since `map` itself is a parser, you can use it in `seq` or other combinators.
183
+ *
184
+ * @param parser - parser to run
185
+ * @param mapperFunc - function to map the result of the parser
186
+ * @returns
187
+ */
188
+ export declare function map<R, C extends PlainObject, X>(parser: GeneralParser<R, C>, mapperFunc: (x: R) => X): GeneralParser<X, C>;
189
+ /**
190
+ * Given a parser that returns a string, `search` looks for all substrings in a string that match that parser.
191
+ * For example, given a parser that matches quoted strings, `search` will return an array of all the quoted strings
192
+ * it finds in the input, as an array.
193
+ *
194
+ * The rest of the input that isn't part of the result is simply joined together and returned as a string.
195
+ * If you need a more structured result + rest, you can use `within` instead.
196
+ *
197
+ * @param parser - a parser that returns a string
198
+ * @returns - a parser that returns an array of strings
199
+ */
121
200
  export declare function search(parser: Parser<string>): Parser<string[]>;
122
201
  /**
123
202
  * seq takes an array of parsers and runs them sequentially.
@@ -146,6 +225,20 @@ export declare function search(parser: Parser<string>): Parser<string[]>;
146
225
  * @returns
147
226
  */
148
227
  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>;
228
+ /** Just like seq except it returns the results.
229
+ * It's like using `seq([parsers], getResults)`.
230
+ */
149
231
  export declare function seqR<const T extends readonly GeneralParser<any, any>[]>(...parsers: T): Parser<MergedResults<T>[]>;
232
+ /** Just like seq except it returns the captures.
233
+ * It's like using `seq([parsers], getCaptures)`.
234
+ */
150
235
  export declare function seqC<const T extends readonly GeneralParser<any, any>[]>(...parsers: T): Parser<MergedCaptures<T>>;
236
+ /**
237
+ * Match takes an input string and a parser. If the parser matches the input string
238
+ * and consumes the entire input string, `match` returns `true`. Otherwise it returns `false`.
239
+ *
240
+ * @param input - input string
241
+ * @param parser - parser to match input against
242
+ * @returns - true if the parser matches the input and consumes all input, false otherwise
243
+ */
151
244
  export declare function match(input: string, parser: GeneralParser<any, any>): boolean;
@@ -9,7 +9,7 @@
9
9
  })(function (require, exports) {
10
10
  "use strict";
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.match = exports.seqC = exports.seqR = exports.seq = exports.search = exports.transform = exports.manyTillStr = exports.many1Till = exports.manyTill = exports.capture = exports.getCaptures = exports.getResults = exports.sepBy = exports.between = exports.not = exports.optional = exports.or = exports.many1WithJoin = exports.manyWithJoin = exports.count = exports.many1 = exports.many = void 0;
12
+ exports.match = exports.seqC = exports.seqR = exports.seq = exports.search = exports.map = exports.iManyTillStr = exports.manyTillStr = exports.many1Till = exports.manyTill = exports.capture = exports.getCaptures = exports.getResults = exports.sepBy = exports.between = exports.not = exports.optional = exports.or = exports.many1WithJoin = exports.manyWithJoin = exports.exactly = exports.count = exports.many1 = exports.many = void 0;
13
13
  const within_1 = require("./parsers/within");
14
14
  const trace_1 = require("./trace");
15
15
  const types_1 = require("./types");
@@ -22,7 +22,6 @@
22
22
  * { captures: <array of captures> }
23
23
  * ```
24
24
  *
25
- * Fails on empty strings
26
25
  * @param parser - parser to run
27
26
  * @returns - parser that runs the given parser zero to many times,
28
27
  * and returns the result as an array
@@ -81,6 +80,21 @@
81
80
  });
82
81
  }
83
82
  exports.many1 = many1;
83
+ /**
84
+ * Takes a parser, runs it, and returns the number of times it succeeded.
85
+ * @param parser - parser to run
86
+ * @returns - the number of times the parser succeeded.
87
+ */
88
+ function count(parser) {
89
+ return (0, trace_1.trace)("count", (input) => {
90
+ const result = many(parser)(input);
91
+ if (result.success) {
92
+ return (0, types_1.success)(result.result.length, result.rest);
93
+ }
94
+ return result;
95
+ });
96
+ }
97
+ exports.count = count;
84
98
  /**
85
99
  * Takes a parser, runs it n times, and returns the results as an array.
86
100
  * If it cannot run the parser n times, it fails without consuming input.
@@ -88,8 +102,8 @@
88
102
  * @param parser - parser to run
89
103
  * @returns - parser that runs the given parser `num` times and returns an array of the results
90
104
  */
91
- function count(num, parser) {
92
- return (0, trace_1.trace)("count", (input) => {
105
+ function exactly(num, parser) {
106
+ return (0, trace_1.trace)("exactly", (input) => {
93
107
  let results = [];
94
108
  let rest = input;
95
109
  for (let i = 0; i < num; i++) {
@@ -103,7 +117,7 @@
103
117
  return (0, types_1.success)(results, rest);
104
118
  });
105
119
  }
106
- exports.count = count;
120
+ exports.exactly = exactly;
107
121
  /**
108
122
  * Same as `many`, but joins the results into a single string.
109
123
  *
@@ -251,6 +265,12 @@
251
265
  };
252
266
  }
253
267
  exports.between = between;
268
+ /**
269
+ * Parses many instances of the parser separated by separator.
270
+ * @param separator
271
+ * @param parser
272
+ * @returns a parser that runs the given parser zero to many times, separated by the separator parser.
273
+ */
254
274
  function sepBy(separator, parser) {
255
275
  return (input) => {
256
276
  let results = [];
@@ -271,14 +291,36 @@
271
291
  };
272
292
  }
273
293
  exports.sepBy = sepBy;
294
+ /**
295
+ * Convenience function to use as the second argument to `seq` to get all the results from `seq`
296
+ * @param results
297
+ * @param captures
298
+ * @returns `results`
299
+ */
274
300
  function getResults(results, captures) {
275
301
  return results;
276
302
  }
277
303
  exports.getResults = getResults;
304
+ /**
305
+ * Convenience function to use as the second argument to seq to get all the captures.
306
+ * @param results
307
+ * @param captures
308
+ * @returns `captures`
309
+ */
278
310
  function getCaptures(results, captures) {
279
311
  return captures;
280
312
  }
281
313
  exports.getCaptures = getCaptures;
314
+ /**
315
+ * `capture` is the only way to create a capture. Given a parser and a name,
316
+ * `capture` runs the parser and saves its result in a captures object
317
+ * with the given name as the key. It returns the result from the parser,
318
+ * and attaches the captures object along with it.
319
+ *
320
+ * @param parser - parser to run
321
+ * @param name - name of the capture
322
+ * @returns - the results of the parser, with the captures object attached.
323
+ */
282
324
  function capture(parser, name) {
283
325
  return (0, trace_1.trace)(`capture(${(0, utils_1.escape)(name)})`, (input) => {
284
326
  let result = parser(input);
@@ -313,6 +355,11 @@
313
355
  };
314
356
  }
315
357
  exports.manyTill = manyTill;
358
+ /**
359
+ * Just like `manyTill`, but fails unless at least one character of input is consumed.
360
+ * @param parser - the stop parser
361
+ * @returns a parser that consumes the input string until the stop parser succeeds.
362
+ */
316
363
  function many1Till(parser) {
317
364
  return (input) => {
318
365
  let current = 0;
@@ -333,9 +380,23 @@
333
380
  };
334
381
  }
335
382
  exports.many1Till = many1Till;
336
- function manyTillStr(str) {
383
+ /**
384
+ * `manyTillStr` is an optimized version of `manyTill`.
385
+ * The `manyTill` combinator is slow because it runs the given parser
386
+ * on every character of the string until it succeeds. However, if you
387
+ * just want to consume input until you get to a substring,
388
+ * use `manyTillStr`. It uses `indexOf`, which is significantly faster
389
+ * than running a parser over every character.
390
+ *
391
+ * @param str - the string to stop at
392
+ * @param options - object of optional parameters. { caseInsensitive: boolean }
393
+ * @returns a parser that consumes the input string until the given string is found.
394
+ */
395
+ function manyTillStr(str, { caseInsensitive = false } = {}) {
337
396
  return (0, trace_1.trace)(`manyTillStr(${str})`, (input) => {
338
- const index = input.indexOf(str);
397
+ const index = caseInsensitive
398
+ ? input.toLocaleLowerCase().indexOf(str.toLocaleLowerCase())
399
+ : input.indexOf(str);
339
400
  if (index === -1) {
340
401
  return (0, types_1.success)(input, "");
341
402
  }
@@ -343,16 +404,46 @@
343
404
  });
344
405
  }
345
406
  exports.manyTillStr = manyTillStr;
346
- function transform(parser, transformerFunc) {
347
- return (0, trace_1.trace)(`transform(${transformerFunc})`, (input) => {
407
+ /**
408
+ * Like `manyTillStr`, but case insensitive.
409
+ * @param str - the string to stop at
410
+ * @returns a parser that consumes the input string until the given string is found.
411
+ */
412
+ function iManyTillStr(str) {
413
+ return manyTillStr(str, { caseInsensitive: true });
414
+ }
415
+ exports.iManyTillStr = iManyTillStr;
416
+ /**
417
+ * `map` is a parser combinator that takes a parser and a mapper function.
418
+ * If the parser succeeds, it maps its result using the mapper function.
419
+ * You can think of map as a general `map`, like for functors, applied to a parser.
420
+ * Since `map` itself is a parser, you can use it in `seq` or other combinators.
421
+ *
422
+ * @param parser - parser to run
423
+ * @param mapperFunc - function to map the result of the parser
424
+ * @returns
425
+ */
426
+ function map(parser, mapperFunc) {
427
+ return (0, trace_1.trace)(`map(${mapperFunc})`, (input) => {
348
428
  let parsed = parser(input);
349
429
  if (parsed.success) {
350
- return Object.assign(Object.assign({}, parsed), { result: transformerFunc(parsed.result) });
430
+ return Object.assign(Object.assign({}, parsed), { result: mapperFunc(parsed.result) });
351
431
  }
352
432
  return parsed;
353
433
  });
354
434
  }
355
- exports.transform = transform;
435
+ exports.map = map;
436
+ /**
437
+ * Given a parser that returns a string, `search` looks for all substrings in a string that match that parser.
438
+ * For example, given a parser that matches quoted strings, `search` will return an array of all the quoted strings
439
+ * it finds in the input, as an array.
440
+ *
441
+ * The rest of the input that isn't part of the result is simply joined together and returned as a string.
442
+ * If you need a more structured result + rest, you can use `within` instead.
443
+ *
444
+ * @param parser - a parser that returns a string
445
+ * @returns - a parser that returns an array of strings
446
+ */
356
447
  function search(parser) {
357
448
  return (0, trace_1.trace)("search", (input) => {
358
449
  let parsed = (0, within_1.within)(parser)(input);
@@ -503,14 +594,28 @@
503
594
  });
504
595
  }
505
596
  exports.seq = seq;
597
+ /** Just like seq except it returns the results.
598
+ * It's like using `seq([parsers], getResults)`.
599
+ */
506
600
  function seqR(...parsers) {
507
601
  return seq(parsers, getResults);
508
602
  }
509
603
  exports.seqR = seqR;
604
+ /** Just like seq except it returns the captures.
605
+ * It's like using `seq([parsers], getCaptures)`.
606
+ */
510
607
  function seqC(...parsers) {
511
608
  return seq(parsers, getCaptures);
512
609
  }
513
610
  exports.seqC = seqC;
611
+ /**
612
+ * Match takes an input string and a parser. If the parser matches the input string
613
+ * and consumes the entire input string, `match` returns `true`. Otherwise it returns `false`.
614
+ *
615
+ * @param input - input string
616
+ * @param parser - parser to match input against
617
+ * @returns - true if the parser matches the input and consumes all input, false otherwise
618
+ */
514
619
  function match(input, parser) {
515
620
  const result = parser(input);
516
621
  return result.success && result.rest === "";
package/dist/parsers.d.ts CHANGED
@@ -10,10 +10,16 @@ export declare function char<const S extends string>(c: S): Parser<S>;
10
10
  /**
11
11
  * Takes a string. Returns a parser that parses that string.
12
12
  *
13
- * @param s - string to parse
13
+ * @param s - string to match on
14
14
  * @returns - parser that parses the given string
15
15
  */
16
16
  export declare function str<const S extends string>(s: S): Parser<S>;
17
+ /**
18
+ * Like `str`, but case insensitive.
19
+ * @param s - string to match on, case insensitive
20
+ * @returns - parser that matches the given string, case insensitive
21
+ */
22
+ export declare function istr<const S extends string>(s: S): Parser<S>;
17
23
  /**
18
24
  * Takes a string. Returns a parser that parses
19
25
  * one of the characters in that string.
@@ -44,11 +50,11 @@ export declare const space: Parser<string>;
44
50
  export declare const spaces: Parser<string>;
45
51
  /** A parser that matches one digit. */
46
52
  export declare const digit: Parser<string>;
47
- /** A parser that matches one letter, currently lowercase only. */
53
+ /** A parser that matches one letter, case insensitive. */
48
54
  export declare const letter: Parser<string>;
49
- /** A parser that matches one digit or letter, currently lowercase only. */
55
+ /** A parser that matches one digit or letter, case insensitive. */
50
56
  export declare const alphanum: Parser<string>;
51
- /** A parser that matches one lowercase word. */
57
+ /** A parser that matches one word, case insensitive. */
52
58
  export declare const word: Parser<string>;
53
59
  /** A parser that matches one or more digits. */
54
60
  export declare const num: Parser<string>;
@@ -64,4 +70,13 @@ export declare const eof: Parser<null>;
64
70
  * Returns the string as the result, including the quotes.
65
71
  */
66
72
  export declare const quotedString: Parser<string>;
67
- export declare function regexParser(str: string | RegExp): Parser<string>;
73
+ /**
74
+ * Returns a parser that matches a regex. If you pass in a string,
75
+ * it will get converted to a regex. The regex should always match from the start of the input.
76
+ * If you pass in a string, a `^` will get prepended to it.
77
+ *
78
+ * @param str - regex string or RegExp instance to match
79
+ * @param options - regex options (i = ignore case, g = global, m = multiline, u = unicode)
80
+ * @returns - parser that matches the given regex
81
+ */
82
+ export declare function regexParser(str: string | RegExp, options?: string): Parser<string>;
package/dist/parsers.js CHANGED
@@ -9,7 +9,7 @@
9
9
  })(function (require, exports) {
10
10
  "use strict";
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.regexParser = exports.quotedString = exports.eof = exports.newline = exports.tab = exports.quote = exports.num = exports.word = exports.alphanum = exports.letter = exports.digit = exports.spaces = exports.space = exports.anyChar = exports.noneOf = exports.oneOf = exports.str = exports.char = exports.betweenWithin = void 0;
12
+ exports.regexParser = exports.quotedString = exports.eof = exports.newline = exports.tab = exports.quote = exports.num = exports.word = exports.alphanum = exports.letter = exports.digit = exports.spaces = exports.space = exports.anyChar = exports.noneOf = exports.oneOf = exports.istr = exports.str = exports.char = exports.betweenWithin = void 0;
13
13
  const combinators_1 = require("./combinators");
14
14
  const trace_1 = require("./trace");
15
15
  const types_1 = require("./types");
@@ -41,7 +41,7 @@
41
41
  /**
42
42
  * Takes a string. Returns a parser that parses that string.
43
43
  *
44
- * @param s - string to parse
44
+ * @param s - string to match on
45
45
  * @returns - parser that parses the given string
46
46
  */
47
47
  function str(s) {
@@ -53,6 +53,20 @@
53
53
  });
54
54
  }
55
55
  exports.str = str;
56
+ /**
57
+ * Like `str`, but case insensitive.
58
+ * @param s - string to match on, case insensitive
59
+ * @returns - parser that matches the given string, case insensitive
60
+ */
61
+ function istr(s) {
62
+ return (0, trace_1.trace)(`istr(${(0, utils_1.escape)(s)})`, (input) => {
63
+ if (input.substring(0, s.length).toLocaleLowerCase() === s.toLocaleLowerCase()) {
64
+ return (0, types_1.success)(input.substring(0, s.length), input.slice(s.length));
65
+ }
66
+ return (0, types_1.failure)(`expected ${s}, got ${input.substring(0, s.length)}`, input);
67
+ });
68
+ }
69
+ exports.istr = istr;
56
70
  /**
57
71
  * Takes a string. Returns a parser that parses
58
72
  * one of the characters in that string.
@@ -111,14 +125,14 @@
111
125
  exports.spaces = (0, combinators_1.many1WithJoin)(exports.space);
112
126
  /** A parser that matches one digit. */
113
127
  exports.digit = oneOf("0123456789");
114
- /** A parser that matches one letter, currently lowercase only. */
115
- exports.letter = oneOf("abcdefghijklmnopqrstuvwxyz");
116
- /** A parser that matches one digit or letter, currently lowercase only. */
117
- exports.alphanum = oneOf("abcdefghijklmnopqrstuvwxyz0123456789");
118
- /** A parser that matches one lowercase word. */
119
- exports.word = (0, combinators_1.many1WithJoin)(exports.letter);
128
+ /** A parser that matches one letter, case insensitive. */
129
+ exports.letter = oneOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
130
+ /** A parser that matches one digit or letter, case insensitive. */
131
+ exports.alphanum = oneOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
132
+ /** A parser that matches one word, case insensitive. */
133
+ exports.word = regexParser("^[a-z]+", "ui");
120
134
  /** A parser that matches one or more digits. */
121
- exports.num = (0, combinators_1.many1WithJoin)(exports.digit);
135
+ exports.num = regexParser("^[0-9]+");
122
136
  /** A parser that matches one single or double quote. */
123
137
  exports.quote = oneOf(`'"`);
124
138
  /** A parser that matches one tab character. */
@@ -137,8 +151,23 @@
137
151
  * Returns the string as the result, including the quotes.
138
152
  */
139
153
  exports.quotedString = (0, combinators_1.seq)([exports.quote, (0, combinators_1.manyWithJoin)(noneOf(`"'`)), exports.quote], (results) => results.join(""));
140
- function regexParser(str) {
141
- const re = typeof str === "string" ? new RegExp(`^(${str})`) : str;
154
+ /**
155
+ * Returns a parser that matches a regex. If you pass in a string,
156
+ * it will get converted to a regex. The regex should always match from the start of the input.
157
+ * If you pass in a string, a `^` will get prepended to it.
158
+ *
159
+ * @param str - regex string or RegExp instance to match
160
+ * @param options - regex options (i = ignore case, g = global, m = multiline, u = unicode)
161
+ * @returns - parser that matches the given regex
162
+ */
163
+ function regexParser(str, options = "") {
164
+ let re;
165
+ if (typeof str === "string") {
166
+ re = new RegExp(str.startsWith("^") ? str : `^${str}`, options);
167
+ }
168
+ else {
169
+ re = str;
170
+ }
142
171
  return (0, trace_1.trace)(`regex(${str})`, (input) => {
143
172
  const match = input.match(re);
144
173
  if (match) {
package/dist/trace.d.ts CHANGED
@@ -1,6 +1,92 @@
1
1
  import { ParserResult } from "./types";
2
+ /**
3
+ * This function is used internally by the `trace` function to create the string for each step.
4
+ * @param name - debug name for parser
5
+ * @param result - parser result
6
+ * @returns - A formatted string that describes the parser's result
7
+ */
2
8
  export declare function resultToString<T>(name: string, result: ParserResult<T>): string;
9
+ /**
10
+ * This function is used internally with debug mode. Given a parser and a debug name for it,
11
+ * when the parser is called, `trace` will:
12
+ * 1. Print a line when the parser starts
13
+ * 2. print a line when the parser ends, indicating success or failure.
14
+ * 3. If the parser returns any captures, print the captures.
15
+ * 4. Count the number of times this parser has been run.
16
+ * 5. Track the total time this parser has taken.
17
+ * 6. Track the total number of steps your parser has taken (a step equals one parser invocation).
18
+ * So, for example, you may find out that your parser to parse Markdown has taken 50 steps to parse that file.
19
+ *
20
+ * All this happens only if debug mode is on, which you can turn on by using `parserDebug`, or setting the env var `DEBUG` to `1`.
21
+ *
22
+ * Caveat: If you have debug mode on through an environment variable, `trace` will capture counts and times
23
+ * for all parsers across your entire application. If you want to profile just a particular section of code, use `parserDebug` instead.
24
+ * If you *do* want to track constant times for all parsers, don't use `parserDebug` as it will reset those.
25
+ *
26
+ *
27
+ * `trace` works with tarsec's built-in parsers out of the box. You can easily set it up to work with your custom parser too.
28
+ *
29
+ * For example, if your parser looks like this:
30
+ *
31
+ * ```ts
32
+ * const myParser = (input:string) => {
33
+ * if (input === "hello") {
34
+ * return { success: true, result: "hello", rest: "" };
35
+ * }
36
+ * return { success: false, message: "expected hello", rest: input };
37
+ * }
38
+ * ```
39
+ *
40
+ * You can wrap it in `trace` like this:
41
+ *
42
+ * ```ts
43
+ * const myParser = trace("myParser", (input:string) => {
44
+ * if (input === "hello") {
45
+ * return { success: true, result: "hello", rest: "" };
46
+ * }
47
+ * return { success: false, message: "expected hello", rest: input };
48
+ * });
49
+ * ```
50
+ *
51
+ * Now, when you run `myParser("hello")` with debug mode on,
52
+ * you will see the debug output.
53
+ *
54
+ * Some parsers, like `seq`, are very general. You might have a few parser that use `seq`.
55
+ * So when you see `seq` debug output, you might not know which `seq` parser that means.
56
+ * ou can pass `seq` a debug name as an optional third argument to be used in the debug output.
57
+ * This name is used to track count and time, so using this name will also mean this `seq` parser's
58
+ * count and time are tracked separately from the other `seq` parsers, which might be useful.
59
+ *
60
+ * @param name - debug name for parser
61
+ * @param parser - parser to run
62
+ * @returns
63
+ */
3
64
  export declare function trace(name: string, parser: any): any;
65
+ /**
66
+ * Utility timing function. Given a callback, it times the callback
67
+ * and returns its runtime in milliseconds. It uses `performance.now()` to do this.
68
+ * If `performance.now()` is not available, it returns null.
69
+ *
70
+ * @param callback - callback to time
71
+ * @returns - time in milliseconds
72
+ */
4
73
  export declare function parserTime(callback: Function): number | null;
74
+ /**
75
+ * Wrapper for parser time. Instead of returning the time in milliseconds,
76
+ * it console.logs it, in a nicely formatted string.
77
+ * @param name - debug name for timing
78
+ * @param callback - callback to time
79
+ */
5
80
  export declare function printTime(name: string, callback: Function): void;
81
+ /**
82
+ * This is the recommended way to run a parser in debug mode.
83
+ * Takes a callback and turns debug mode on just for the callback.
84
+ * This enables `trace` to capture all sorts of information
85
+ * about any executed parsers and print them to console.log.
86
+ * `trace` tracks counts and times but they don't actually get reset to zero
87
+ * unless you use this function to wrap your code.
88
+ *
89
+ * @param name - debug name
90
+ * @param callback - callback to run in debug mode
91
+ */
6
92
  export declare function parserDebug(name: string, callback: Function): void;
package/dist/trace.js CHANGED
@@ -12,6 +12,12 @@
12
12
  exports.parserDebug = exports.printTime = exports.parserTime = exports.trace = exports.resultToString = void 0;
13
13
  const utils_1 = require("./utils");
14
14
  const STEP = 2;
15
+ /**
16
+ * This function is used internally by the `trace` function to create the string for each step.
17
+ * @param name - debug name for parser
18
+ * @param result - parser result
19
+ * @returns - A formatted string that describes the parser's result
20
+ */
15
21
  function resultToString(name, result) {
16
22
  if (result.success) {
17
23
  return `✅ ${name} -- match: ${(0, utils_1.escape)(result.result)}, rest: ${(0, utils_1.escape)(result.rest)}`;
@@ -25,6 +31,61 @@
25
31
  let debugFlag = !!process.env.DEBUG;
26
32
  let stepCount = 0;
27
33
  let stepLimit = -1;
34
+ /**
35
+ * This function is used internally with debug mode. Given a parser and a debug name for it,
36
+ * when the parser is called, `trace` will:
37
+ * 1. Print a line when the parser starts
38
+ * 2. print a line when the parser ends, indicating success or failure.
39
+ * 3. If the parser returns any captures, print the captures.
40
+ * 4. Count the number of times this parser has been run.
41
+ * 5. Track the total time this parser has taken.
42
+ * 6. Track the total number of steps your parser has taken (a step equals one parser invocation).
43
+ * So, for example, you may find out that your parser to parse Markdown has taken 50 steps to parse that file.
44
+ *
45
+ * All this happens only if debug mode is on, which you can turn on by using `parserDebug`, or setting the env var `DEBUG` to `1`.
46
+ *
47
+ * Caveat: If you have debug mode on through an environment variable, `trace` will capture counts and times
48
+ * for all parsers across your entire application. If you want to profile just a particular section of code, use `parserDebug` instead.
49
+ * If you *do* want to track constant times for all parsers, don't use `parserDebug` as it will reset those.
50
+ *
51
+ *
52
+ * `trace` works with tarsec's built-in parsers out of the box. You can easily set it up to work with your custom parser too.
53
+ *
54
+ * For example, if your parser looks like this:
55
+ *
56
+ * ```ts
57
+ * const myParser = (input:string) => {
58
+ * if (input === "hello") {
59
+ * return { success: true, result: "hello", rest: "" };
60
+ * }
61
+ * return { success: false, message: "expected hello", rest: input };
62
+ * }
63
+ * ```
64
+ *
65
+ * You can wrap it in `trace` like this:
66
+ *
67
+ * ```ts
68
+ * const myParser = trace("myParser", (input:string) => {
69
+ * if (input === "hello") {
70
+ * return { success: true, result: "hello", rest: "" };
71
+ * }
72
+ * return { success: false, message: "expected hello", rest: input };
73
+ * });
74
+ * ```
75
+ *
76
+ * Now, when you run `myParser("hello")` with debug mode on,
77
+ * you will see the debug output.
78
+ *
79
+ * Some parsers, like `seq`, are very general. You might have a few parser that use `seq`.
80
+ * So when you see `seq` debug output, you might not know which `seq` parser that means.
81
+ * ou can pass `seq` a debug name as an optional third argument to be used in the debug output.
82
+ * This name is used to track count and time, so using this name will also mean this `seq` parser's
83
+ * count and time are tracked separately from the other `seq` parsers, which might be useful.
84
+ *
85
+ * @param name - debug name for parser
86
+ * @param parser - parser to run
87
+ * @returns
88
+ */
28
89
  function trace(name, parser) {
29
90
  return (input) => {
30
91
  if (debugFlag) {
@@ -53,6 +114,14 @@
53
114
  };
54
115
  }
55
116
  exports.trace = trace;
117
+ /**
118
+ * Utility timing function. Given a callback, it times the callback
119
+ * and returns its runtime in milliseconds. It uses `performance.now()` to do this.
120
+ * If `performance.now()` is not available, it returns null.
121
+ *
122
+ * @param callback - callback to time
123
+ * @returns - time in milliseconds
124
+ */
56
125
  function parserTime(callback) {
57
126
  if (performance && performance.now) {
58
127
  const start = performance.now();
@@ -67,6 +136,12 @@
67
136
  }
68
137
  }
69
138
  exports.parserTime = parserTime;
139
+ /**
140
+ * Wrapper for parser time. Instead of returning the time in milliseconds,
141
+ * it console.logs it, in a nicely formatted string.
142
+ * @param name - debug name for timing
143
+ * @param callback - callback to time
144
+ */
70
145
  function printTime(name, callback) {
71
146
  const time = parserTime(callback);
72
147
  if (time) {
@@ -74,6 +149,17 @@
74
149
  }
75
150
  }
76
151
  exports.printTime = printTime;
152
+ /**
153
+ * This is the recommended way to run a parser in debug mode.
154
+ * Takes a callback and turns debug mode on just for the callback.
155
+ * This enables `trace` to capture all sorts of information
156
+ * about any executed parsers and print them to console.log.
157
+ * `trace` tracks counts and times but they don't actually get reset to zero
158
+ * unless you use this function to wrap your code.
159
+ *
160
+ * @param name - debug name
161
+ * @param callback - callback to run in debug mode
162
+ */
77
163
  function parserDebug(name, callback) {
78
164
  debugFlag = true;
79
165
  stepCount = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tarsec",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "A parser combinator library for TypeScript, inspired by Parsec.",
5
5
  "homepage": "https://github.com/egonSchiele/tarsec",
6
6
  "scripts": {
@@ -21,7 +21,8 @@
21
21
  "require": "./dist/index.js"
22
22
  }
23
23
  },
24
- "keywords": [],
24
+ "types": "./dist/index.d.ts",
25
+ "keywords": ["parser", "parser combinator", "parsec"],
25
26
  "author": "",
26
27
  "license": "ISC",
27
28
  "devDependencies": {