tarsec 0.0.12 → 0.0.13
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/dist/combinators.d.ts +79 -6
- package/dist/combinators.js +141 -24
- package/dist/parsers/within.d.ts +2 -2
- package/dist/parsers.d.ts +15 -0
- package/dist/parsers.js +26 -1
- package/dist/trace.d.ts +3 -0
- package/dist/trace.js +70 -8
- package/dist/types.d.ts +52 -3
- package/dist/types.js +8 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +5 -1
- package/package.json +2 -1
package/dist/combinators.d.ts
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
|
-
import { CaptureParser, GeneralParser, MergedCaptures, MergedResults, Parser, PickParserType,
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { CaptureParser, GeneralParser, InferManyReturnType, MergedCaptures, MergedResults, Parser, PickParserType, PlainObject } from "./types";
|
|
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
|
+
* Fails on empty strings
|
|
11
|
+
* @param parser - parser to run
|
|
12
|
+
* @returns - parser that runs the given parser zero to many times,
|
|
13
|
+
* and returns the result as an array
|
|
14
|
+
*/
|
|
15
|
+
export declare function many<const T extends GeneralParser<any, any>>(parser: T): InferManyReturnType<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Same as `many`, but fails if the parser doesn't match at least once.
|
|
18
|
+
*
|
|
19
|
+
* @param parser - parser to run
|
|
20
|
+
* @returns a parser that runs the given parser one to many times,
|
|
21
|
+
*/
|
|
22
|
+
export declare function many1<const T extends GeneralParser<any, any>>(parser: T): InferManyReturnType<T>;
|
|
4
23
|
/**
|
|
5
24
|
* Takes a parser, runs it n times, and returns the results as an array.
|
|
6
25
|
* If it cannot run the parser n times, it fails without consuming input.
|
|
@@ -9,7 +28,21 @@ export declare function many1<T>(parser: Parser<T>): Parser<T[]>;
|
|
|
9
28
|
* @returns - parser that runs the given parser `num` times and returns an array of the results
|
|
10
29
|
*/
|
|
11
30
|
export declare function count<T>(num: number, parser: Parser<T>): Parser<T[]>;
|
|
12
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Same as `many`, but joins the results into a single string.
|
|
33
|
+
*
|
|
34
|
+
* @param parser - parser to run. The parser must return a string as its result.
|
|
35
|
+
* @returns - parser that runs the given parser zero to many times,
|
|
36
|
+
* and returns the result as a single string
|
|
37
|
+
*/
|
|
38
|
+
export declare function manyWithJoin<const T extends GeneralParser<string, any>>(parser: T): GeneralParser<string, any>;
|
|
39
|
+
/**
|
|
40
|
+
* Same as `many1`, but joins the results into a single string.
|
|
41
|
+
*
|
|
42
|
+
* @param parser - parser to run. The parser must return a string as its result.
|
|
43
|
+
* @returns - parser that runs the given parser one to many times,
|
|
44
|
+
* and returns the result as a single string
|
|
45
|
+
*/
|
|
13
46
|
export declare function many1WithJoin(parser: Parser<string>): Parser<string>;
|
|
14
47
|
/**
|
|
15
48
|
* `or` takes an array of parsers and runs them sequentially.
|
|
@@ -38,16 +71,53 @@ export declare function many1WithJoin(parser: Parser<string>): Parser<string>;
|
|
|
38
71
|
* @returns - a parser that tries each parser in order. Returns the result of the first parser that succeeds.
|
|
39
72
|
*/
|
|
40
73
|
export declare function or<const T extends readonly GeneralParser<any, any>[]>(...parsers: T): PickParserType<T>;
|
|
74
|
+
/**
|
|
75
|
+
* Takes a parser and runs it. If the parser fails,
|
|
76
|
+
* optional returns a success with a null result.
|
|
77
|
+
*
|
|
78
|
+
* @param parser - parser to run
|
|
79
|
+
* @returns - a parser that runs the given parser.
|
|
80
|
+
* If it fails, returns a success with a null result.
|
|
81
|
+
*/
|
|
41
82
|
export declare function optional<T>(parser: Parser<T>): Parser<T | null>;
|
|
83
|
+
/**
|
|
84
|
+
* Takes a parser and runs it. If the parser fails,
|
|
85
|
+
* `not` returns a success with a `null` result.
|
|
86
|
+
* If the parser succeeds, `not` returns a failure.
|
|
87
|
+
*
|
|
88
|
+
* @param parser - parser to run
|
|
89
|
+
* @returns - a parser that runs the given parser.
|
|
90
|
+
* If it fails, returns a success with a `null` result.
|
|
91
|
+
* If it succeeds, returns a failure.
|
|
92
|
+
*/
|
|
42
93
|
export declare function not(parser: Parser<any>): Parser<null>;
|
|
94
|
+
/**
|
|
95
|
+
* Takes three parsers, `open`, `close`, and `parser`.
|
|
96
|
+
* `between` matches something that matches `parser`,
|
|
97
|
+
* surrounded by `open` and `close`. It returns the result of `parser`.
|
|
98
|
+
* If any of the parsers fail, `between` fails.
|
|
99
|
+
*
|
|
100
|
+
* @param open - parser for the opening delimiter
|
|
101
|
+
* @param close - parser for the closing delimiter
|
|
102
|
+
* @param parser - parser for the content
|
|
103
|
+
* @returns a parser that returns the result of `parser`.
|
|
104
|
+
*/
|
|
43
105
|
export declare function between<O, C, P>(open: Parser<O>, close: Parser<C>, parser: Parser<P>): Parser<P>;
|
|
44
106
|
export declare function sepBy<S, P>(separator: Parser<S>, parser: Parser<P>): Parser<P[]>;
|
|
45
107
|
export declare function getResults<R, C>(results: R, captures: C): R;
|
|
46
108
|
export declare function getCaptures<R, C>(results: R, captures: C): C;
|
|
47
109
|
export declare function capture<T, const S extends string>(parser: Parser<T>, name: S): CaptureParser<T, Record<S, T>>;
|
|
48
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Returns a parser that consumes input till the given parser succeeds.
|
|
112
|
+
* @param parser - the stop parser
|
|
113
|
+
* @returns a parser that consumes the input string until the stop parser succeeds.
|
|
114
|
+
* Then it returns the consumed input as a string.
|
|
115
|
+
* The stop parser's match is not included in the result.
|
|
116
|
+
*/
|
|
49
117
|
export declare function manyTill<T>(parser: Parser<T>): Parser<string>;
|
|
50
|
-
export declare function
|
|
118
|
+
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>;
|
|
51
121
|
export declare function search(parser: Parser<string>): Parser<string[]>;
|
|
52
122
|
/**
|
|
53
123
|
* seq takes an array of parsers and runs them sequentially.
|
|
@@ -68,6 +138,8 @@ export declare function search(parser: Parser<string>): Parser<string[]>;
|
|
|
68
138
|
* and pass the remaining input to the next parser yourself.
|
|
69
139
|
* seq also does some backtracking for you that you will need to do yourself.
|
|
70
140
|
*
|
|
141
|
+
* Also see `seqR` and `seqC` for convenience functions that return the results or captures respectively.
|
|
142
|
+
*
|
|
71
143
|
* @param parsers - parsers to run sequentially
|
|
72
144
|
* @param transform - function to transform the results and captures. The params are the results and captures
|
|
73
145
|
* @param debugName - optional name for trace debugging
|
|
@@ -76,3 +148,4 @@ export declare function search(parser: Parser<string>): Parser<string[]>;
|
|
|
76
148
|
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>;
|
|
77
149
|
export declare function seqR<const T extends readonly GeneralParser<any, any>[]>(...parsers: T): Parser<MergedResults<T>[]>;
|
|
78
150
|
export declare function seqC<const T extends readonly GeneralParser<any, any>[]>(...parsers: T): Parser<MergedCaptures<T>>;
|
|
151
|
+
export declare function match(input: string, parser: GeneralParser<any, any>): boolean;
|
package/dist/combinators.js
CHANGED
|
@@ -9,26 +9,63 @@
|
|
|
9
9
|
})(function (require, exports) {
|
|
10
10
|
"use strict";
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.seqC = exports.seqR = exports.seq = exports.search = exports.transform = exports.
|
|
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;
|
|
13
13
|
const within_1 = require("./parsers/within");
|
|
14
14
|
const trace_1 = require("./trace");
|
|
15
15
|
const types_1 = require("./types");
|
|
16
16
|
const utils_1 = require("./utils");
|
|
17
|
+
/**
|
|
18
|
+
* Takes a parser and runs it zero or more times, returning the results as an array.
|
|
19
|
+
* If the parser is a capture parser, it returns the captures as an array in this form:
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* { captures: <array of captures> }
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* Fails on empty strings
|
|
26
|
+
* @param parser - parser to run
|
|
27
|
+
* @returns - parser that runs the given parser zero to many times,
|
|
28
|
+
* and returns the result as an array
|
|
29
|
+
*/
|
|
17
30
|
function many(parser) {
|
|
18
31
|
return (0, trace_1.trace)("many", (input) => {
|
|
19
32
|
let results = [];
|
|
33
|
+
let captures = [];
|
|
20
34
|
let rest = input;
|
|
21
35
|
while (true) {
|
|
22
36
|
let parsed = parser(rest);
|
|
23
37
|
if (!parsed.success) {
|
|
24
|
-
|
|
38
|
+
if (Object.keys(captures).length) {
|
|
39
|
+
return (0, types_1.captureSuccess)(results, rest, { captures });
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
return (0, types_1.success)(results, rest);
|
|
43
|
+
}
|
|
25
44
|
}
|
|
26
45
|
results.push(parsed.result);
|
|
46
|
+
if ((0, types_1.isCaptureResult)(parsed)) {
|
|
47
|
+
captures.push(parsed.captures);
|
|
48
|
+
}
|
|
27
49
|
rest = parsed.rest;
|
|
50
|
+
// don't loop infinitely on empty strings
|
|
51
|
+
if (rest === "") {
|
|
52
|
+
if (Object.keys(captures).length) {
|
|
53
|
+
return (0, types_1.captureSuccess)(results, rest, { captures });
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
return (0, types_1.success)(results, rest);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
28
59
|
}
|
|
29
60
|
});
|
|
30
61
|
}
|
|
31
62
|
exports.many = many;
|
|
63
|
+
/**
|
|
64
|
+
* Same as `many`, but fails if the parser doesn't match at least once.
|
|
65
|
+
*
|
|
66
|
+
* @param parser - parser to run
|
|
67
|
+
* @returns a parser that runs the given parser one to many times,
|
|
68
|
+
*/
|
|
32
69
|
function many1(parser) {
|
|
33
70
|
return (0, trace_1.trace)(`many1`, (input) => {
|
|
34
71
|
let result = many(parser)(input);
|
|
@@ -67,12 +104,38 @@
|
|
|
67
104
|
});
|
|
68
105
|
}
|
|
69
106
|
exports.count = count;
|
|
107
|
+
/**
|
|
108
|
+
* Same as `many`, but joins the results into a single string.
|
|
109
|
+
*
|
|
110
|
+
* @param parser - parser to run. The parser must return a string as its result.
|
|
111
|
+
* @returns - parser that runs the given parser zero to many times,
|
|
112
|
+
* and returns the result as a single string
|
|
113
|
+
*/
|
|
70
114
|
function manyWithJoin(parser) {
|
|
71
|
-
return
|
|
115
|
+
return (0, trace_1.trace)("manyWithJoin", (input) => {
|
|
116
|
+
const result = many(parser)(input);
|
|
117
|
+
if (result.success) {
|
|
118
|
+
return Object.assign(Object.assign({}, result), { result: result.result.join("") });
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
});
|
|
72
122
|
}
|
|
73
123
|
exports.manyWithJoin = manyWithJoin;
|
|
124
|
+
/**
|
|
125
|
+
* Same as `many1`, but joins the results into a single string.
|
|
126
|
+
*
|
|
127
|
+
* @param parser - parser to run. The parser must return a string as its result.
|
|
128
|
+
* @returns - parser that runs the given parser one to many times,
|
|
129
|
+
* and returns the result as a single string
|
|
130
|
+
*/
|
|
74
131
|
function many1WithJoin(parser) {
|
|
75
|
-
return
|
|
132
|
+
return (0, trace_1.trace)("many1WithJoin", (input) => {
|
|
133
|
+
const result = many1(parser)(input);
|
|
134
|
+
if (result.success) {
|
|
135
|
+
return Object.assign(Object.assign({}, result), { result: result.result.join("") });
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
});
|
|
76
139
|
}
|
|
77
140
|
exports.many1WithJoin = many1WithJoin;
|
|
78
141
|
/**
|
|
@@ -117,6 +180,14 @@
|
|
|
117
180
|
});
|
|
118
181
|
}
|
|
119
182
|
exports.or = or;
|
|
183
|
+
/**
|
|
184
|
+
* Takes a parser and runs it. If the parser fails,
|
|
185
|
+
* optional returns a success with a null result.
|
|
186
|
+
*
|
|
187
|
+
* @param parser - parser to run
|
|
188
|
+
* @returns - a parser that runs the given parser.
|
|
189
|
+
* If it fails, returns a success with a null result.
|
|
190
|
+
*/
|
|
120
191
|
function optional(parser) {
|
|
121
192
|
return (0, trace_1.trace)("optional", (input) => {
|
|
122
193
|
let result = parser(input);
|
|
@@ -127,6 +198,16 @@
|
|
|
127
198
|
});
|
|
128
199
|
}
|
|
129
200
|
exports.optional = optional;
|
|
201
|
+
/**
|
|
202
|
+
* Takes a parser and runs it. If the parser fails,
|
|
203
|
+
* `not` returns a success with a `null` result.
|
|
204
|
+
* If the parser succeeds, `not` returns a failure.
|
|
205
|
+
*
|
|
206
|
+
* @param parser - parser to run
|
|
207
|
+
* @returns - a parser that runs the given parser.
|
|
208
|
+
* If it fails, returns a success with a `null` result.
|
|
209
|
+
* If it succeeds, returns a failure.
|
|
210
|
+
*/
|
|
130
211
|
function not(parser) {
|
|
131
212
|
return (0, trace_1.trace)("not", (input) => {
|
|
132
213
|
let result = parser(input);
|
|
@@ -134,13 +215,24 @@
|
|
|
134
215
|
return {
|
|
135
216
|
success: false,
|
|
136
217
|
rest: input,
|
|
137
|
-
message: "
|
|
218
|
+
message: "expected parser not to succeed",
|
|
138
219
|
};
|
|
139
220
|
}
|
|
140
221
|
return (0, types_1.success)(null, input);
|
|
141
222
|
});
|
|
142
223
|
}
|
|
143
224
|
exports.not = not;
|
|
225
|
+
/**
|
|
226
|
+
* Takes three parsers, `open`, `close`, and `parser`.
|
|
227
|
+
* `between` matches something that matches `parser`,
|
|
228
|
+
* surrounded by `open` and `close`. It returns the result of `parser`.
|
|
229
|
+
* If any of the parsers fail, `between` fails.
|
|
230
|
+
*
|
|
231
|
+
* @param open - parser for the opening delimiter
|
|
232
|
+
* @param close - parser for the closing delimiter
|
|
233
|
+
* @param parser - parser for the content
|
|
234
|
+
* @returns a parser that returns the result of `parser`.
|
|
235
|
+
*/
|
|
144
236
|
function between(open, close, parser) {
|
|
145
237
|
return (input) => {
|
|
146
238
|
const result1 = open(input);
|
|
@@ -200,18 +292,13 @@
|
|
|
200
292
|
});
|
|
201
293
|
}
|
|
202
294
|
exports.capture = capture;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
return result;
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
exports.wrap = wrap;
|
|
295
|
+
/**
|
|
296
|
+
* Returns a parser that consumes input till the given parser succeeds.
|
|
297
|
+
* @param parser - the stop parser
|
|
298
|
+
* @returns a parser that consumes the input string until the stop parser succeeds.
|
|
299
|
+
* Then it returns the consumed input as a string.
|
|
300
|
+
* The stop parser's match is not included in the result.
|
|
301
|
+
*/
|
|
215
302
|
function manyTill(parser) {
|
|
216
303
|
return (input) => {
|
|
217
304
|
let current = 0;
|
|
@@ -226,6 +313,36 @@
|
|
|
226
313
|
};
|
|
227
314
|
}
|
|
228
315
|
exports.manyTill = manyTill;
|
|
316
|
+
function many1Till(parser) {
|
|
317
|
+
return (input) => {
|
|
318
|
+
let current = 0;
|
|
319
|
+
while (current < input.length) {
|
|
320
|
+
const parsed = parser(input.slice(current));
|
|
321
|
+
if (parsed.success) {
|
|
322
|
+
if (current === 0) {
|
|
323
|
+
return (0, types_1.failure)("expected to consume at least one character of input", input);
|
|
324
|
+
}
|
|
325
|
+
return (0, types_1.success)(input.slice(0, current), input.slice(current));
|
|
326
|
+
}
|
|
327
|
+
current++;
|
|
328
|
+
}
|
|
329
|
+
if (current === 0) {
|
|
330
|
+
return (0, types_1.failure)("expected to consume at least one character of input", input);
|
|
331
|
+
}
|
|
332
|
+
return (0, types_1.success)(input, "");
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
exports.many1Till = many1Till;
|
|
336
|
+
function manyTillStr(str) {
|
|
337
|
+
return (0, trace_1.trace)(`manyTillStr(${str})`, (input) => {
|
|
338
|
+
const index = input.indexOf(str);
|
|
339
|
+
if (index === -1) {
|
|
340
|
+
return (0, types_1.success)(input, "");
|
|
341
|
+
}
|
|
342
|
+
return (0, types_1.success)(input.slice(0, index), input.slice(index));
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
exports.manyTillStr = manyTillStr;
|
|
229
346
|
function transform(parser, transformerFunc) {
|
|
230
347
|
return (0, trace_1.trace)(`transform(${transformerFunc})`, (input) => {
|
|
231
348
|
let parsed = parser(input);
|
|
@@ -330,6 +447,8 @@
|
|
|
330
447
|
* and pass the remaining input to the next parser yourself.
|
|
331
448
|
* seq also does some backtracking for you that you will need to do yourself.
|
|
332
449
|
*
|
|
450
|
+
* Also see `seqR` and `seqC` for convenience functions that return the results or captures respectively.
|
|
451
|
+
*
|
|
333
452
|
* @param parsers - parsers to run sequentially
|
|
334
453
|
* @param transform - function to transform the results and captures. The params are the results and captures
|
|
335
454
|
* @param debugName - optional name for trace debugging
|
|
@@ -392,11 +511,9 @@
|
|
|
392
511
|
return seq(parsers, getCaptures);
|
|
393
512
|
}
|
|
394
513
|
exports.seqC = seqC;
|
|
514
|
+
function match(input, parser) {
|
|
515
|
+
const result = parser(input);
|
|
516
|
+
return result.success && result.rest === "";
|
|
517
|
+
}
|
|
518
|
+
exports.match = match;
|
|
395
519
|
});
|
|
396
|
-
/*
|
|
397
|
-
export function seqX<const T extends readonly GeneralParser<any, any>[], U>(
|
|
398
|
-
parsers: T,
|
|
399
|
-
transform: (results: MergedResults<T>[], captures: MergedCaptures<T>) => U,
|
|
400
|
-
debugName: string = ""
|
|
401
|
-
): Parser<U> {
|
|
402
|
-
*/
|
package/dist/parsers/within.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function within(parser: Parser<string>): Parser<
|
|
1
|
+
import { WithinResult, Parser } from "../types";
|
|
2
|
+
export declare function within(parser: Parser<string>): Parser<WithinResult[]>;
|
package/dist/parsers.d.ts
CHANGED
|
@@ -38,15 +38,30 @@ export declare function noneOf(chars: string): Parser<string>;
|
|
|
38
38
|
* @returns - ParserResult
|
|
39
39
|
*/
|
|
40
40
|
export declare const anyChar: any;
|
|
41
|
+
/** A parser that matches one of " \t\n\r". */
|
|
41
42
|
export declare const space: Parser<string>;
|
|
43
|
+
/** A parser that matches one or more spaces. */
|
|
42
44
|
export declare const spaces: Parser<string>;
|
|
45
|
+
/** A parser that matches one digit. */
|
|
43
46
|
export declare const digit: Parser<string>;
|
|
47
|
+
/** A parser that matches one letter, currently lowercase only. */
|
|
44
48
|
export declare const letter: Parser<string>;
|
|
49
|
+
/** A parser that matches one digit or letter, currently lowercase only. */
|
|
45
50
|
export declare const alphanum: Parser<string>;
|
|
51
|
+
/** A parser that matches one lowercase word. */
|
|
46
52
|
export declare const word: Parser<string>;
|
|
53
|
+
/** A parser that matches one or more digits. */
|
|
47
54
|
export declare const num: Parser<string>;
|
|
55
|
+
/** A parser that matches one single or double quote. */
|
|
48
56
|
export declare const quote: Parser<string>;
|
|
57
|
+
/** A parser that matches one tab character. */
|
|
49
58
|
export declare const tab: Parser<string>;
|
|
59
|
+
/** A parser that matches one newline ("\n" only) character. */
|
|
50
60
|
export declare const newline: Parser<string>;
|
|
61
|
+
/** A parser that succeeds on an empty string. Returns `null` as the result. */
|
|
51
62
|
export declare const eof: Parser<null>;
|
|
63
|
+
/** A parser that matches a quoted string, in single or double quotes.
|
|
64
|
+
* Returns the string as the result, including the quotes.
|
|
65
|
+
*/
|
|
52
66
|
export declare const quotedString: Parser<string>;
|
|
67
|
+
export declare function regexParser(str: string | RegExp): 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.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.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");
|
|
@@ -105,16 +105,27 @@
|
|
|
105
105
|
}
|
|
106
106
|
return (0, types_1.success)(input[0], input.slice(1));
|
|
107
107
|
});
|
|
108
|
+
/** A parser that matches one of " \t\n\r". */
|
|
108
109
|
exports.space = oneOf(" \t\n\r");
|
|
110
|
+
/** A parser that matches one or more spaces. */
|
|
109
111
|
exports.spaces = (0, combinators_1.many1WithJoin)(exports.space);
|
|
112
|
+
/** A parser that matches one digit. */
|
|
110
113
|
exports.digit = oneOf("0123456789");
|
|
114
|
+
/** A parser that matches one letter, currently lowercase only. */
|
|
111
115
|
exports.letter = oneOf("abcdefghijklmnopqrstuvwxyz");
|
|
116
|
+
/** A parser that matches one digit or letter, currently lowercase only. */
|
|
112
117
|
exports.alphanum = oneOf("abcdefghijklmnopqrstuvwxyz0123456789");
|
|
118
|
+
/** A parser that matches one lowercase word. */
|
|
113
119
|
exports.word = (0, combinators_1.many1WithJoin)(exports.letter);
|
|
120
|
+
/** A parser that matches one or more digits. */
|
|
114
121
|
exports.num = (0, combinators_1.many1WithJoin)(exports.digit);
|
|
122
|
+
/** A parser that matches one single or double quote. */
|
|
115
123
|
exports.quote = oneOf(`'"`);
|
|
124
|
+
/** A parser that matches one tab character. */
|
|
116
125
|
exports.tab = char("\t");
|
|
126
|
+
/** A parser that matches one newline ("\n" only) character. */
|
|
117
127
|
exports.newline = char("\n");
|
|
128
|
+
/** A parser that succeeds on an empty string. Returns `null` as the result. */
|
|
118
129
|
const eof = (input) => {
|
|
119
130
|
if (input === "") {
|
|
120
131
|
return (0, types_1.success)(null, input);
|
|
@@ -122,5 +133,19 @@
|
|
|
122
133
|
return (0, types_1.failure)("expected end of input", input);
|
|
123
134
|
};
|
|
124
135
|
exports.eof = eof;
|
|
136
|
+
/** A parser that matches a quoted string, in single or double quotes.
|
|
137
|
+
* Returns the string as the result, including the quotes.
|
|
138
|
+
*/
|
|
125
139
|
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;
|
|
142
|
+
return (0, trace_1.trace)(`regex(${str})`, (input) => {
|
|
143
|
+
const match = input.match(re);
|
|
144
|
+
if (match) {
|
|
145
|
+
return (0, types_1.success)(match[0], input.slice(match[0].length));
|
|
146
|
+
}
|
|
147
|
+
return (0, types_1.failure)(`expected ${str}, got ${input.slice(0, 10)}`, input);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
exports.regexParser = regexParser;
|
|
126
151
|
});
|
package/dist/trace.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import { ParserResult } from "./types";
|
|
2
2
|
export declare function resultToString<T>(name: string, result: ParserResult<T>): string;
|
|
3
3
|
export declare function trace(name: string, parser: any): any;
|
|
4
|
+
export declare function parserTime(callback: Function): number | null;
|
|
5
|
+
export declare function printTime(name: string, callback: Function): void;
|
|
6
|
+
export declare function parserDebug(name: string, callback: Function): void;
|
package/dist/trace.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.trace = exports.resultToString = void 0;
|
|
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
15
|
function resultToString(name, result) {
|
|
@@ -20,23 +20,85 @@
|
|
|
20
20
|
}
|
|
21
21
|
exports.resultToString = resultToString;
|
|
22
22
|
let level = 0;
|
|
23
|
+
let counts = {};
|
|
24
|
+
let times = {};
|
|
25
|
+
let debugFlag = !!process.env.DEBUG;
|
|
26
|
+
let stepCount = 0;
|
|
27
|
+
let stepLimit = -1;
|
|
23
28
|
function trace(name, parser) {
|
|
24
29
|
return (input) => {
|
|
25
|
-
if (
|
|
30
|
+
if (debugFlag) {
|
|
26
31
|
console.log(" ".repeat(level) + `🔍 ${name} -- input: ${(0, utils_1.escape)(input)}`);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
let result;
|
|
33
|
+
const time = parserTime(() => {
|
|
34
|
+
level += STEP;
|
|
35
|
+
result = parser(input);
|
|
36
|
+
level -= STEP;
|
|
37
|
+
});
|
|
38
|
+
counts[name] = counts[name] ? counts[name] + 1 : 1;
|
|
39
|
+
stepCount += 1;
|
|
40
|
+
if (time) {
|
|
41
|
+
times[name] = times[name] ? times[name] + time : time;
|
|
42
|
+
}
|
|
32
43
|
console.log(" ".repeat(level) + resultToString(name, result));
|
|
33
44
|
if (result.success && result.captures) {
|
|
34
45
|
console.log(" ".repeat(level) +
|
|
35
46
|
`⭐ ${name} -- captures: ${JSON.stringify(result.captures)}`);
|
|
36
47
|
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
return parser(input);
|
|
37
52
|
}
|
|
38
|
-
return result;
|
|
39
53
|
};
|
|
40
54
|
}
|
|
41
55
|
exports.trace = trace;
|
|
56
|
+
function parserTime(callback) {
|
|
57
|
+
if (performance && performance.now) {
|
|
58
|
+
const start = performance.now();
|
|
59
|
+
callback();
|
|
60
|
+
const end = performance.now();
|
|
61
|
+
return end - start;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
console.error("performance.now not available");
|
|
65
|
+
callback();
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.parserTime = parserTime;
|
|
70
|
+
function printTime(name, callback) {
|
|
71
|
+
const time = parserTime(callback);
|
|
72
|
+
if (time) {
|
|
73
|
+
console.log(`⏱ ${name} -- time: ${(0, utils_1.round)(time)}ms`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.printTime = printTime;
|
|
77
|
+
function parserDebug(name, callback) {
|
|
78
|
+
debugFlag = true;
|
|
79
|
+
stepCount = 0;
|
|
80
|
+
counts = {};
|
|
81
|
+
times = {};
|
|
82
|
+
printTime(name, callback);
|
|
83
|
+
debugFlag = false;
|
|
84
|
+
console.log("\n");
|
|
85
|
+
console.log(`📊 ${name} -- counts:`);
|
|
86
|
+
const sorted = Object.entries(counts).sort((a, b) => b[1] - a[1]);
|
|
87
|
+
for (const [name, count] of sorted) {
|
|
88
|
+
console.log(` ${name}: ${count}`);
|
|
89
|
+
}
|
|
90
|
+
console.log("\n");
|
|
91
|
+
console.log(`📊 ${name} -- times:`);
|
|
92
|
+
const sortedTimes = Object.entries(times).sort((a, b) => b[1] - a[1]);
|
|
93
|
+
for (const [name, time] of sortedTimes) {
|
|
94
|
+
console.log(` ${name}: ${(0, utils_1.round)(time)}ms`);
|
|
95
|
+
}
|
|
96
|
+
console.log("\n");
|
|
97
|
+
console.log(`📊 ${name} -- step count: ${stepCount}`);
|
|
98
|
+
console.log("\n\n");
|
|
99
|
+
stepCount = 0;
|
|
100
|
+
counts = {};
|
|
101
|
+
times = {};
|
|
102
|
+
}
|
|
103
|
+
exports.parserDebug = parserDebug;
|
|
42
104
|
});
|
package/dist/types.d.ts
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
|
+
/** A generic object type. */
|
|
1
2
|
export type PlainObject = Record<string, unknown>;
|
|
3
|
+
/** Represents a parse success with no captures. */
|
|
2
4
|
export type ParserSuccess<T> = {
|
|
3
5
|
success: true;
|
|
4
6
|
result: T;
|
|
5
7
|
rest: string;
|
|
6
|
-
nextParser?:
|
|
8
|
+
nextParser?: Parser<any>;
|
|
7
9
|
};
|
|
8
|
-
|
|
10
|
+
/** Represents a parse success with captures. Notice nextParser is also a CaptureParser. */
|
|
11
|
+
export type CaptureParserSuccess<T, C extends PlainObject> = {
|
|
12
|
+
success: true;
|
|
13
|
+
result: T;
|
|
14
|
+
rest: string;
|
|
9
15
|
captures: C;
|
|
16
|
+
nextParser?: CaptureParser<any, any>;
|
|
10
17
|
};
|
|
18
|
+
/** Represents a parse failure. */
|
|
11
19
|
export type ParserFailure = {
|
|
12
20
|
success: false;
|
|
13
21
|
rest: string;
|
|
@@ -15,22 +23,46 @@ export type ParserFailure = {
|
|
|
15
23
|
};
|
|
16
24
|
export type ParserResult<T> = ParserSuccess<T> | ParserFailure;
|
|
17
25
|
export type CaptureParserResult<T, C extends PlainObject> = CaptureParserSuccess<T, C> | ParserFailure;
|
|
26
|
+
/** A parser is any function that takes a string and returns a ParserResult. */
|
|
18
27
|
export type Parser<T> = (input: string) => ParserResult<T>;
|
|
28
|
+
/** A capture parser is any function that takes a string and returns a CaptureParserResult.
|
|
29
|
+
* A CaptureParserResult is the same as a ParserResult, except it also includes captures,
|
|
30
|
+
* i.e. matches selected using `capture`. */
|
|
19
31
|
export type CaptureParser<T, C extends PlainObject> = (input: string) => CaptureParserResult<T, C>;
|
|
20
32
|
export type GeneralParser<T, C extends PlainObject> = Parser<T> | CaptureParser<T, C>;
|
|
21
33
|
export declare function isCaptureResult<T, C extends PlainObject>(result: ParserResult<T>): result is CaptureParserSuccess<T, C>;
|
|
34
|
+
/** Convenience function to return a ParserSuccess */
|
|
22
35
|
export declare function success<T>(result: T, rest: string): ParserSuccess<T>;
|
|
36
|
+
/** Convenience function to return a CaptureParserSuccess */
|
|
23
37
|
export declare function captureSuccess<T, C extends PlainObject>(result: T, rest: string, captures: C): CaptureParserSuccess<T, C>;
|
|
38
|
+
/** Convenience function to return a ParserFailure */
|
|
24
39
|
export declare function failure(message: string, rest: string): ParserFailure;
|
|
40
|
+
/** Prettify an intersected type, to make it easier to read. */
|
|
25
41
|
export type Prettify<T> = {
|
|
26
42
|
[K in keyof T]: T[K];
|
|
27
43
|
} & {};
|
|
44
|
+
/** see <https://stackoverflow.com/a/50375286/3625> */
|
|
28
45
|
export type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
|
|
46
|
+
/** Convenience type to get the result type out of a parser. */
|
|
29
47
|
type ExtractResults<T> = T extends Parser<infer U> ? U : never;
|
|
48
|
+
/** Convenience type to get the capture type out of a capture parser. */
|
|
30
49
|
type ExtractCaptures<T> = T extends CaptureParser<any, infer U> ? U : never;
|
|
50
|
+
/** Convenience type where given an array of parsers and capture parsers,
|
|
51
|
+
* it returns the types of the capture parsers, like
|
|
52
|
+
* CaptureParser<string, { name: string }> | CaptureParser<number, { age: number }>
|
|
53
|
+
*/
|
|
31
54
|
type ExtractCaptureParsers<T extends readonly GeneralParser<any, any>[]> = Extract<T[number], CaptureParser<any, any>>;
|
|
55
|
+
/** Convenience type where given an array of parsers and capture parsers,
|
|
56
|
+
* it returns a single capture type that merges all the capture types. */
|
|
32
57
|
export type MergedCaptures<T extends readonly GeneralParser<any, any>[]> = Prettify<UnionToIntersection<UnionOfCaptures<T>>>;
|
|
58
|
+
/** Convenience type where given an array of parsers and capture parsers,
|
|
59
|
+
* it first gets the capture parsers, then extracts the capture types,
|
|
60
|
+
* and returns a union of all the capture types. Example:
|
|
61
|
+
* { name: string } | { age: number }
|
|
62
|
+
*/
|
|
33
63
|
export type UnionOfCaptures<T extends readonly GeneralParser<any, any>[]> = Prettify<ExtractCaptures<ExtractCaptureParsers<T>>>;
|
|
64
|
+
/** Convenience type where given an array of parsers and capture parsers,
|
|
65
|
+
* it returns true if there are any capture parsers, otherwise false. */
|
|
34
66
|
export type HasCaptureParsers<T extends readonly GeneralParser<any, any>[]> = ExtractCaptureParsers<T> extends never ? false : true;
|
|
35
67
|
/**
|
|
36
68
|
* For a given array of GeneralParsers, if any of them is a CaptureParser,
|
|
@@ -40,7 +72,18 @@ export type HasCaptureParsers<T extends readonly GeneralParser<any, any>[]> = Ex
|
|
|
40
72
|
* which is not able to infer its return type correctly.
|
|
41
73
|
*/
|
|
42
74
|
export type PickParserType<T extends readonly GeneralParser<any, any>[]> = HasCaptureParsers<T> extends true ? CaptureParser<MergedResults<T>, UnionOfCaptures<T>> : Parser<MergedResults<T>>;
|
|
75
|
+
/** This is used to generate a return type for the `many` and `many1` combinators.
|
|
76
|
+
* Given a parser we want to apply `many` to. Suppose its type is `Parser<string>`.
|
|
77
|
+
* This will return `Parser<string[]>` as the return type.
|
|
78
|
+
*
|
|
79
|
+
* Suppose the parser is a `CaptureParser<string, { name: string }>`.
|
|
80
|
+
* This will return `CaptureParser<string[], { captures: { name: string }[] }>` as the return type.
|
|
81
|
+
*/
|
|
82
|
+
export type InferManyReturnType<T extends GeneralParser<any, any>> = T extends CaptureParser<infer R, infer C> ? CaptureParser<R[], {
|
|
83
|
+
captures: C[];
|
|
84
|
+
}> : Parser<T[]>;
|
|
43
85
|
export type MergedResults<T extends readonly GeneralParser<any, any>[]> = ExtractResults<T[number]>;
|
|
86
|
+
/** Used to create a parser tree for backtracking. */
|
|
44
87
|
export type Node = ParserNode | EmptyNode;
|
|
45
88
|
export type ParserNode = {
|
|
46
89
|
parent: Node;
|
|
@@ -50,8 +93,14 @@ export type ParserNode = {
|
|
|
50
93
|
closed: boolean;
|
|
51
94
|
};
|
|
52
95
|
export type EmptyNode = null;
|
|
96
|
+
/** Convenience function to create a ParserNode. */
|
|
53
97
|
export declare function createNode(parent: Node | null, parser: GeneralParser<any, any>): ParserNode;
|
|
98
|
+
/** Convenience function where, given an array of parsers, it creates a tree we can use for backtracking.
|
|
99
|
+
* This tree is what `seq` use. It's used to keep track of the parsers we've tried so far,
|
|
100
|
+
* so we can backtrack if we need to.
|
|
101
|
+
*/
|
|
54
102
|
export declare function createTree(parsers: readonly GeneralParser<any, any>[]): Node;
|
|
103
|
+
/** Used by `within`. */
|
|
55
104
|
export type Matched = {
|
|
56
105
|
type: "matched";
|
|
57
106
|
value: string;
|
|
@@ -60,5 +109,5 @@ export type Unmatched = {
|
|
|
60
109
|
type: "unmatched";
|
|
61
110
|
value: string;
|
|
62
111
|
};
|
|
63
|
-
export type
|
|
112
|
+
export type WithinResult = Matched | Unmatched;
|
|
64
113
|
export {};
|
package/dist/types.js
CHANGED
|
@@ -14,18 +14,22 @@
|
|
|
14
14
|
return "captures" in result;
|
|
15
15
|
}
|
|
16
16
|
exports.isCaptureResult = isCaptureResult;
|
|
17
|
+
/** Convenience function to return a ParserSuccess */
|
|
17
18
|
function success(result, rest) {
|
|
18
19
|
return { success: true, result, rest };
|
|
19
20
|
}
|
|
20
21
|
exports.success = success;
|
|
22
|
+
/** Convenience function to return a CaptureParserSuccess */
|
|
21
23
|
function captureSuccess(result, rest, captures) {
|
|
22
24
|
return { success: true, result, rest, captures };
|
|
23
25
|
}
|
|
24
26
|
exports.captureSuccess = captureSuccess;
|
|
27
|
+
/** Convenience function to return a ParserFailure */
|
|
25
28
|
function failure(message, rest) {
|
|
26
29
|
return { success: false, message, rest };
|
|
27
30
|
}
|
|
28
31
|
exports.failure = failure;
|
|
32
|
+
/** Convenience function to create a ParserNode. */
|
|
29
33
|
function createNode(parent, parser) {
|
|
30
34
|
return {
|
|
31
35
|
parent,
|
|
@@ -35,6 +39,10 @@
|
|
|
35
39
|
};
|
|
36
40
|
}
|
|
37
41
|
exports.createNode = createNode;
|
|
42
|
+
/** Convenience function where, given an array of parsers, it creates a tree we can use for backtracking.
|
|
43
|
+
* This tree is what `seq` use. It's used to keep track of the parsers we've tried so far,
|
|
44
|
+
* so we can backtrack if we need to.
|
|
45
|
+
*/
|
|
38
46
|
function createTree(parsers) {
|
|
39
47
|
if (parsers.length === 0) {
|
|
40
48
|
return null;
|
package/dist/utils.d.ts
CHANGED
|
@@ -4,3 +4,4 @@ export declare function merge(a: any | any[], b: any | any[]): any[];
|
|
|
4
4
|
export declare function mergeCaptures(a: Record<string, any>, b: Record<string, any>): Record<string, any>;
|
|
5
5
|
export declare function findAncestorWithNextParser(node: Node, count?: number): [Node, number];
|
|
6
6
|
export declare function popMany(arr: any[], count: number): void;
|
|
7
|
+
export declare function round(num: number, places?: number): number;
|
package/dist/utils.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.popMany = exports.findAncestorWithNextParser = exports.mergeCaptures = exports.merge = exports.escape = void 0;
|
|
12
|
+
exports.round = exports.popMany = exports.findAncestorWithNextParser = exports.mergeCaptures = exports.merge = exports.escape = void 0;
|
|
13
13
|
function escape(str) {
|
|
14
14
|
return JSON.stringify(str);
|
|
15
15
|
}
|
|
@@ -63,4 +63,8 @@
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
exports.popMany = popMany;
|
|
66
|
+
function round(num, places = 2) {
|
|
67
|
+
return Math.round(num * 10 ** places) / 10 ** places;
|
|
68
|
+
}
|
|
69
|
+
exports.round = round;
|
|
66
70
|
});
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tarsec",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "A parser combinator library for TypeScript, inspired by Parsec.",
|
|
5
5
|
"homepage": "https://github.com/egonSchiele/tarsec",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "vitest",
|
|
8
|
+
"test:tsc": "tsc -p tests/tsconfig.json",
|
|
8
9
|
"coverage": "vitest --coverage",
|
|
9
10
|
"build": "rm -rf dist && tsc",
|
|
10
11
|
"start": "cd dist && node index.js",
|