parser-combinators 1.2.3 → 1.2.6
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/parser.js +1 -1
- package/dist/parsers/any.js +4 -2
- package/dist/parsers/anyString.js +11 -16
- package/dist/parsers/index.d.ts +4 -0
- package/dist/parsers/index.js +4 -0
- package/dist/parsers/many.d.ts +0 -12
- package/dist/parsers/many.js +5 -107
- package/dist/parsers/oneOrMany.d.ts +5 -0
- package/dist/parsers/oneOrMany.js +66 -0
- package/dist/parsers/oneOrManyRed.d.ts +5 -0
- package/dist/parsers/oneOrManyRed.js +44 -0
- package/dist/parsers/readymade.d.ts +7 -0
- package/dist/parsers/readymade.js +46 -0
- package/dist/parsers/regex.js +1 -1
- package/dist/parsers/utilities.js +2 -1
- package/dist/parsers/zeroOrMany.d.ts +5 -0
- package/dist/parsers/zeroOrMany.js +64 -0
- package/dist/types.d.ts +1 -0
- package/dist-esm/parser.js +1 -1
- package/dist-esm/parsers/any.js +4 -2
- package/dist-esm/parsers/anyString.js +11 -16
- package/dist-esm/parsers/index.d.ts +4 -0
- package/dist-esm/parsers/index.js +4 -0
- package/dist-esm/parsers/many.d.ts +0 -12
- package/dist-esm/parsers/many.js +5 -104
- package/dist-esm/parsers/oneOrMany.d.ts +5 -0
- package/dist-esm/parsers/oneOrMany.js +63 -0
- package/dist-esm/parsers/oneOrManyRed.d.ts +5 -0
- package/dist-esm/parsers/oneOrManyRed.js +41 -0
- package/dist-esm/parsers/readymade.d.ts +7 -0
- package/dist-esm/parsers/readymade.js +43 -0
- package/dist-esm/parsers/regex.js +1 -1
- package/dist-esm/parsers/utilities.js +2 -1
- package/dist-esm/parsers/zeroOrMany.d.ts +5 -0
- package/dist-esm/parsers/zeroOrMany.js +61 -0
- package/dist-esm/types.d.ts +1 -0
- package/package.json +61 -61
package/dist/parser.js
CHANGED
|
@@ -12,7 +12,7 @@ const types_1 = require("./types");
|
|
|
12
12
|
function ParseText(text, parser, path = '') {
|
|
13
13
|
const res = parser({ text, path, index: 0 });
|
|
14
14
|
if ((0, types_1.isFailure)(res)) {
|
|
15
|
-
throw new types_1.ParseError(`Parse error, expected ${[
|
|
15
|
+
throw new types_1.ParseError(`Parse error, expected ${res.history[res.history.length - 1]} at char ${res.ctx.index}`, text, res.ctx.index, res.history);
|
|
16
16
|
}
|
|
17
17
|
if (res.ctx.index !== text.length) {
|
|
18
18
|
throw new types_1.ParseError(`Parse error, expected end of text at char ${res.ctx.index}`, text, res.ctx.index, []);
|
package/dist/parsers/any.js
CHANGED
|
@@ -22,8 +22,10 @@ function any(...parsers) {
|
|
|
22
22
|
for (const parser of parsers) {
|
|
23
23
|
const res = parser(ctx);
|
|
24
24
|
if ((0, types_1.isFailure)(res)) {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
26
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
27
|
+
if (surelyIndex >= 0) {
|
|
28
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['any', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
27
29
|
}
|
|
28
30
|
expected.push(res);
|
|
29
31
|
}
|
|
@@ -26,14 +26,7 @@ function createSearchTree(matches) {
|
|
|
26
26
|
}
|
|
27
27
|
function addMatchToTree(node, match, idIndex, charIndex = 0) {
|
|
28
28
|
if (charIndex >= match[0].length) {
|
|
29
|
-
|
|
30
|
-
if (node.matchIndex > idIndex) {
|
|
31
|
-
node.matchIndex = idIndex;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
node.matchIndex = idIndex;
|
|
36
|
-
}
|
|
29
|
+
node.matchIndex ??= idIndex;
|
|
37
30
|
}
|
|
38
31
|
else {
|
|
39
32
|
const char = match[0][charIndex];
|
|
@@ -51,15 +44,17 @@ function addMatchToTree(node, match, idIndex, charIndex = 0) {
|
|
|
51
44
|
}
|
|
52
45
|
}
|
|
53
46
|
else {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
47
|
+
node.set(char, node.get(char) ?? newNode);
|
|
48
|
+
if (lowercase !== uppercase) {
|
|
49
|
+
const lower = node.get(lowercase);
|
|
50
|
+
const upper = node.get(uppercase);
|
|
51
|
+
if (lower != null && lower === upper) {
|
|
52
|
+
const copy = new Map(lower.entries());
|
|
53
|
+
copy.matchIndex = lower.matchIndex;
|
|
54
|
+
node.set(uppercase, copy);
|
|
55
|
+
}
|
|
61
56
|
}
|
|
62
|
-
addMatchToTree(
|
|
57
|
+
addMatchToTree(node.get(char), match, idIndex, charIndex + 1);
|
|
63
58
|
}
|
|
64
59
|
}
|
|
65
60
|
}
|
package/dist/parsers/index.d.ts
CHANGED
|
@@ -2,6 +2,9 @@ export * from './any';
|
|
|
2
2
|
export * from './between';
|
|
3
3
|
export * from './exhaust';
|
|
4
4
|
export * from './many';
|
|
5
|
+
export * from './zeroOrMany';
|
|
6
|
+
export * from './oneOrMany';
|
|
7
|
+
export * from './oneOrManyRed';
|
|
5
8
|
export * from './map';
|
|
6
9
|
export * from './opt';
|
|
7
10
|
export * from './regex';
|
|
@@ -10,3 +13,4 @@ export { str, stri } from './str';
|
|
|
10
13
|
export * from './recovery';
|
|
11
14
|
export * from './utilities';
|
|
12
15
|
export * from './values';
|
|
16
|
+
export * from './readymade';
|
package/dist/parsers/index.js
CHANGED
|
@@ -19,6 +19,9 @@ __exportStar(require("./any"), exports);
|
|
|
19
19
|
__exportStar(require("./between"), exports);
|
|
20
20
|
__exportStar(require("./exhaust"), exports);
|
|
21
21
|
__exportStar(require("./many"), exports);
|
|
22
|
+
__exportStar(require("./zeroOrMany"), exports);
|
|
23
|
+
__exportStar(require("./oneOrMany"), exports);
|
|
24
|
+
__exportStar(require("./oneOrManyRed"), exports);
|
|
22
25
|
__exportStar(require("./map"), exports);
|
|
23
26
|
__exportStar(require("./opt"), exports);
|
|
24
27
|
__exportStar(require("./regex"), exports);
|
|
@@ -29,3 +32,4 @@ Object.defineProperty(exports, "stri", { enumerable: true, get: function () { re
|
|
|
29
32
|
__exportStar(require("./recovery"), exports);
|
|
30
33
|
__exportStar(require("./utilities"), exports);
|
|
31
34
|
__exportStar(require("./values"), exports);
|
|
35
|
+
__exportStar(require("./readymade"), exports);
|
package/dist/parsers/many.d.ts
CHANGED
|
@@ -3,15 +3,3 @@ import { Parser } from "../types";
|
|
|
3
3
|
* @returns A parser returning an array of many parses.
|
|
4
4
|
*/
|
|
5
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> | undefined): 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>;
|
package/dist/parsers/many.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.many = many;
|
|
4
|
-
exports.zeroOrMany = zeroOrMany;
|
|
5
|
-
exports.oneOrMany = oneOrMany;
|
|
6
|
-
exports.oneOrManyRed = oneOrManyRed;
|
|
7
4
|
const types_1 = require("../types");
|
|
8
5
|
/** Parses zero or more occurences of the given parser.
|
|
9
6
|
* @returns A parser returning an array of many parses.
|
|
@@ -14,114 +11,15 @@ function many(parser) {
|
|
|
14
11
|
while (true) {
|
|
15
12
|
const res = parser(ctx);
|
|
16
13
|
if ((0, types_1.isFailure)(res)) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
/** Parses zero or more occurences of the given parser, separated with the separator parser.
|
|
25
|
-
* @returns A parser returning an array of many parses, omitting the separator.
|
|
26
|
-
*/
|
|
27
|
-
function zeroOrMany(item, separator = undefined) {
|
|
28
|
-
if (separator) {
|
|
29
|
-
return (ctx) => {
|
|
30
|
-
const results = [];
|
|
31
|
-
const res = item(ctx);
|
|
32
|
-
if ((0, types_1.isFailure)(res)) {
|
|
33
|
-
return (0, types_1.success)(ctx, results);
|
|
34
|
-
}
|
|
35
|
-
ctx = res.ctx;
|
|
36
|
-
results.push(res.value);
|
|
37
|
-
while (true) {
|
|
38
|
-
const resSep = separator(ctx);
|
|
39
|
-
if ((0, types_1.isFailure)(resSep)) {
|
|
40
|
-
return (0, types_1.success)(ctx, results);
|
|
41
|
-
}
|
|
42
|
-
const res = item(resSep.ctx);
|
|
43
|
-
if ((0, types_1.isFailure)(res)) {
|
|
44
|
-
return (0, types_1.success)(ctx, results);
|
|
45
|
-
}
|
|
46
|
-
ctx = res.ctx;
|
|
47
|
-
results.push(res.value);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
else
|
|
52
|
-
return many(item);
|
|
53
|
-
}
|
|
54
|
-
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
55
|
-
* @returns A parser returning an array of many parses, omitting the separator.
|
|
56
|
-
*/
|
|
57
|
-
function oneOrMany(item, separator = undefined) {
|
|
58
|
-
if (separator) {
|
|
59
|
-
return (ctx) => {
|
|
60
|
-
const results = [];
|
|
61
|
-
const res = item(ctx);
|
|
62
|
-
if ((0, types_1.isFailure)(res))
|
|
63
|
-
return res;
|
|
64
|
-
ctx = res.ctx;
|
|
65
|
-
results.push(res.value);
|
|
66
|
-
while (true) {
|
|
67
|
-
const resSep = separator(ctx);
|
|
68
|
-
if ((0, types_1.isFailure)(resSep)) {
|
|
69
|
-
return (0, types_1.success)(ctx, results);
|
|
14
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
15
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
16
|
+
if (surelyIndex >= 0) {
|
|
17
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['many', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
70
18
|
}
|
|
71
|
-
|
|
72
|
-
if ((0, types_1.isFailure)(res)) {
|
|
73
|
-
return (0, types_1.success)(ctx, results);
|
|
74
|
-
}
|
|
75
|
-
ctx = res.ctx;
|
|
76
|
-
results.push(res.value);
|
|
19
|
+
return (0, types_1.success)(ctx, results);
|
|
77
20
|
}
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
return (ctx) => {
|
|
82
|
-
const results = [];
|
|
83
|
-
const res = item(ctx);
|
|
84
|
-
if ((0, types_1.isFailure)(res))
|
|
85
|
-
return res;
|
|
86
21
|
ctx = res.ctx;
|
|
87
22
|
results.push(res.value);
|
|
88
|
-
while (true) {
|
|
89
|
-
const res = item(ctx);
|
|
90
|
-
if ((0, types_1.isFailure)(res)) {
|
|
91
|
-
return (0, types_1.success)(ctx, results);
|
|
92
|
-
}
|
|
93
|
-
ctx = res.ctx;
|
|
94
|
-
results.push(res.value);
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
100
|
-
* @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
|
|
101
|
-
*/
|
|
102
|
-
function oneOrManyRed(item, separator, reducer) {
|
|
103
|
-
return (ctx) => {
|
|
104
|
-
const res = item(ctx);
|
|
105
|
-
if ((0, types_1.isFailure)(res))
|
|
106
|
-
return res;
|
|
107
|
-
ctx = res.ctx;
|
|
108
|
-
let result = res.value;
|
|
109
|
-
while (true) {
|
|
110
|
-
const resSep = separator(ctx);
|
|
111
|
-
if ((0, types_1.isFailure)(resSep)) {
|
|
112
|
-
return (0, types_1.success)(ctx, result);
|
|
113
|
-
}
|
|
114
|
-
const res = item(resSep.ctx);
|
|
115
|
-
if ((0, types_1.isFailure)(res)) {
|
|
116
|
-
return (0, types_1.success)(ctx, result);
|
|
117
|
-
}
|
|
118
|
-
ctx = res.ctx;
|
|
119
|
-
try {
|
|
120
|
-
result = reducer(result, res.value, resSep.value);
|
|
121
|
-
}
|
|
122
|
-
catch {
|
|
123
|
-
return (0, types_1.failure)(res.ctx, 'Error while reducing', ['oneOrManyRed']);
|
|
124
|
-
}
|
|
125
23
|
}
|
|
126
24
|
};
|
|
127
25
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Parser } from "../types";
|
|
2
|
+
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
3
|
+
* @returns A parser returning an array of many parses, omitting the separator.
|
|
4
|
+
*/
|
|
5
|
+
export declare function oneOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oneOrMany = oneOrMany;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
6
|
+
* @returns A parser returning an array of many parses, omitting the separator.
|
|
7
|
+
*/
|
|
8
|
+
function oneOrMany(item, separator = undefined) {
|
|
9
|
+
if (separator) {
|
|
10
|
+
return (ctx) => {
|
|
11
|
+
const results = [];
|
|
12
|
+
const res = item(ctx);
|
|
13
|
+
if ((0, types_1.isFailure)(res)) {
|
|
14
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['oneOrMany', ...res.history]);
|
|
15
|
+
}
|
|
16
|
+
ctx = res.ctx;
|
|
17
|
+
results.push(res.value);
|
|
18
|
+
while (true) {
|
|
19
|
+
const resSep = separator(ctx);
|
|
20
|
+
if ((0, types_1.isFailure)(resSep)) {
|
|
21
|
+
const surelyIndex = resSep.history.findIndex(h => h === 'surely');
|
|
22
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
23
|
+
if (surelyIndex >= 0) {
|
|
24
|
+
return (0, types_1.failure)(resSep.ctx, resSep.expected, ['oneOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
|
|
25
|
+
}
|
|
26
|
+
return (0, types_1.success)(ctx, results);
|
|
27
|
+
}
|
|
28
|
+
const res = item(resSep.ctx);
|
|
29
|
+
if ((0, types_1.isFailure)(res)) {
|
|
30
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
31
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
32
|
+
if (surelyIndex >= 0) {
|
|
33
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
34
|
+
}
|
|
35
|
+
return (0, types_1.success)(ctx, results);
|
|
36
|
+
}
|
|
37
|
+
ctx = res.ctx;
|
|
38
|
+
results.push(res.value);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return (ctx) => {
|
|
44
|
+
const results = [];
|
|
45
|
+
const res = item(ctx);
|
|
46
|
+
if ((0, types_1.isFailure)(res)) {
|
|
47
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['oneOrMany', ...res.history]);
|
|
48
|
+
}
|
|
49
|
+
ctx = res.ctx;
|
|
50
|
+
results.push(res.value);
|
|
51
|
+
while (true) {
|
|
52
|
+
const res = item(ctx);
|
|
53
|
+
if ((0, types_1.isFailure)(res)) {
|
|
54
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
55
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
56
|
+
if (surelyIndex >= 0) {
|
|
57
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
58
|
+
}
|
|
59
|
+
return (0, types_1.success)(ctx, results);
|
|
60
|
+
}
|
|
61
|
+
ctx = res.ctx;
|
|
62
|
+
results.push(res.value);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Parser } from "../types";
|
|
2
|
+
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
3
|
+
* @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
|
|
4
|
+
*/
|
|
5
|
+
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>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oneOrManyRed = oneOrManyRed;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
6
|
+
* @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
|
|
7
|
+
*/
|
|
8
|
+
function oneOrManyRed(item, separator, reducer) {
|
|
9
|
+
return (ctx) => {
|
|
10
|
+
const res = item(ctx);
|
|
11
|
+
if ((0, types_1.isFailure)(res)) {
|
|
12
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['oneOrManyRed', ...res.history]);
|
|
13
|
+
}
|
|
14
|
+
ctx = res.ctx;
|
|
15
|
+
let result = res.value;
|
|
16
|
+
while (true) {
|
|
17
|
+
const resSep = separator(ctx);
|
|
18
|
+
if ((0, types_1.isFailure)(resSep)) {
|
|
19
|
+
const surelyIndex = resSep.history.findIndex(h => h === 'surely');
|
|
20
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
21
|
+
if (surelyIndex >= 0) {
|
|
22
|
+
return (0, types_1.failure)(resSep.ctx, resSep.expected, ['oneOrManyRed', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
|
|
23
|
+
}
|
|
24
|
+
return (0, types_1.success)(ctx, result);
|
|
25
|
+
}
|
|
26
|
+
const res = item(resSep.ctx);
|
|
27
|
+
if ((0, types_1.isFailure)(res)) {
|
|
28
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
29
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
30
|
+
if (surelyIndex >= 0) {
|
|
31
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['oneOrManyRed', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
32
|
+
}
|
|
33
|
+
return (0, types_1.success)(ctx, result);
|
|
34
|
+
}
|
|
35
|
+
ctx = res.ctx;
|
|
36
|
+
try {
|
|
37
|
+
result = reducer(result, res.value, resSep.value);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return (0, types_1.failure)(res.ctx, 'Error while reducing', ['oneOrManyRed']);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.json = void 0;
|
|
4
|
+
const any_1 = require("./any");
|
|
5
|
+
const between_1 = require("./between");
|
|
6
|
+
const zeroOrMany_1 = require("./zeroOrMany");
|
|
7
|
+
const map_1 = require("./map");
|
|
8
|
+
const regex_1 = require("./regex");
|
|
9
|
+
const seq_1 = require("./seq");
|
|
10
|
+
const str_1 = require("./str");
|
|
11
|
+
const utilities_1 = require("./utilities");
|
|
12
|
+
const WhiteSpace = (0, regex_1.regex)(/\s*/m, 'whitespace');
|
|
13
|
+
const True = (0, map_1.map)((0, str_1.str)("true"), () => true);
|
|
14
|
+
const False = (0, map_1.map)((0, str_1.str)("false"), () => false);
|
|
15
|
+
const Null = (0, map_1.map)((0, str_1.str)("null"), () => null);
|
|
16
|
+
const LCurly = (0, str_1.str)("{");
|
|
17
|
+
const RCurly = (0, utilities_1.surely)((0, str_1.str)("}"));
|
|
18
|
+
const LSquare = (0, str_1.str)("[");
|
|
19
|
+
const RSquare = (0, utilities_1.surely)((0, str_1.str)("]"));
|
|
20
|
+
const Quote = (0, str_1.str)('"');
|
|
21
|
+
const Comma = (0, str_1.str)(",");
|
|
22
|
+
const Colon = (0, utilities_1.surely)((0, str_1.str)(":"));
|
|
23
|
+
const replacements = {
|
|
24
|
+
'\\\\': '\\',
|
|
25
|
+
'\\0': '\0',
|
|
26
|
+
'\\b': '\b',
|
|
27
|
+
'\\f': '\f',
|
|
28
|
+
'\\n': '\n',
|
|
29
|
+
'\\r': '\r',
|
|
30
|
+
'\\t': '\t',
|
|
31
|
+
'\\v': '\v',
|
|
32
|
+
'\\"': '"'
|
|
33
|
+
};
|
|
34
|
+
const StringLiteral = (0, between_1.between)(Quote, (0, map_1.map)((0, regex_1.regex)(/(?:[^\\"]|\\(?:[0bfnrtv"\\]|u[0-9a-fA-F]{4}))*/, 'string literal'), str => str.replace(/\\(?:[0bfnrtv"\\]|u[0-9a-fA-F]{4})/g, function (replace) {
|
|
35
|
+
const tabled = replacements[replace];
|
|
36
|
+
if (tabled != null) {
|
|
37
|
+
return tabled;
|
|
38
|
+
}
|
|
39
|
+
return String.fromCharCode(parseInt(replace.slice(2), 16));
|
|
40
|
+
})), Quote);
|
|
41
|
+
const NumberLiteral = (0, map_1.map)((0, regex_1.regex)(/-?(?:0|(?:[1-9]\d*))(?:\.\d+)?(?:[eE][+-]?\d+)?/, 'number literal'), parseFloat);
|
|
42
|
+
const JArray = (0, utilities_1.lazy)(() => (0, map_1.map)((0, seq_1.seq)(LSquare, (0, utilities_1.surely)((0, seq_1.seq)(WhiteSpace, (0, zeroOrMany_1.zeroOrMany)(Value, (0, seq_1.seq)(WhiteSpace, Comma, WhiteSpace)), WhiteSpace, RSquare))), (data) => data[1][1]));
|
|
43
|
+
const JObject = (0, utilities_1.lazy)(() => (0, map_1.map)((0, seq_1.seq)(LCurly, (0, utilities_1.surely)((0, seq_1.seq)(WhiteSpace, (0, zeroOrMany_1.zeroOrMany)(ObjectEntry, (0, seq_1.seq)(WhiteSpace, Comma, WhiteSpace)), WhiteSpace, RCurly))), data => Object.fromEntries(data[1][1])));
|
|
44
|
+
const Value = (0, any_1.any)(StringLiteral, NumberLiteral, JObject, JArray, True, False, Null);
|
|
45
|
+
const ObjectEntry = (0, map_1.map)((0, seq_1.seq)(StringLiteral, (0, utilities_1.surely)((0, seq_1.seq)(WhiteSpace, Colon, WhiteSpace, Value))), ([key, rest]) => [key, rest[3]]);
|
|
46
|
+
exports.json = (0, between_1.between)(WhiteSpace, Value, WhiteSpace);
|
package/dist/parsers/regex.js
CHANGED
|
@@ -10,7 +10,7 @@ function regex(match, expected) {
|
|
|
10
10
|
return (ctx) => {
|
|
11
11
|
regexp.lastIndex = ctx.index;
|
|
12
12
|
const regexMatch = regexp.exec(ctx.text);
|
|
13
|
-
if (regexMatch !== null
|
|
13
|
+
if (regexMatch !== null) {
|
|
14
14
|
return (0, types_1.success)({ ...ctx, index: ctx.index + regexMatch[0].length }, regexMatch[0]);
|
|
15
15
|
}
|
|
16
16
|
else {
|
|
@@ -15,7 +15,8 @@ function ref(parser, check, expected) {
|
|
|
15
15
|
return (ctx) => {
|
|
16
16
|
const res = parser(ctx);
|
|
17
17
|
if (!(0, types_1.isFailure)(res) && !check(res.value)) {
|
|
18
|
-
|
|
18
|
+
const phrase = expected ?? 'check';
|
|
19
|
+
return (0, types_1.failure)(res.ctx, phrase, [`ref: ${phrase}`]);
|
|
19
20
|
}
|
|
20
21
|
return res;
|
|
21
22
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Parser } from "../types";
|
|
2
|
+
/** Parses zero or more occurences of the given parser, separated with the separator parser.
|
|
3
|
+
* @returns A parser returning an array of many parses, omitting the separator.
|
|
4
|
+
*/
|
|
5
|
+
export declare function zeroOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.zeroOrMany = zeroOrMany;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
/** Parses zero or more occurences of the given parser, separated with the separator parser.
|
|
6
|
+
* @returns A parser returning an array of many parses, omitting the separator.
|
|
7
|
+
*/
|
|
8
|
+
function zeroOrMany(item, separator = undefined) {
|
|
9
|
+
if (separator) {
|
|
10
|
+
return (ctx) => {
|
|
11
|
+
const results = [];
|
|
12
|
+
const res = item(ctx);
|
|
13
|
+
if ((0, types_1.isFailure)(res)) {
|
|
14
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
15
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
16
|
+
if (surelyIndex >= 0) {
|
|
17
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
18
|
+
}
|
|
19
|
+
return (0, types_1.success)(ctx, results);
|
|
20
|
+
}
|
|
21
|
+
ctx = res.ctx;
|
|
22
|
+
results.push(res.value);
|
|
23
|
+
while (true) {
|
|
24
|
+
const resSep = separator(ctx);
|
|
25
|
+
if ((0, types_1.isFailure)(resSep)) {
|
|
26
|
+
const surelyIndex = resSep.history.findIndex(h => h === 'surely');
|
|
27
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
28
|
+
if (surelyIndex >= 0) {
|
|
29
|
+
return (0, types_1.failure)(resSep.ctx, resSep.expected, ['zeroOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
|
|
30
|
+
}
|
|
31
|
+
return (0, types_1.success)(ctx, results);
|
|
32
|
+
}
|
|
33
|
+
const res = item(resSep.ctx);
|
|
34
|
+
if ((0, types_1.isFailure)(res)) {
|
|
35
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
36
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
37
|
+
if (surelyIndex >= 0) {
|
|
38
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
39
|
+
}
|
|
40
|
+
return (0, types_1.success)(ctx, results);
|
|
41
|
+
}
|
|
42
|
+
ctx = res.ctx;
|
|
43
|
+
results.push(res.value);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
else
|
|
48
|
+
return (ctx) => {
|
|
49
|
+
const results = [];
|
|
50
|
+
while (true) {
|
|
51
|
+
const res = item(ctx);
|
|
52
|
+
if ((0, types_1.isFailure)(res)) {
|
|
53
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
54
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
55
|
+
if (surelyIndex >= 0) {
|
|
56
|
+
return (0, types_1.failure)(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
57
|
+
}
|
|
58
|
+
return (0, types_1.success)(ctx, results);
|
|
59
|
+
}
|
|
60
|
+
ctx = res.ctx;
|
|
61
|
+
results.push(res.value);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
package/dist/types.d.ts
CHANGED
package/dist-esm/parser.js
CHANGED
|
@@ -9,7 +9,7 @@ import { isFailure, ParseError } from './types';
|
|
|
9
9
|
export function ParseText(text, parser, path = '') {
|
|
10
10
|
const res = parser({ text, path, index: 0 });
|
|
11
11
|
if (isFailure(res)) {
|
|
12
|
-
throw new ParseError(`Parse error, expected ${[
|
|
12
|
+
throw new ParseError(`Parse error, expected ${res.history[res.history.length - 1]} at char ${res.ctx.index}`, text, res.ctx.index, res.history);
|
|
13
13
|
}
|
|
14
14
|
if (res.ctx.index !== text.length) {
|
|
15
15
|
throw new ParseError(`Parse error, expected end of text at char ${res.ctx.index}`, text, res.ctx.index, []);
|
package/dist-esm/parsers/any.js
CHANGED
|
@@ -19,8 +19,10 @@ export function any(...parsers) {
|
|
|
19
19
|
for (const parser of parsers) {
|
|
20
20
|
const res = parser(ctx);
|
|
21
21
|
if (isFailure(res)) {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
23
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
24
|
+
if (surelyIndex >= 0) {
|
|
25
|
+
return failure(res.ctx, res.expected, ['any', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
24
26
|
}
|
|
25
27
|
expected.push(res);
|
|
26
28
|
}
|
|
@@ -23,14 +23,7 @@ function createSearchTree(matches) {
|
|
|
23
23
|
}
|
|
24
24
|
function addMatchToTree(node, match, idIndex, charIndex = 0) {
|
|
25
25
|
if (charIndex >= match[0].length) {
|
|
26
|
-
|
|
27
|
-
if (node.matchIndex > idIndex) {
|
|
28
|
-
node.matchIndex = idIndex;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
node.matchIndex = idIndex;
|
|
33
|
-
}
|
|
26
|
+
node.matchIndex ??= idIndex;
|
|
34
27
|
}
|
|
35
28
|
else {
|
|
36
29
|
const char = match[0][charIndex];
|
|
@@ -48,15 +41,17 @@ function addMatchToTree(node, match, idIndex, charIndex = 0) {
|
|
|
48
41
|
}
|
|
49
42
|
}
|
|
50
43
|
else {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
44
|
+
node.set(char, node.get(char) ?? newNode);
|
|
45
|
+
if (lowercase !== uppercase) {
|
|
46
|
+
const lower = node.get(lowercase);
|
|
47
|
+
const upper = node.get(uppercase);
|
|
48
|
+
if (lower != null && lower === upper) {
|
|
49
|
+
const copy = new Map(lower.entries());
|
|
50
|
+
copy.matchIndex = lower.matchIndex;
|
|
51
|
+
node.set(uppercase, copy);
|
|
52
|
+
}
|
|
58
53
|
}
|
|
59
|
-
addMatchToTree(
|
|
54
|
+
addMatchToTree(node.get(char), match, idIndex, charIndex + 1);
|
|
60
55
|
}
|
|
61
56
|
}
|
|
62
57
|
}
|
|
@@ -2,6 +2,9 @@ export * from './any';
|
|
|
2
2
|
export * from './between';
|
|
3
3
|
export * from './exhaust';
|
|
4
4
|
export * from './many';
|
|
5
|
+
export * from './zeroOrMany';
|
|
6
|
+
export * from './oneOrMany';
|
|
7
|
+
export * from './oneOrManyRed';
|
|
5
8
|
export * from './map';
|
|
6
9
|
export * from './opt';
|
|
7
10
|
export * from './regex';
|
|
@@ -10,3 +13,4 @@ export { str, stri } from './str';
|
|
|
10
13
|
export * from './recovery';
|
|
11
14
|
export * from './utilities';
|
|
12
15
|
export * from './values';
|
|
16
|
+
export * from './readymade';
|
|
@@ -2,6 +2,9 @@ export * from './any';
|
|
|
2
2
|
export * from './between';
|
|
3
3
|
export * from './exhaust';
|
|
4
4
|
export * from './many';
|
|
5
|
+
export * from './zeroOrMany';
|
|
6
|
+
export * from './oneOrMany';
|
|
7
|
+
export * from './oneOrManyRed';
|
|
5
8
|
export * from './map';
|
|
6
9
|
export * from './opt';
|
|
7
10
|
export * from './regex';
|
|
@@ -10,3 +13,4 @@ export { str, stri } from './str';
|
|
|
10
13
|
export * from './recovery';
|
|
11
14
|
export * from './utilities';
|
|
12
15
|
export * from './values';
|
|
16
|
+
export * from './readymade';
|
|
@@ -3,15 +3,3 @@ import { Parser } from "../types";
|
|
|
3
3
|
* @returns A parser returning an array of many parses.
|
|
4
4
|
*/
|
|
5
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> | undefined): 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>;
|
package/dist-esm/parsers/many.js
CHANGED
|
@@ -8,114 +8,15 @@ export function many(parser) {
|
|
|
8
8
|
while (true) {
|
|
9
9
|
const res = parser(ctx);
|
|
10
10
|
if (isFailure(res)) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
/** Parses zero or more occurences of the given parser, separated with the separator parser.
|
|
19
|
-
* @returns A parser returning an array of many parses, omitting the separator.
|
|
20
|
-
*/
|
|
21
|
-
export function zeroOrMany(item, separator = undefined) {
|
|
22
|
-
if (separator) {
|
|
23
|
-
return (ctx) => {
|
|
24
|
-
const results = [];
|
|
25
|
-
const res = item(ctx);
|
|
26
|
-
if (isFailure(res)) {
|
|
27
|
-
return success(ctx, results);
|
|
28
|
-
}
|
|
29
|
-
ctx = res.ctx;
|
|
30
|
-
results.push(res.value);
|
|
31
|
-
while (true) {
|
|
32
|
-
const resSep = separator(ctx);
|
|
33
|
-
if (isFailure(resSep)) {
|
|
34
|
-
return success(ctx, results);
|
|
35
|
-
}
|
|
36
|
-
const res = item(resSep.ctx);
|
|
37
|
-
if (isFailure(res)) {
|
|
38
|
-
return success(ctx, results);
|
|
39
|
-
}
|
|
40
|
-
ctx = res.ctx;
|
|
41
|
-
results.push(res.value);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
else
|
|
46
|
-
return many(item);
|
|
47
|
-
}
|
|
48
|
-
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
49
|
-
* @returns A parser returning an array of many parses, omitting the separator.
|
|
50
|
-
*/
|
|
51
|
-
export function oneOrMany(item, separator = undefined) {
|
|
52
|
-
if (separator) {
|
|
53
|
-
return (ctx) => {
|
|
54
|
-
const results = [];
|
|
55
|
-
const res = item(ctx);
|
|
56
|
-
if (isFailure(res))
|
|
57
|
-
return res;
|
|
58
|
-
ctx = res.ctx;
|
|
59
|
-
results.push(res.value);
|
|
60
|
-
while (true) {
|
|
61
|
-
const resSep = separator(ctx);
|
|
62
|
-
if (isFailure(resSep)) {
|
|
63
|
-
return success(ctx, results);
|
|
11
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
12
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
13
|
+
if (surelyIndex >= 0) {
|
|
14
|
+
return failure(res.ctx, res.expected, ['many', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
64
15
|
}
|
|
65
|
-
|
|
66
|
-
if (isFailure(res)) {
|
|
67
|
-
return success(ctx, results);
|
|
68
|
-
}
|
|
69
|
-
ctx = res.ctx;
|
|
70
|
-
results.push(res.value);
|
|
16
|
+
return success(ctx, results);
|
|
71
17
|
}
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
return (ctx) => {
|
|
76
|
-
const results = [];
|
|
77
|
-
const res = item(ctx);
|
|
78
|
-
if (isFailure(res))
|
|
79
|
-
return res;
|
|
80
18
|
ctx = res.ctx;
|
|
81
19
|
results.push(res.value);
|
|
82
|
-
while (true) {
|
|
83
|
-
const res = item(ctx);
|
|
84
|
-
if (isFailure(res)) {
|
|
85
|
-
return success(ctx, results);
|
|
86
|
-
}
|
|
87
|
-
ctx = res.ctx;
|
|
88
|
-
results.push(res.value);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
94
|
-
* @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
|
|
95
|
-
*/
|
|
96
|
-
export function oneOrManyRed(item, separator, reducer) {
|
|
97
|
-
return (ctx) => {
|
|
98
|
-
const res = item(ctx);
|
|
99
|
-
if (isFailure(res))
|
|
100
|
-
return res;
|
|
101
|
-
ctx = res.ctx;
|
|
102
|
-
let result = res.value;
|
|
103
|
-
while (true) {
|
|
104
|
-
const resSep = separator(ctx);
|
|
105
|
-
if (isFailure(resSep)) {
|
|
106
|
-
return success(ctx, result);
|
|
107
|
-
}
|
|
108
|
-
const res = item(resSep.ctx);
|
|
109
|
-
if (isFailure(res)) {
|
|
110
|
-
return success(ctx, result);
|
|
111
|
-
}
|
|
112
|
-
ctx = res.ctx;
|
|
113
|
-
try {
|
|
114
|
-
result = reducer(result, res.value, resSep.value);
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
return failure(res.ctx, 'Error while reducing', ['oneOrManyRed']);
|
|
118
|
-
}
|
|
119
20
|
}
|
|
120
21
|
};
|
|
121
22
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Parser } from "../types";
|
|
2
|
+
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
3
|
+
* @returns A parser returning an array of many parses, omitting the separator.
|
|
4
|
+
*/
|
|
5
|
+
export declare function oneOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { failure, isFailure, success } from "../types";
|
|
2
|
+
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
3
|
+
* @returns A parser returning an array of many parses, omitting the separator.
|
|
4
|
+
*/
|
|
5
|
+
export function oneOrMany(item, separator = undefined) {
|
|
6
|
+
if (separator) {
|
|
7
|
+
return (ctx) => {
|
|
8
|
+
const results = [];
|
|
9
|
+
const res = item(ctx);
|
|
10
|
+
if (isFailure(res)) {
|
|
11
|
+
return failure(res.ctx, res.expected, ['oneOrMany', ...res.history]);
|
|
12
|
+
}
|
|
13
|
+
ctx = res.ctx;
|
|
14
|
+
results.push(res.value);
|
|
15
|
+
while (true) {
|
|
16
|
+
const resSep = separator(ctx);
|
|
17
|
+
if (isFailure(resSep)) {
|
|
18
|
+
const surelyIndex = resSep.history.findIndex(h => h === 'surely');
|
|
19
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
20
|
+
if (surelyIndex >= 0) {
|
|
21
|
+
return failure(resSep.ctx, resSep.expected, ['oneOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
|
|
22
|
+
}
|
|
23
|
+
return success(ctx, results);
|
|
24
|
+
}
|
|
25
|
+
const res = item(resSep.ctx);
|
|
26
|
+
if (isFailure(res)) {
|
|
27
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
28
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
29
|
+
if (surelyIndex >= 0) {
|
|
30
|
+
return failure(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
31
|
+
}
|
|
32
|
+
return success(ctx, results);
|
|
33
|
+
}
|
|
34
|
+
ctx = res.ctx;
|
|
35
|
+
results.push(res.value);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
return (ctx) => {
|
|
41
|
+
const results = [];
|
|
42
|
+
const res = item(ctx);
|
|
43
|
+
if (isFailure(res)) {
|
|
44
|
+
return failure(res.ctx, res.expected, ['oneOrMany', ...res.history]);
|
|
45
|
+
}
|
|
46
|
+
ctx = res.ctx;
|
|
47
|
+
results.push(res.value);
|
|
48
|
+
while (true) {
|
|
49
|
+
const res = item(ctx);
|
|
50
|
+
if (isFailure(res)) {
|
|
51
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
52
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
53
|
+
if (surelyIndex >= 0) {
|
|
54
|
+
return failure(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
55
|
+
}
|
|
56
|
+
return success(ctx, results);
|
|
57
|
+
}
|
|
58
|
+
ctx = res.ctx;
|
|
59
|
+
results.push(res.value);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Parser } from "../types";
|
|
2
|
+
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
3
|
+
* @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
|
|
4
|
+
*/
|
|
5
|
+
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>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { failure, isFailure, success } from "../types";
|
|
2
|
+
/** Parses one or more occurences of the given parser, separated with the separator parser.
|
|
3
|
+
* @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
|
|
4
|
+
*/
|
|
5
|
+
export function oneOrManyRed(item, separator, reducer) {
|
|
6
|
+
return (ctx) => {
|
|
7
|
+
const res = item(ctx);
|
|
8
|
+
if (isFailure(res)) {
|
|
9
|
+
return failure(res.ctx, res.expected, ['oneOrManyRed', ...res.history]);
|
|
10
|
+
}
|
|
11
|
+
ctx = res.ctx;
|
|
12
|
+
let result = res.value;
|
|
13
|
+
while (true) {
|
|
14
|
+
const resSep = separator(ctx);
|
|
15
|
+
if (isFailure(resSep)) {
|
|
16
|
+
const surelyIndex = resSep.history.findIndex(h => h === 'surely');
|
|
17
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
18
|
+
if (surelyIndex >= 0) {
|
|
19
|
+
return failure(resSep.ctx, resSep.expected, ['oneOrManyRed', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
|
|
20
|
+
}
|
|
21
|
+
return success(ctx, result);
|
|
22
|
+
}
|
|
23
|
+
const res = item(resSep.ctx);
|
|
24
|
+
if (isFailure(res)) {
|
|
25
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
26
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
27
|
+
if (surelyIndex >= 0) {
|
|
28
|
+
return failure(res.ctx, res.expected, ['oneOrManyRed', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
29
|
+
}
|
|
30
|
+
return success(ctx, result);
|
|
31
|
+
}
|
|
32
|
+
ctx = res.ctx;
|
|
33
|
+
try {
|
|
34
|
+
result = reducer(result, res.value, resSep.value);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return failure(res.ctx, 'Error while reducing', ['oneOrManyRed']);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { any } from "./any";
|
|
2
|
+
import { between } from "./between";
|
|
3
|
+
import { zeroOrMany } from "./zeroOrMany";
|
|
4
|
+
import { map } from "./map";
|
|
5
|
+
import { regex } from "./regex";
|
|
6
|
+
import { seq } from "./seq";
|
|
7
|
+
import { str } from "./str";
|
|
8
|
+
import { lazy, surely } from "./utilities";
|
|
9
|
+
const WhiteSpace = regex(/\s*/m, 'whitespace');
|
|
10
|
+
const True = map(str("true"), () => true);
|
|
11
|
+
const False = map(str("false"), () => false);
|
|
12
|
+
const Null = map(str("null"), () => null);
|
|
13
|
+
const LCurly = str("{");
|
|
14
|
+
const RCurly = surely(str("}"));
|
|
15
|
+
const LSquare = str("[");
|
|
16
|
+
const RSquare = surely(str("]"));
|
|
17
|
+
const Quote = str('"');
|
|
18
|
+
const Comma = str(",");
|
|
19
|
+
const Colon = surely(str(":"));
|
|
20
|
+
const replacements = {
|
|
21
|
+
'\\\\': '\\',
|
|
22
|
+
'\\0': '\0',
|
|
23
|
+
'\\b': '\b',
|
|
24
|
+
'\\f': '\f',
|
|
25
|
+
'\\n': '\n',
|
|
26
|
+
'\\r': '\r',
|
|
27
|
+
'\\t': '\t',
|
|
28
|
+
'\\v': '\v',
|
|
29
|
+
'\\"': '"'
|
|
30
|
+
};
|
|
31
|
+
const StringLiteral = between(Quote, map(regex(/(?:[^\\"]|\\(?:[0bfnrtv"\\]|u[0-9a-fA-F]{4}))*/, 'string literal'), str => str.replace(/\\(?:[0bfnrtv"\\]|u[0-9a-fA-F]{4})/g, function (replace) {
|
|
32
|
+
const tabled = replacements[replace];
|
|
33
|
+
if (tabled != null) {
|
|
34
|
+
return tabled;
|
|
35
|
+
}
|
|
36
|
+
return String.fromCharCode(parseInt(replace.slice(2), 16));
|
|
37
|
+
})), Quote);
|
|
38
|
+
const NumberLiteral = map(regex(/-?(?:0|(?:[1-9]\d*))(?:\.\d+)?(?:[eE][+-]?\d+)?/, 'number literal'), parseFloat);
|
|
39
|
+
const JArray = lazy(() => map(seq(LSquare, surely(seq(WhiteSpace, zeroOrMany(Value, seq(WhiteSpace, Comma, WhiteSpace)), WhiteSpace, RSquare))), (data) => data[1][1]));
|
|
40
|
+
const JObject = lazy(() => map(seq(LCurly, surely(seq(WhiteSpace, zeroOrMany(ObjectEntry, seq(WhiteSpace, Comma, WhiteSpace)), WhiteSpace, RCurly))), data => Object.fromEntries(data[1][1])));
|
|
41
|
+
const Value = any(StringLiteral, NumberLiteral, JObject, JArray, True, False, Null);
|
|
42
|
+
const ObjectEntry = map(seq(StringLiteral, surely(seq(WhiteSpace, Colon, WhiteSpace, Value))), ([key, rest]) => [key, rest[3]]);
|
|
43
|
+
export const json = between(WhiteSpace, Value, WhiteSpace);
|
|
@@ -7,7 +7,7 @@ export function regex(match, expected) {
|
|
|
7
7
|
return (ctx) => {
|
|
8
8
|
regexp.lastIndex = ctx.index;
|
|
9
9
|
const regexMatch = regexp.exec(ctx.text);
|
|
10
|
-
if (regexMatch !== null
|
|
10
|
+
if (regexMatch !== null) {
|
|
11
11
|
return success({ ...ctx, index: ctx.index + regexMatch[0].length }, regexMatch[0]);
|
|
12
12
|
}
|
|
13
13
|
else {
|
|
@@ -6,7 +6,8 @@ export function ref(parser, check, expected) {
|
|
|
6
6
|
return (ctx) => {
|
|
7
7
|
const res = parser(ctx);
|
|
8
8
|
if (!isFailure(res) && !check(res.value)) {
|
|
9
|
-
|
|
9
|
+
const phrase = expected ?? 'check';
|
|
10
|
+
return failure(res.ctx, phrase, [`ref: ${phrase}`]);
|
|
10
11
|
}
|
|
11
12
|
return res;
|
|
12
13
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Parser } from "../types";
|
|
2
|
+
/** Parses zero or more occurences of the given parser, separated with the separator parser.
|
|
3
|
+
* @returns A parser returning an array of many parses, omitting the separator.
|
|
4
|
+
*/
|
|
5
|
+
export declare function zeroOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { failure, isFailure, success } from "../types";
|
|
2
|
+
/** Parses zero or more occurences of the given parser, separated with the separator parser.
|
|
3
|
+
* @returns A parser returning an array of many parses, omitting the separator.
|
|
4
|
+
*/
|
|
5
|
+
export function zeroOrMany(item, separator = undefined) {
|
|
6
|
+
if (separator) {
|
|
7
|
+
return (ctx) => {
|
|
8
|
+
const results = [];
|
|
9
|
+
const res = item(ctx);
|
|
10
|
+
if (isFailure(res)) {
|
|
11
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
12
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
13
|
+
if (surelyIndex >= 0) {
|
|
14
|
+
return failure(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
15
|
+
}
|
|
16
|
+
return success(ctx, results);
|
|
17
|
+
}
|
|
18
|
+
ctx = res.ctx;
|
|
19
|
+
results.push(res.value);
|
|
20
|
+
while (true) {
|
|
21
|
+
const resSep = separator(ctx);
|
|
22
|
+
if (isFailure(resSep)) {
|
|
23
|
+
const surelyIndex = resSep.history.findIndex(h => h === 'surely');
|
|
24
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
25
|
+
if (surelyIndex >= 0) {
|
|
26
|
+
return failure(resSep.ctx, resSep.expected, ['zeroOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
|
|
27
|
+
}
|
|
28
|
+
return success(ctx, results);
|
|
29
|
+
}
|
|
30
|
+
const res = item(resSep.ctx);
|
|
31
|
+
if (isFailure(res)) {
|
|
32
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
33
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
34
|
+
if (surelyIndex >= 0) {
|
|
35
|
+
return failure(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
36
|
+
}
|
|
37
|
+
return success(ctx, results);
|
|
38
|
+
}
|
|
39
|
+
ctx = res.ctx;
|
|
40
|
+
results.push(res.value);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
else
|
|
45
|
+
return (ctx) => {
|
|
46
|
+
const results = [];
|
|
47
|
+
while (true) {
|
|
48
|
+
const res = item(ctx);
|
|
49
|
+
if (isFailure(res)) {
|
|
50
|
+
const surelyIndex = res.history.findIndex(h => h === 'surely');
|
|
51
|
+
// Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
|
|
52
|
+
if (surelyIndex >= 0) {
|
|
53
|
+
return failure(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
|
|
54
|
+
}
|
|
55
|
+
return success(ctx, results);
|
|
56
|
+
}
|
|
57
|
+
ctx = res.ctx;
|
|
58
|
+
results.push(res.value);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
package/dist-esm/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "parser-combinators",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"license": "ISC",
|
|
5
|
-
"maintainers": [
|
|
6
|
-
"Micha_i"
|
|
7
|
-
],
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/michalusio/Parser.git"
|
|
11
|
-
},
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/michalusio/Parser/issues"
|
|
14
|
-
},
|
|
15
|
-
"homepage": "https://github.com/michalusio/Parser#readme",
|
|
16
|
-
"description": "A library of parser combinators, with which you can create your own parsers. The library will be continuously improved in time.",
|
|
17
|
-
"scripts": {
|
|
18
|
-
"start": "tsc && node .",
|
|
19
|
-
"lint": "eslint src --ext .ts",
|
|
20
|
-
"build": "tsc",
|
|
21
|
-
"build-esm": "tsc --project tsconfig.esm.json",
|
|
22
|
-
"bundle": "npm run lint && npm run build && npm run build-esm",
|
|
23
|
-
"test:mutate": "stryker run",
|
|
24
|
-
"test:unit": "mocha",
|
|
25
|
-
"test": "nyc -e '.ts' --r html -r lcov -r text npm run test:unit"
|
|
26
|
-
},
|
|
27
|
-
"author": "Micha_i <isalski.michal@gmail.com> (https://github.com/michalusio)",
|
|
28
|
-
"main": "./dist/index.js",
|
|
29
|
-
"types": "./dist/index.d.ts",
|
|
30
|
-
"type": "commonjs",
|
|
31
|
-
"engines": {
|
|
32
|
-
"node": ">=18"
|
|
33
|
-
},
|
|
34
|
-
"devDependencies": {
|
|
35
|
-
"@stryker-mutator/core": "^9.
|
|
36
|
-
"@stryker-mutator/mocha-runner": "^9.
|
|
37
|
-
"@stryker-mutator/typescript-checker": "^9.
|
|
38
|
-
"@types/mocha": "10.0.10",
|
|
39
|
-
"@types/node": "25.0
|
|
40
|
-
"cross-env": "10.1.0",
|
|
41
|
-
"esbuild": "0.27.2",
|
|
42
|
-
"eslint": "9.39.2",
|
|
43
|
-
"mocha": "11.7.5",
|
|
44
|
-
"nyc": "17.1.0",
|
|
45
|
-
"ts-node": "10.9.2",
|
|
46
|
-
"typescript": "5.9.3",
|
|
47
|
-
"typescript-eslint": "8.
|
|
48
|
-
},
|
|
49
|
-
"keywords": [
|
|
50
|
-
"parser",
|
|
51
|
-
"combinator",
|
|
52
|
-
"parser-combinator",
|
|
53
|
-
"parsing",
|
|
54
|
-
"combining",
|
|
55
|
-
"functional"
|
|
56
|
-
],
|
|
57
|
-
"prettier": {
|
|
58
|
-
"tabWidth": 4,
|
|
59
|
-
"useTabs": false
|
|
60
|
-
}
|
|
61
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "parser-combinators",
|
|
3
|
+
"version": "1.2.6",
|
|
4
|
+
"license": "ISC",
|
|
5
|
+
"maintainers": [
|
|
6
|
+
"Micha_i"
|
|
7
|
+
],
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/michalusio/Parser.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/michalusio/Parser/issues"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/michalusio/Parser#readme",
|
|
16
|
+
"description": "A library of parser combinators, with which you can create your own parsers. The library will be continuously improved in time.",
|
|
17
|
+
"scripts": {
|
|
18
|
+
"start": "tsc && node .",
|
|
19
|
+
"lint": "eslint src --ext .ts",
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"build-esm": "tsc --project tsconfig.esm.json",
|
|
22
|
+
"bundle": "npm run lint && npm run build && npm run build-esm",
|
|
23
|
+
"test:mutate": "stryker run",
|
|
24
|
+
"test:unit": "mocha",
|
|
25
|
+
"test": "nyc -e '.ts' --r html -r lcov -r text npm run test:unit"
|
|
26
|
+
},
|
|
27
|
+
"author": "Micha_i <isalski.michal@gmail.com> (https://github.com/michalusio)",
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"type": "commonjs",
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@stryker-mutator/core": "^9.5.0",
|
|
36
|
+
"@stryker-mutator/mocha-runner": "^9.5.0",
|
|
37
|
+
"@stryker-mutator/typescript-checker": "^9.5.0",
|
|
38
|
+
"@types/mocha": "10.0.10",
|
|
39
|
+
"@types/node": "25.1.0",
|
|
40
|
+
"cross-env": "10.1.0",
|
|
41
|
+
"esbuild": "0.27.2",
|
|
42
|
+
"eslint": "9.39.2",
|
|
43
|
+
"mocha": "11.7.5",
|
|
44
|
+
"nyc": "17.1.0",
|
|
45
|
+
"ts-node": "10.9.2",
|
|
46
|
+
"typescript": "5.9.3",
|
|
47
|
+
"typescript-eslint": "8.54.0"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"parser",
|
|
51
|
+
"combinator",
|
|
52
|
+
"parser-combinator",
|
|
53
|
+
"parsing",
|
|
54
|
+
"combining",
|
|
55
|
+
"functional"
|
|
56
|
+
],
|
|
57
|
+
"prettier": {
|
|
58
|
+
"tabWidth": 4,
|
|
59
|
+
"useTabs": false
|
|
60
|
+
}
|
|
61
|
+
}
|