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 +5 -1
- package/dist/combinators.d.ts +97 -4
- package/dist/combinators.js +116 -11
- package/dist/parsers.d.ts +20 -5
- package/dist/parsers.js +40 -11
- package/dist/trace.d.ts +86 -0
- package/dist/trace.js +86 -0
- package/package.json +3 -2
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.
|
package/dist/combinators.d.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
120
|
-
|
|
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;
|
package/dist/combinators.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.match = exports.seqC = exports.seqR = exports.seq = exports.search = exports.
|
|
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
|
|
92
|
-
return (0, trace_1.trace)("
|
|
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.
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
347
|
-
|
|
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:
|
|
430
|
+
return Object.assign(Object.assign({}, parsed), { result: mapperFunc(parsed.result) });
|
|
351
431
|
}
|
|
352
432
|
return parsed;
|
|
353
433
|
});
|
|
354
434
|
}
|
|
355
|
-
exports.
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
|
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,
|
|
115
|
-
exports.letter = oneOf("
|
|
116
|
-
/** A parser that matches one digit or letter,
|
|
117
|
-
exports.alphanum = oneOf("
|
|
118
|
-
/** A parser that matches one
|
|
119
|
-
exports.word = (
|
|
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
|
|
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
|
-
|
|
141
|
-
|
|
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.
|
|
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
|
-
"
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"keywords": ["parser", "parser combinator", "parsec"],
|
|
25
26
|
"author": "",
|
|
26
27
|
"license": "ISC",
|
|
27
28
|
"devDependencies": {
|