parser-combinators 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +12 -0
- package/README.md +49 -4
- package/dist/index.d.ts +3 -0
- package/dist/index.js +19 -0
- package/{parser.d.ts → dist/parser.d.ts} +9 -16
- package/{parser.js → dist/parser.js} +21 -34
- package/{parsers → dist/parsers}/any.d.ts +16 -15
- package/dist/parsers/any.js +47 -0
- package/dist/parsers/anyString.d.ts +15 -0
- package/dist/parsers/anyString.js +85 -0
- package/{parsers → dist/parsers}/between.d.ts +5 -5
- package/{parsers → dist/parsers}/between.js +20 -21
- package/{parsers → dist/parsers}/exhaust.d.ts +5 -5
- package/{parsers → dist/parsers}/exhaust.js +25 -27
- package/{parsers → dist/parsers}/index.d.ts +12 -11
- package/{parsers → dist/parsers}/index.js +31 -23
- package/{parsers → dist/parsers}/many.d.ts +17 -17
- package/{parsers → dist/parsers}/many.js +61 -61
- package/{parsers → dist/parsers}/map.d.ts +5 -5
- package/{parsers → dist/parsers}/map.js +21 -22
- package/{parsers → dist/parsers}/opt.d.ts +5 -5
- package/{parsers → dist/parsers}/opt.js +16 -17
- package/dist/parsers/recovery.d.ts +14 -0
- package/dist/parsers/recovery.js +53 -0
- package/{parsers → dist/parsers}/regex.d.ts +5 -5
- package/{parsers → dist/parsers}/regex.js +20 -21
- package/{parsers → dist/parsers}/seq.d.ts +16 -15
- package/{parsers → dist/parsers}/seq.js +17 -18
- package/dist/parsers/str.d.ts +17 -0
- package/dist/parsers/str.js +36 -0
- package/dist/parsers/utilities.d.ts +33 -0
- package/dist/parsers/utilities.js +96 -0
- package/{parsers → dist/parsers}/values.d.ts +31 -28
- package/{parsers → dist/parsers}/values.js +48 -36
- package/{types.d.ts → dist/types.d.ts} +40 -33
- package/{types.js → dist/types.js} +47 -47
- package/package.json +22 -24
- package/parsers/any.js +0 -20
- package/parsers/str.d.ts +0 -5
- package/parsers/str.js +0 -18
- package/parsers/utilities.d.ts +0 -9
- package/parsers/utilities.js +0 -30
package/LICENSE
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Copyright 2022 Michał Isalski
|
|
2
|
+
|
|
3
|
+
Permission to use, copy, modify, and/or distribute
|
|
4
|
+
this software for any purpose with or without fee is hereby granted,
|
|
5
|
+
provided that the above copyright notice and this permission notice appear in all copies.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
8
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
|
9
|
+
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
|
|
10
|
+
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
11
|
+
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
|
12
|
+
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
## Parser Combinators
|
|
2
2
|
|
|
3
|
-
](https://github.com/michalusio/Parser/actions/workflows/CI.yml)
|
|
4
4
|
[](https://github.com/michalusio/Parser/actions/workflows/codeql-analysis.yml)
|
|
5
|
-
](https://codecov.io/gh/michalusio/Parser)
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
[](https://badge.fury.io/js/parser-combinators)
|
|
9
|
-
[](https://status.david-dm.org/)
|
|
10
9
|
|
|
11
10
|
A library of parser combinators, with which you can create your own parsers.
|
|
12
11
|
|
|
@@ -34,10 +33,14 @@ A library of parser combinators, with which you can create your own parsers.
|
|
|
34
33
|
- `opt`ional
|
|
35
34
|
- `regex`
|
|
36
35
|
- `seq`uence
|
|
37
|
-
- `str`ing
|
|
36
|
+
- `str`ing and `stri`ng (case-insensitive)
|
|
38
37
|
- Utility combinators:
|
|
39
38
|
- `ref`er
|
|
40
39
|
- `expect`
|
|
40
|
+
- `expectErase`
|
|
41
|
+
- `surely`
|
|
42
|
+
- `token`
|
|
43
|
+
- `lookaround`
|
|
41
44
|
- Ready-made value combinators:
|
|
42
45
|
- `spaces`
|
|
43
46
|
- `spacesPlus`
|
|
@@ -45,6 +48,27 @@ A library of parser combinators, with which you can create your own parsers.
|
|
|
45
48
|
- `bool` (and `boolP`)
|
|
46
49
|
- `int` (and `intP`)
|
|
47
50
|
- `real` (and `realP`)
|
|
51
|
+
- `eof`
|
|
52
|
+
- Recovery combinators:
|
|
53
|
+
- `recoverBySkippingChars`
|
|
54
|
+
- `recoverByAddingChars`
|
|
55
|
+
- Whole parsers:
|
|
56
|
+
- Extended Backus-Naur Form (`EBNF`)
|
|
57
|
+
- JavaScript Object Notation (`JSON`)
|
|
58
|
+
|
|
59
|
+
##### Optimization remarks:
|
|
60
|
+
|
|
61
|
+
Combining many string parsers using an `any` parser uses parser fusion.
|
|
62
|
+
This means that a parser of the form e.g. `any(str(...), ..., str())` is automatically converted into a search trie.
|
|
63
|
+
This drastically decreases the number of callbacks, and improves performance because all search strings are checked "at once" by going over the trie.
|
|
64
|
+
|
|
65
|
+
Nested `any` parsers are also supported, as well as `stri` parsers, so all of these undergo fusion:
|
|
66
|
+
|
|
67
|
+
any(str('QeQMTvqJuS'), str('IoOYSLNPlM'), str('SpFMUWpzHs'))
|
|
68
|
+
|
|
69
|
+
any(str('QeQMTvqJuS'), any(str('IoOYSLNPlM'), str('SpFMUWpzHs')))
|
|
70
|
+
|
|
71
|
+
any(str('QeQMTvqJuS'), stri('QeQMTvqJuS'), str('QeqmtabeacErEmTDUUIFcFpsAJhfwqXN'), str('SpFMUWpzHs'))
|
|
48
72
|
|
|
49
73
|
### Example usage:
|
|
50
74
|
|
|
@@ -81,3 +105,24 @@ A library of parser combinators, with which you can create your own parsers.
|
|
|
81
105
|
'The number must be over 1.5!'
|
|
82
106
|
);
|
|
83
107
|
const result = ParseText(' number: 1.25 ', parser); // Will throw a ParseError('The number must be over 1.5!')
|
|
108
|
+
|
|
109
|
+
##### Pretty messages available on parsing errors:
|
|
110
|
+
|
|
111
|
+
import { spacesPlus, str } from 'parser-combinators/parsers';
|
|
112
|
+
import { ParseText } from 'parser-combinators';
|
|
113
|
+
|
|
114
|
+
const parser = seq(
|
|
115
|
+
str('Lazy fox jumps'), spacesPlus, str('over'), spacesPlus, str('a lazy dog')
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const result = ParseText('Lazy fox jumps under a lazy dog', parser);
|
|
120
|
+
} catch (e) {
|
|
121
|
+
console.error(e.getPrettyErrorMessage());
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
Will write:
|
|
125
|
+
|
|
126
|
+
Parse error, expected over at char 15 (line 1, col 16):
|
|
127
|
+
Lazy fox jumps under a lazy dog
|
|
128
|
+
---------------^
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./parsers"), exports);
|
|
19
|
+
__exportStar(require("./parser"), exports);
|
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
import { Parser } from './types';
|
|
2
|
-
/** Parses the
|
|
3
|
-
* @param
|
|
4
|
-
* @param parser The parser to use.
|
|
5
|
-
* @
|
|
6
|
-
* @
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* @param text The string to parse.
|
|
11
|
-
* @param parser The parser to use.
|
|
12
|
-
* @param path The path of the parsed text. Can be used for error reporting.
|
|
13
|
-
* @returns The result of the parse.
|
|
14
|
-
* @throws {ParseError} if the parsing fails or the parser does not consume the full input.
|
|
15
|
-
*/
|
|
16
|
-
export declare function ParseText<T>(text: string, parser: Parser<T>, path?: string): T;
|
|
1
|
+
import { Parser } from './types';
|
|
2
|
+
/** Parses the given string.
|
|
3
|
+
* @param text The string to parse.
|
|
4
|
+
* @param parser The parser to use.
|
|
5
|
+
* @param path The path of the parsed text. Can be used for error reporting.
|
|
6
|
+
* @returns The result of the parse.
|
|
7
|
+
* @throws {ParseError} if the parsing fails or the parser does not consume the full input.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ParseText<T>(text: string, parser: Parser<T>, path?: string): T;
|
|
@@ -1,34 +1,21 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ParseText =
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* @param
|
|
8
|
-
* @param
|
|
9
|
-
* @returns The result of the parse.
|
|
10
|
-
* @throws {ParseError} if the parsing fails or the parser does not consume the full input.
|
|
11
|
-
*/
|
|
12
|
-
function
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
* @throws {ParseError} if the parsing fails or the parser does not consume the full input.
|
|
23
|
-
*/
|
|
24
|
-
function ParseText(text, parser, path = '') {
|
|
25
|
-
const res = parser({ text, path, index: 0 });
|
|
26
|
-
if ((0, types_1.isFailure)(res)) {
|
|
27
|
-
throw new types_1.ParseError(`Parse error, expected ${[...res.history].pop()} at char ${res.ctx.index}`, text, res.ctx.index, res.history);
|
|
28
|
-
}
|
|
29
|
-
if (res.ctx.index !== text.length) {
|
|
30
|
-
throw new types_1.ParseError(`Parse error at index ${res.ctx.index}`, text, res.ctx.index, []);
|
|
31
|
-
}
|
|
32
|
-
return res.value;
|
|
33
|
-
}
|
|
34
|
-
exports.ParseText = ParseText;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ParseText = ParseText;
|
|
4
|
+
const types_1 = require("./types");
|
|
5
|
+
/** Parses the given string.
|
|
6
|
+
* @param text The string to parse.
|
|
7
|
+
* @param parser The parser to use.
|
|
8
|
+
* @param path The path of the parsed text. Can be used for error reporting.
|
|
9
|
+
* @returns The result of the parse.
|
|
10
|
+
* @throws {ParseError} if the parsing fails or the parser does not consume the full input.
|
|
11
|
+
*/
|
|
12
|
+
function ParseText(text, parser, path = '') {
|
|
13
|
+
const res = parser({ text, path, index: 0 });
|
|
14
|
+
if ((0, types_1.isFailure)(res)) {
|
|
15
|
+
throw new types_1.ParseError(`Parse error, expected ${[...res.history].pop()} at char ${res.ctx.index}`, text, res.ctx.index, res.history);
|
|
16
|
+
}
|
|
17
|
+
if (res.ctx.index !== text.length) {
|
|
18
|
+
throw new types_1.ParseError(`Parse error, expected end of text at char ${res.ctx.index}`, text, res.ctx.index, []);
|
|
19
|
+
}
|
|
20
|
+
return res.value;
|
|
21
|
+
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { Parser } from '../types';
|
|
2
|
-
/** Parses the input using any passed parser, trying from left to right.
|
|
3
|
-
* @returns A parser returning the result of the first parser that succeeds, or the failure that has come the furthest.
|
|
4
|
-
*/
|
|
5
|
-
export declare function any<T, U, V, W, X, Z, I, J, K, L, M>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>, Parser<L>, Parser<M>]): Parser<T | U | V | W | X | Z | I | J | K | L | M>;
|
|
6
|
-
export declare function any<T, U, V, W, X, Z, I, J, K, L>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>, Parser<L>]): Parser<T | U | V | W | X | Z | I | J | K | L>;
|
|
7
|
-
export declare function any<T, U, V, W, X, Z, I, J, K>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>]): Parser<T | U | V | W | X | Z | I | J | K>;
|
|
8
|
-
export declare function any<T, U, V, W, X, Z, I, J>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>]): Parser<T | U | V | W | X | Z | I | J>;
|
|
9
|
-
export declare function any<T, U, V, W, X, Z, I>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>]): Parser<T | U | V | W | X | Z | I>;
|
|
10
|
-
export declare function any<T, U, V, W, X, Z>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>]): Parser<T | U | V | W | X | Z>;
|
|
11
|
-
export declare function any<T, U, V, W, X>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>]): Parser<T | U | V | W | X>;
|
|
12
|
-
export declare function any<T, U, V, W>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>]): Parser<T | U | V | W>;
|
|
13
|
-
export declare function any<T, U, V>(...parsers: [Parser<T>, Parser<U>, Parser<V>]): Parser<T | U | V>;
|
|
14
|
-
export declare function any<T, U>(...parsers: [Parser<T>, Parser<U>]): Parser<T | U>;
|
|
15
|
-
export declare function any<T>(...parsers: [Parser<T>]): Parser<T>;
|
|
1
|
+
import { Parser } from '../types';
|
|
2
|
+
/** Parses the input using any passed parser, trying from left to right.
|
|
3
|
+
* @returns A parser returning the result of the first parser that succeeds, or the failure that has come the furthest.
|
|
4
|
+
*/
|
|
5
|
+
export declare function any<T, U, V, W, X, Z, I, J, K, L, M>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>, Parser<L>, Parser<M>]): Parser<T | U | V | W | X | Z | I | J | K | L | M>;
|
|
6
|
+
export declare function any<T, U, V, W, X, Z, I, J, K, L>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>, Parser<L>]): Parser<T | U | V | W | X | Z | I | J | K | L>;
|
|
7
|
+
export declare function any<T, U, V, W, X, Z, I, J, K>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>]): Parser<T | U | V | W | X | Z | I | J | K>;
|
|
8
|
+
export declare function any<T, U, V, W, X, Z, I, J>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>]): Parser<T | U | V | W | X | Z | I | J>;
|
|
9
|
+
export declare function any<T, U, V, W, X, Z, I>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>]): Parser<T | U | V | W | X | Z | I>;
|
|
10
|
+
export declare function any<T, U, V, W, X, Z>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>]): Parser<T | U | V | W | X | Z>;
|
|
11
|
+
export declare function any<T, U, V, W, X>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>]): Parser<T | U | V | W | X>;
|
|
12
|
+
export declare function any<T, U, V, W>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>]): Parser<T | U | V | W>;
|
|
13
|
+
export declare function any<T, U, V>(...parsers: [Parser<T>, Parser<U>, Parser<V>]): Parser<T | U | V>;
|
|
14
|
+
export declare function any<T, U>(...parsers: [Parser<T>, Parser<U>]): Parser<T | U>;
|
|
15
|
+
export declare function any<T>(...parsers: [Parser<T>]): Parser<T>;
|
|
16
|
+
export declare function any<T>(...parsers: Parser<T>[]): Parser<T>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.any = any;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const anyString_1 = require("./anyString");
|
|
6
|
+
const utilities_1 = require("./utilities");
|
|
7
|
+
const optimizableTypes = ['str', 'stri', 'anyString'];
|
|
8
|
+
function any(...parsers) {
|
|
9
|
+
let marker = {};
|
|
10
|
+
if ((0, utilities_1.shouldPerformFusions)() && parsers.every(p => 'parserType' in p && typeof p.parserType === 'string' && optimizableTypes.includes(p.parserType))) {
|
|
11
|
+
const optimizableParsers = parsers;
|
|
12
|
+
const matches = optimizableParsers.flatMap(p => {
|
|
13
|
+
switch (p.parserType) {
|
|
14
|
+
case 'anyString':
|
|
15
|
+
return p.matches;
|
|
16
|
+
case 'str':
|
|
17
|
+
return [[p.match, false]];
|
|
18
|
+
case 'stri':
|
|
19
|
+
return [[p.match, true]];
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
// Not fusing if not enough matches
|
|
23
|
+
// We do pass the matches forward though, because a parser above may want to fuse
|
|
24
|
+
if (matches.length > 10) {
|
|
25
|
+
return (0, anyString_1.anyString)(matches);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
marker = { parserType: 'anyString', matches };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return Object.assign((ctx) => {
|
|
32
|
+
const expected = [];
|
|
33
|
+
for (const parser of parsers) {
|
|
34
|
+
const res = parser(ctx);
|
|
35
|
+
if ((0, types_1.isFailure)(res)) {
|
|
36
|
+
if (res.history.includes('surely')) {
|
|
37
|
+
return (0, types_1.failure)(res.ctx, res.expected, res.history.filter(h => h !== 'surely'));
|
|
38
|
+
}
|
|
39
|
+
expected.push(res);
|
|
40
|
+
}
|
|
41
|
+
else
|
|
42
|
+
return res;
|
|
43
|
+
}
|
|
44
|
+
const longest = expected.reduce((a, b) => a.history.length > b.history.length ? a : b);
|
|
45
|
+
return (0, types_1.failure)(longest.ctx, longest.expected, ['any', ...longest.history]);
|
|
46
|
+
}, marker);
|
|
47
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Parser } from "../types";
|
|
2
|
+
import { StrIParser, StrParser } from "./str";
|
|
3
|
+
type AnyStringParser<T> = Parser<T> & {
|
|
4
|
+
parserType: 'anyString';
|
|
5
|
+
/**
|
|
6
|
+
* if flag is true, match case-insensitive
|
|
7
|
+
*/
|
|
8
|
+
matches: (readonly [string, boolean])[];
|
|
9
|
+
};
|
|
10
|
+
export type OptimizableStrParser<T> = AnyStringParser<T> | StrParser<T> | StrIParser<T>;
|
|
11
|
+
/**
|
|
12
|
+
* Optimization for `any(str(), str(), ...)` which replaces the parser tree with one parser which tries all strings together
|
|
13
|
+
*/
|
|
14
|
+
export declare function anyString<T extends string>(matches: (readonly [string, boolean])[]): AnyStringParser<T>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.anyString = anyString;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
/**
|
|
6
|
+
* Optimization for `any(str(), str(), ...)` which replaces the parser tree with one parser which tries all strings together
|
|
7
|
+
*/
|
|
8
|
+
function anyString(matches) {
|
|
9
|
+
const lastMatchInQuotes = `'${matches[matches.length - 1][0]}'`;
|
|
10
|
+
let tree;
|
|
11
|
+
return Object.assign((ctx) => {
|
|
12
|
+
tree ??= createSearchTree(matches);
|
|
13
|
+
const result = searchThroughTree(tree, ctx.text, ctx.index);
|
|
14
|
+
if (result) {
|
|
15
|
+
return (0, types_1.success)({ ...ctx, index: result.end }, matches[result.matchIndex][0]);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
return (0, types_1.failure)(ctx, lastMatchInQuotes, ['any', lastMatchInQuotes]);
|
|
19
|
+
}
|
|
20
|
+
}, { parserType: 'anyString', matches });
|
|
21
|
+
}
|
|
22
|
+
function createSearchTree(matches) {
|
|
23
|
+
const tree = new Map();
|
|
24
|
+
matches.forEach((match, index) => addMatchToTree(tree, match, index));
|
|
25
|
+
return tree;
|
|
26
|
+
}
|
|
27
|
+
function addMatchToTree(node, match, idIndex, charIndex = 0) {
|
|
28
|
+
if (charIndex >= match[0].length) {
|
|
29
|
+
if (node.matchIndex != undefined) {
|
|
30
|
+
node.matchIndex = Math.min(node.matchIndex, idIndex);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
node.matchIndex = idIndex;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
const char = match[0][charIndex];
|
|
38
|
+
const lowercase = char.toLowerCase();
|
|
39
|
+
const uppercase = char.toUpperCase();
|
|
40
|
+
const newNode = new Map();
|
|
41
|
+
if (match[1] && (lowercase !== uppercase)) {
|
|
42
|
+
const lower = node.get(lowercase) ?? newNode;
|
|
43
|
+
const upper = node.get(uppercase) ?? newNode;
|
|
44
|
+
node.set(lowercase, lower);
|
|
45
|
+
node.set(uppercase, upper);
|
|
46
|
+
addMatchToTree(lower, match, idIndex, charIndex + 1);
|
|
47
|
+
if (lower !== upper) {
|
|
48
|
+
addMatchToTree(upper, match, idIndex, charIndex + 1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const charNode = node.get(char) ?? newNode;
|
|
53
|
+
node.set(char, charNode);
|
|
54
|
+
const lower = node.get(lowercase);
|
|
55
|
+
if (lower === node.get(uppercase)) {
|
|
56
|
+
const copy = new Map(lower.entries());
|
|
57
|
+
copy.matchIndex = lower.matchIndex;
|
|
58
|
+
node.set(uppercase, copy);
|
|
59
|
+
}
|
|
60
|
+
addMatchToTree(charNode, match, idIndex, charIndex + 1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function searchThroughTree(node, text, start) {
|
|
65
|
+
let lastSuccessIndex = undefined;
|
|
66
|
+
let lastSuccessMatchIndex = undefined;
|
|
67
|
+
let currentNode = node;
|
|
68
|
+
for (let index = start; index < text.length; index++) {
|
|
69
|
+
const char = text[index];
|
|
70
|
+
if (currentNode.matchIndex != undefined && (lastSuccessMatchIndex == undefined || currentNode.matchIndex <= lastSuccessMatchIndex)) {
|
|
71
|
+
lastSuccessIndex = index;
|
|
72
|
+
lastSuccessMatchIndex = currentNode.matchIndex;
|
|
73
|
+
}
|
|
74
|
+
currentNode = currentNode.get(char);
|
|
75
|
+
if (!currentNode)
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
if (currentNode && currentNode.matchIndex != undefined && (lastSuccessMatchIndex == undefined || currentNode.matchIndex <= lastSuccessMatchIndex)) {
|
|
79
|
+
lastSuccessIndex = text.length;
|
|
80
|
+
lastSuccessMatchIndex = currentNode.matchIndex;
|
|
81
|
+
}
|
|
82
|
+
return lastSuccessIndex == undefined
|
|
83
|
+
? undefined
|
|
84
|
+
: { end: lastSuccessIndex, matchIndex: lastSuccessMatchIndex };
|
|
85
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Parser } from '../types';
|
|
2
|
-
/** Parses a sequence of three parsers.
|
|
3
|
-
* @returns A parser returning only the middle parser's result.
|
|
4
|
-
*/
|
|
5
|
-
export declare function between<T, U, V>(left: Parser<U>, parser: Parser<T>, right: Parser<V>): Parser<T>;
|
|
1
|
+
import { Parser } from '../types';
|
|
2
|
+
/** Parses a sequence of three parsers.
|
|
3
|
+
* @returns A parser returning only the middle parser's result.
|
|
4
|
+
*/
|
|
5
|
+
export declare function between<T, U, V>(left: Parser<U>, parser: Parser<T>, right: Parser<V>): Parser<T>;
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.between =
|
|
4
|
-
const types_1 = require("../types");
|
|
5
|
-
const seq_1 = require("./seq");
|
|
6
|
-
/** Parses a sequence of three parsers.
|
|
7
|
-
* @returns A parser returning only the middle parser's result.
|
|
8
|
-
*/
|
|
9
|
-
function between(left, parser, right) {
|
|
10
|
-
const sequence = (0, seq_1.seq)(left, parser, right);
|
|
11
|
-
return (ctx) => {
|
|
12
|
-
const res = sequence(ctx);
|
|
13
|
-
if ((0, types_1.isFailure)(res)) {
|
|
14
|
-
const newHistory = [...res.history];
|
|
15
|
-
newHistory.splice(0, 1);
|
|
16
|
-
return (0, types_1.failure)(res.ctx, res.expected, ['between', ...newHistory]);
|
|
17
|
-
}
|
|
18
|
-
return { ...res, value: res.value[1] };
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
exports.between = between;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.between = between;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const seq_1 = require("./seq");
|
|
6
|
+
/** Parses a sequence of three parsers.
|
|
7
|
+
* @returns A parser returning only the middle parser's result.
|
|
8
|
+
*/
|
|
9
|
+
function between(left, parser, right) {
|
|
10
|
+
const sequence = (0, seq_1.seq)(left, parser, right);
|
|
11
|
+
return (ctx) => {
|
|
12
|
+
const res = sequence(ctx);
|
|
13
|
+
if ((0, types_1.isFailure)(res)) {
|
|
14
|
+
const newHistory = [...res.history];
|
|
15
|
+
newHistory.splice(0, 1);
|
|
16
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['between', ...newHistory]);
|
|
17
|
+
}
|
|
18
|
+
return { ...res, value: res.value[1] };
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Parser } from '../types';
|
|
2
|
-
/** Parses using the passed in parser, until the input is exhausted or until the `until` condition is satisfied.
|
|
3
|
-
* @returns A parser returning an array of parsed results.
|
|
4
|
-
*/
|
|
5
|
-
export declare function exhaust<T, V>(parser: Parser<T>, until?: Parser<V> | null): Parser<T[]>;
|
|
1
|
+
import { Parser } from '../types';
|
|
2
|
+
/** Parses using the passed in parser, until the input is exhausted or until the `until` condition is satisfied.
|
|
3
|
+
* @returns A parser returning an array of parsed results.
|
|
4
|
+
*/
|
|
5
|
+
export declare function exhaust<T, V>(parser: Parser<T>, until?: Parser<V> | null): Parser<T[]>;
|
|
@@ -1,27 +1,25 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.exhaust =
|
|
4
|
-
const types_1 = require("../types");
|
|
5
|
-
/** Parses using the passed in parser, until the input is exhausted or until the `until` condition is satisfied.
|
|
6
|
-
* @returns A parser returning an array of parsed results.
|
|
7
|
-
*/
|
|
8
|
-
function exhaust(parser, until = null) {
|
|
9
|
-
return (ctx) => {
|
|
10
|
-
const results = [];
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
exports.exhaust = exhaust;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.exhaust = exhaust;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
/** Parses using the passed in parser, until the input is exhausted or until the `until` condition is satisfied.
|
|
6
|
+
* @returns A parser returning an array of parsed results.
|
|
7
|
+
*/
|
|
8
|
+
function exhaust(parser, until = null) {
|
|
9
|
+
return (ctx) => {
|
|
10
|
+
const results = [];
|
|
11
|
+
while (true) {
|
|
12
|
+
const res = parser(ctx);
|
|
13
|
+
if ((0, types_1.isFailure)(res)) {
|
|
14
|
+
if (until === null || (0, types_1.isFailure)(until(ctx))) {
|
|
15
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['exhaust', ...res.history]);
|
|
16
|
+
}
|
|
17
|
+
return (0, types_1.success)(ctx, results);
|
|
18
|
+
}
|
|
19
|
+
ctx = res.ctx;
|
|
20
|
+
results.push(res.value);
|
|
21
|
+
if (res.ctx.index === res.ctx.text.length)
|
|
22
|
+
return (0, types_1.success)(res.ctx, results);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
export * from './any';
|
|
2
|
-
export * from './between';
|
|
3
|
-
export * from './exhaust';
|
|
4
|
-
export * from './many';
|
|
5
|
-
export * from './map';
|
|
6
|
-
export * from './opt';
|
|
7
|
-
export * from './regex';
|
|
8
|
-
export * from './seq';
|
|
9
|
-
export
|
|
10
|
-
export * from './
|
|
11
|
-
export * from './
|
|
1
|
+
export * from './any';
|
|
2
|
+
export * from './between';
|
|
3
|
+
export * from './exhaust';
|
|
4
|
+
export * from './many';
|
|
5
|
+
export * from './map';
|
|
6
|
+
export * from './opt';
|
|
7
|
+
export * from './regex';
|
|
8
|
+
export * from './seq';
|
|
9
|
+
export { str, stri } from './str';
|
|
10
|
+
export * from './recovery';
|
|
11
|
+
export * from './utilities';
|
|
12
|
+
export * from './values';
|
|
@@ -1,23 +1,31 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
__exportStar(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
__exportStar(require("./
|
|
19
|
-
__exportStar(require("./
|
|
20
|
-
__exportStar(require("./
|
|
21
|
-
__exportStar(require("./
|
|
22
|
-
__exportStar(require("./
|
|
23
|
-
__exportStar(require("./
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.stri = exports.str = void 0;
|
|
18
|
+
__exportStar(require("./any"), exports);
|
|
19
|
+
__exportStar(require("./between"), exports);
|
|
20
|
+
__exportStar(require("./exhaust"), exports);
|
|
21
|
+
__exportStar(require("./many"), exports);
|
|
22
|
+
__exportStar(require("./map"), exports);
|
|
23
|
+
__exportStar(require("./opt"), exports);
|
|
24
|
+
__exportStar(require("./regex"), exports);
|
|
25
|
+
__exportStar(require("./seq"), exports);
|
|
26
|
+
var str_1 = require("./str");
|
|
27
|
+
Object.defineProperty(exports, "str", { enumerable: true, get: function () { return str_1.str; } });
|
|
28
|
+
Object.defineProperty(exports, "stri", { enumerable: true, get: function () { return str_1.stri; } });
|
|
29
|
+
__exportStar(require("./recovery"), exports);
|
|
30
|
+
__exportStar(require("./utilities"), exports);
|
|
31
|
+
__exportStar(require("./values"), exports);
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { Parser } from '../types';
|
|
2
|
-
/** Parses zero or more occurences of the given parser.
|
|
3
|
-
* @returns A parser returning an array of many parses.
|
|
4
|
-
*/
|
|
5
|
-
export declare function many<T>(parser: Parser<T>): Parser<T[]>;
|
|
6
|
-
/** Parses zero or more occurences of the given parser, separated with the separator parser.
|
|
7
|
-
* @returns A parser returning an array of many parses, omitting the separator.
|
|
8
|
-
*/
|
|
9
|
-
export declare function zeroOrMany<T, V>(item: Parser<T>, separator: Parser<V>): Parser<T[]>;
|
|
10
|
-
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
11
|
-
* @returns A parser returning an array of many parses, omitting the separator.
|
|
12
|
-
*/
|
|
13
|
-
export declare function oneOrMany<T, V>(item: Parser<T>, separator
|
|
14
|
-
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
15
|
-
* @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
|
|
16
|
-
*/
|
|
17
|
-
export declare function oneOrManyRed<T, V, U = T>(item: Parser<T>, separator: Parser<V>, reducer: (left: U | T, right: T, sep: V) => U): Parser<U | T>;
|
|
1
|
+
import { Parser } from '../types';
|
|
2
|
+
/** Parses zero or more occurences of the given parser.
|
|
3
|
+
* @returns A parser returning an array of many parses.
|
|
4
|
+
*/
|
|
5
|
+
export declare function many<T>(parser: Parser<T>): Parser<T[]>;
|
|
6
|
+
/** Parses zero or more occurences of the given parser, separated with the separator parser.
|
|
7
|
+
* @returns A parser returning an array of many parses, omitting the separator.
|
|
8
|
+
*/
|
|
9
|
+
export declare function zeroOrMany<T, V>(item: Parser<T>, separator: Parser<V>): Parser<T[]>;
|
|
10
|
+
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
11
|
+
* @returns A parser returning an array of many parses, omitting the separator.
|
|
12
|
+
*/
|
|
13
|
+
export declare function oneOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
|
|
14
|
+
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
15
|
+
* @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
|
|
16
|
+
*/
|
|
17
|
+
export declare function oneOrManyRed<T, V, U = T>(item: Parser<T>, separator: Parser<V>, reducer: (left: U | T, right: T, sep: V) => U): Parser<U | T>;
|