@thi.ng/parse 2.4.9 → 2.4.11
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/CHANGELOG.md +1 -1
- package/README.md +1 -1
- package/api.js +0 -1
- package/combinators/alt.js +15 -21
- package/combinators/boundary.js +10 -4
- package/combinators/check.js +7 -4
- package/combinators/dynamic.js +8 -18
- package/combinators/expect.js +4 -1
- package/combinators/lookahead.js +17 -77
- package/combinators/maybe.js +4 -1
- package/combinators/not.js +10 -17
- package/combinators/repeat.js +26 -18
- package/combinators/seq.js +14 -10
- package/combinators/wrap.js +4 -1
- package/combinators/xform.js +16 -14
- package/context.js +134 -137
- package/error.js +6 -3
- package/grammar.js +241 -185
- package/package.json +12 -9
- package/presets/alpha.js +14 -17
- package/presets/bits.js +6 -2
- package/presets/digits.js +6 -8
- package/presets/escape.js +14 -11
- package/presets/hex.js +8 -13
- package/presets/numbers.js +12 -23
- package/presets/string.js +6 -1
- package/presets/whitespace.js +18 -32
- package/prims/always.js +6 -2
- package/prims/anchor.js +24 -21
- package/prims/fail.js +4 -1
- package/prims/lit.js +8 -19
- package/prims/none-of.js +10 -15
- package/prims/one-of.js +10 -14
- package/prims/pass.js +6 -12
- package/prims/range.js +18 -37
- package/prims/satisfy.js +17 -19
- package/prims/skip.js +13 -30
- package/prims/string.js +48 -43
- package/readers/array-reader.js +22 -20
- package/readers/string-reader.js +27 -26
- package/utils.js +4 -9
- package/xform/collect.js +9 -16
- package/xform/comp.js +19 -22
- package/xform/count.js +9 -16
- package/xform/discard.js +6 -10
- package/xform/hoist.js +15 -30
- package/xform/join.js +17 -24
- package/xform/json.js +8 -15
- package/xform/nest.js +21 -32
- package/xform/number.js +16 -36
- package/xform/print.js +21 -47
- package/xform/replace.js +9 -17
- package/xform/trim.js +8 -17
- package/xform/with-id.js +6 -8
package/presets/hex.js
CHANGED
|
@@ -3,16 +3,11 @@ import { oneOrMore, repeat } from "../combinators/repeat.js";
|
|
|
3
3
|
import { xform } from "../combinators/xform.js";
|
|
4
4
|
import { oneOf } from "../prims/one-of.js";
|
|
5
5
|
import { xfInt } from "../xform/number.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Matches 1-8 successive {@link HEX_DIGIT} and transforms with
|
|
16
|
-
* {@link xfInt} to JS number.
|
|
17
|
-
*/
|
|
18
|
-
export const HEX_UINT = xform(repeat(HEX_DIGIT, 1, 8, "uint"), xfInt(16));
|
|
6
|
+
const HEX_DIGIT = oneOf(HEX);
|
|
7
|
+
const HEX_DIGITS = oneOrMore(HEX_DIGIT);
|
|
8
|
+
const HEX_UINT = xform(repeat(HEX_DIGIT, 1, 8, "uint"), xfInt(16));
|
|
9
|
+
export {
|
|
10
|
+
HEX_DIGIT,
|
|
11
|
+
HEX_DIGITS,
|
|
12
|
+
HEX_UINT
|
|
13
|
+
};
|
package/presets/numbers.js
CHANGED
|
@@ -10,31 +10,20 @@ import { join } from "../xform/join.js";
|
|
|
10
10
|
import { xfFloat, xfInt } from "../xform/number.js";
|
|
11
11
|
import { xfID } from "../xform/with-id.js";
|
|
12
12
|
import { DIGIT, DIGITS } from "./digits.js";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export const SIGN = maybe(oneOf("-+"));
|
|
17
|
-
/**
|
|
18
|
-
* Matches optionally signed {@link DIGITS} and result transformed w/
|
|
19
|
-
* {@link xfInt} to JS number.
|
|
20
|
-
*/
|
|
21
|
-
export const INT = xform(seq([SIGN, DIGITS], "int"), xfInt());
|
|
22
|
-
/**
|
|
23
|
-
* Matches same as {@link DIGITS} but result transformed w/
|
|
24
|
-
* {@link xfInt} to JS number.
|
|
25
|
-
*/
|
|
26
|
-
export const UINT = xform(DIGITS, comp(xfID("uint"), xfInt()));
|
|
13
|
+
const SIGN = maybe(oneOf("-+"));
|
|
14
|
+
const INT = xform(seq([SIGN, DIGITS], "int"), xfInt());
|
|
15
|
+
const UINT = xform(DIGITS, comp(xfID("uint"), xfInt()));
|
|
27
16
|
const EXP = maybe(seq([maybe(oneOf("eE")), SIGN, DIGITS]));
|
|
28
17
|
const DOT = lit(".");
|
|
29
18
|
const FRACT0 = maybe(seq([DOT, zeroOrMore(DIGIT)]));
|
|
30
19
|
const FRACT1 = seq([DOT, DIGITS]);
|
|
31
20
|
const _REAL = seq([SIGN, alt([FRACT1, seq([DIGITS, FRACT0])]), EXP], "real");
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
21
|
+
const REAL = join(_REAL);
|
|
22
|
+
const FLOAT = xform(_REAL, xfFloat);
|
|
23
|
+
export {
|
|
24
|
+
FLOAT,
|
|
25
|
+
INT,
|
|
26
|
+
REAL,
|
|
27
|
+
SIGN,
|
|
28
|
+
UINT
|
|
29
|
+
};
|
package/presets/string.js
CHANGED
|
@@ -6,4 +6,9 @@ import { noneOf } from "../prims/none-of.js";
|
|
|
6
6
|
import { join } from "../xform/join.js";
|
|
7
7
|
import { ESC, UNICODE } from "./escape.js";
|
|
8
8
|
const quote = litD('"');
|
|
9
|
-
|
|
9
|
+
const STRING = join(
|
|
10
|
+
seq([quote, zeroOrMore(alt([UNICODE, ESC, noneOf('"')])), quote], "string")
|
|
11
|
+
);
|
|
12
|
+
export {
|
|
13
|
+
STRING
|
|
14
|
+
};
|
package/presets/whitespace.js
CHANGED
|
@@ -1,35 +1,21 @@
|
|
|
1
1
|
import { WS as _WS } from "@thi.ng/strings/groups";
|
|
2
2
|
import { oneOrMoreD, zeroOrMoreD } from "../combinators/repeat.js";
|
|
3
3
|
import { oneOf, oneOfD } from "../prims/one-of.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*/
|
|
23
|
-
export const WS0 = zeroOrMoreD(WS);
|
|
24
|
-
/**
|
|
25
|
-
* One or more {@link WS}. Result will be discarded.
|
|
26
|
-
*/
|
|
27
|
-
export const WS1 = oneOrMoreD(WS);
|
|
28
|
-
/**
|
|
29
|
-
* Zero or more {@link SPACE}. Result will be discarded.
|
|
30
|
-
*/
|
|
31
|
-
export const SPACES0 = zeroOrMoreD(SPACE);
|
|
32
|
-
/**
|
|
33
|
-
* One or more {@link SPACE}. Result will be discarded.
|
|
34
|
-
*/
|
|
35
|
-
export const SPACES = oneOrMoreD(SPACE);
|
|
4
|
+
const WS = oneOfD(_WS);
|
|
5
|
+
const SPACE = oneOfD(" ");
|
|
6
|
+
const NL = oneOf("\n\r");
|
|
7
|
+
const DNL = oneOfD("\n\r");
|
|
8
|
+
const WS0 = zeroOrMoreD(WS);
|
|
9
|
+
const WS1 = oneOrMoreD(WS);
|
|
10
|
+
const SPACES0 = zeroOrMoreD(SPACE);
|
|
11
|
+
const SPACES = oneOrMoreD(SPACE);
|
|
12
|
+
export {
|
|
13
|
+
DNL,
|
|
14
|
+
NL,
|
|
15
|
+
SPACE,
|
|
16
|
+
SPACES,
|
|
17
|
+
SPACES0,
|
|
18
|
+
WS,
|
|
19
|
+
WS0,
|
|
20
|
+
WS1
|
|
21
|
+
};
|
package/prims/always.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import { satisfy, satisfyD } from "./satisfy.js";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
const always = (id = "always") => satisfy(() => true, id);
|
|
3
|
+
const alwaysD = () => satisfyD(() => true);
|
|
4
|
+
export {
|
|
5
|
+
always,
|
|
6
|
+
alwaysD
|
|
7
|
+
};
|
package/prims/anchor.js
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import { ALPHA_NUM } from "@thi.ng/strings/groups";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
const anchor = (fn) => (ctx) => {
|
|
3
|
+
const state = ctx.state;
|
|
4
|
+
return fn(state.last, state.done ? null : ctx.reader.read(state));
|
|
5
5
|
};
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
const inputStart = (ctx) => ctx.state.last == null;
|
|
7
|
+
const inputEnd = (ctx) => ctx.state.done || ctx.reader.read(ctx.state) === void 0;
|
|
8
|
+
const lineStart = (ctx) => {
|
|
9
|
+
const l = ctx.state.last;
|
|
10
|
+
return l == null || l === "\n" || l === "\r";
|
|
11
11
|
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
const lineEnd = (ctx) => {
|
|
13
|
+
const state = ctx.state;
|
|
14
|
+
let c;
|
|
15
|
+
return state.done || (c = ctx.reader.read(state)) === "\n" || c === "\r";
|
|
16
16
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
const wordBoundaryP = (prev, next) => {
|
|
18
|
+
return prev ? next ? ALPHA_NUM[prev] && !ALPHA_NUM[next] : ALPHA_NUM[prev] : next ? ALPHA_NUM[next] : false;
|
|
19
|
+
};
|
|
20
|
+
const wordBoundary = anchor(wordBoundaryP);
|
|
21
|
+
export {
|
|
22
|
+
anchor,
|
|
23
|
+
inputEnd,
|
|
24
|
+
inputStart,
|
|
25
|
+
lineEnd,
|
|
26
|
+
lineStart,
|
|
27
|
+
wordBoundary,
|
|
28
|
+
wordBoundaryP
|
|
25
29
|
};
|
|
26
|
-
export const wordBoundary = anchor(wordBoundaryP);
|
package/prims/fail.js
CHANGED
package/prims/lit.js
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
import { satisfyD, satisfy } from "./satisfy.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*
|
|
11
|
-
* @param c -
|
|
12
|
-
* @param id -
|
|
13
|
-
*/
|
|
14
|
-
export const lit = (c, id = "lit") => satisfy(litP(c), id);
|
|
15
|
-
/**
|
|
16
|
-
* Discarded literal. Same as {@link lit}, but result will be discarded.
|
|
17
|
-
*
|
|
18
|
-
* @param c -
|
|
19
|
-
*/
|
|
20
|
-
export const litD = (c) => satisfyD(litP(c));
|
|
2
|
+
const litP = (c) => (x) => x === c;
|
|
3
|
+
const lit = (c, id = "lit") => satisfy(litP(c), id);
|
|
4
|
+
const litD = (c) => satisfyD(litP(c));
|
|
5
|
+
export {
|
|
6
|
+
lit,
|
|
7
|
+
litD,
|
|
8
|
+
litP
|
|
9
|
+
};
|
package/prims/none-of.js
CHANGED
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import { isPlainObject } from "@thi.ng/checks/is-plain-object";
|
|
2
2
|
import { isSet } from "@thi.ng/checks/is-set";
|
|
3
3
|
import { satisfy, satisfyD } from "./satisfy.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* @param opts -
|
|
9
|
-
*/
|
|
10
|
-
export const noneOfP = (opts) => isSet(opts)
|
|
11
|
-
? (x) => !opts.has(x)
|
|
12
|
-
: isPlainObject(opts)
|
|
13
|
-
? (x) => !opts[x]
|
|
14
|
-
: (x) => opts.indexOf(x) < 0;
|
|
15
|
-
export function noneOf(opts, id = "noneOf") {
|
|
16
|
-
return satisfy(noneOfP(opts), id);
|
|
4
|
+
const noneOfP = (opts) => isSet(opts) ? (x) => !opts.has(x) : isPlainObject(opts) ? (x) => !opts[x] : (x) => opts.indexOf(x) < 0;
|
|
5
|
+
function noneOf(opts, id = "noneOf") {
|
|
6
|
+
return satisfy(noneOfP(opts), id);
|
|
17
7
|
}
|
|
18
|
-
|
|
19
|
-
|
|
8
|
+
function noneOfD(opts) {
|
|
9
|
+
return satisfyD(noneOfP(opts));
|
|
20
10
|
}
|
|
11
|
+
export {
|
|
12
|
+
noneOf,
|
|
13
|
+
noneOfD,
|
|
14
|
+
noneOfP
|
|
15
|
+
};
|
package/prims/one-of.js
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import { isPlainObject } from "@thi.ng/checks/is-plain-object";
|
|
2
2
|
import { isSet } from "@thi.ng/checks/is-set";
|
|
3
3
|
import { satisfy, satisfyD } from "./satisfy.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* @param opts -
|
|
8
|
-
*/
|
|
9
|
-
export const oneOfP = (opts) => isSet(opts)
|
|
10
|
-
? (x) => opts.has(x)
|
|
11
|
-
: isPlainObject(opts)
|
|
12
|
-
? (x) => opts[x]
|
|
13
|
-
: (x) => opts.indexOf(x) >= 0;
|
|
14
|
-
export function oneOf(opts, id = "oneOf") {
|
|
15
|
-
return satisfy(oneOfP(opts), id);
|
|
4
|
+
const oneOfP = (opts) => isSet(opts) ? (x) => opts.has(x) : isPlainObject(opts) ? (x) => opts[x] : (x) => opts.indexOf(x) >= 0;
|
|
5
|
+
function oneOf(opts, id = "oneOf") {
|
|
6
|
+
return satisfy(oneOfP(opts), id);
|
|
16
7
|
}
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
function oneOfD(opts) {
|
|
9
|
+
return satisfyD(oneOfP(opts));
|
|
19
10
|
}
|
|
11
|
+
export {
|
|
12
|
+
oneOf,
|
|
13
|
+
oneOfD,
|
|
14
|
+
oneOfP
|
|
15
|
+
};
|
package/prims/pass.js
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import { isFunction } from "@thi.ng/checks/is-function";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
*/
|
|
9
|
-
export const pass = (result, id = "pass") => (ctx) => ctx.addChild(id, isFunction(result) ? result() : result);
|
|
10
|
-
/**
|
|
11
|
-
* Parser which consumes no input and always succeeds. No AST creation.
|
|
12
|
-
*/
|
|
13
|
-
export const passD = () => true;
|
|
2
|
+
const pass = (result, id = "pass") => (ctx) => ctx.addChild(id, isFunction(result) ? result() : result);
|
|
3
|
+
const passD = () => true;
|
|
4
|
+
export {
|
|
5
|
+
pass,
|
|
6
|
+
passD
|
|
7
|
+
};
|
package/prims/range.js
CHANGED
|
@@ -1,41 +1,22 @@
|
|
|
1
1
|
import { satisfy, satisfyD } from "./satisfy.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* @param max -
|
|
7
|
-
*/
|
|
8
|
-
export const rangeP = (min, max) => (x) => x >= min && x <= max;
|
|
9
|
-
/**
|
|
10
|
-
* HOF predicate for matching single char within given UTF16 codepoint
|
|
11
|
-
* range.
|
|
12
|
-
*
|
|
13
|
-
* @param min -
|
|
14
|
-
* @param max -
|
|
15
|
-
*/
|
|
16
|
-
export const utf16RangeP = (min, max) => (x) => {
|
|
17
|
-
const c = x.charCodeAt(0);
|
|
18
|
-
return c >= min && c <= max;
|
|
2
|
+
const rangeP = (min, max) => (x) => x >= min && x <= max;
|
|
3
|
+
const utf16RangeP = (min, max) => (x) => {
|
|
4
|
+
const c = x.charCodeAt(0);
|
|
5
|
+
return c >= min && c <= max;
|
|
19
6
|
};
|
|
20
|
-
|
|
21
|
-
|
|
7
|
+
function range(min, max, id = "lit") {
|
|
8
|
+
return satisfy(rangeP(min, max), id);
|
|
22
9
|
}
|
|
23
|
-
|
|
24
|
-
|
|
10
|
+
function rangeD(min, max) {
|
|
11
|
+
return satisfyD(rangeP(min, max));
|
|
25
12
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
*
|
|
37
|
-
* @param min -
|
|
38
|
-
* @param max -
|
|
39
|
-
* @param id -
|
|
40
|
-
*/
|
|
41
|
-
export const utf16RangeD = (min, max) => satisfyD(utf16RangeP(min, max));
|
|
13
|
+
const utf16Range = (min, max, id = "utfLit") => satisfy(utf16RangeP(min, max), id);
|
|
14
|
+
const utf16RangeD = (min, max) => satisfyD(utf16RangeP(min, max));
|
|
15
|
+
export {
|
|
16
|
+
range,
|
|
17
|
+
rangeD,
|
|
18
|
+
rangeP,
|
|
19
|
+
utf16Range,
|
|
20
|
+
utf16RangeD,
|
|
21
|
+
utf16RangeP
|
|
22
|
+
};
|
package/prims/satisfy.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return pred(reader.read(state)) ? (reader.next(state), true) : false;
|
|
19
|
-
});
|
|
1
|
+
const satisfy = (pred, id = "satisfy") => (ctx) => {
|
|
2
|
+
if (ctx.done)
|
|
3
|
+
return false;
|
|
4
|
+
const r = ctx.reader.read(ctx.state);
|
|
5
|
+
return pred(r) ? ctx.addChild(id, r, true) : false;
|
|
6
|
+
};
|
|
7
|
+
const satisfyD = (pred) => (ctx) => {
|
|
8
|
+
if (ctx.done)
|
|
9
|
+
return false;
|
|
10
|
+
const state = ctx.state;
|
|
11
|
+
const reader = ctx.reader;
|
|
12
|
+
return pred(reader.read(state)) ? (reader.next(state), true) : false;
|
|
13
|
+
};
|
|
14
|
+
export {
|
|
15
|
+
satisfy,
|
|
16
|
+
satisfyD
|
|
17
|
+
};
|
package/prims/skip.js
CHANGED
|
@@ -1,31 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*
|
|
15
|
-
* ctx.state
|
|
16
|
-
* // { p: 15, l: 2, c: 1, done: true, last: '\n' }
|
|
17
|
-
* ```
|
|
18
|
-
*
|
|
19
|
-
* @param pred -
|
|
20
|
-
*/
|
|
21
|
-
export const skipWhile = (pred) => (ctx) => {
|
|
22
|
-
const state = { ...ctx.state };
|
|
23
|
-
const reader = ctx.reader;
|
|
24
|
-
while (!state.done) {
|
|
25
|
-
if (!pred(reader.read(state)))
|
|
26
|
-
break;
|
|
27
|
-
reader.next(state);
|
|
28
|
-
}
|
|
29
|
-
ctx.state = state;
|
|
30
|
-
return true;
|
|
1
|
+
const skipWhile = (pred) => (ctx) => {
|
|
2
|
+
const state = { ...ctx.state };
|
|
3
|
+
const reader = ctx.reader;
|
|
4
|
+
while (!state.done) {
|
|
5
|
+
if (!pred(reader.read(state)))
|
|
6
|
+
break;
|
|
7
|
+
reader.next(state);
|
|
8
|
+
}
|
|
9
|
+
ctx.state = state;
|
|
10
|
+
return true;
|
|
11
|
+
};
|
|
12
|
+
export {
|
|
13
|
+
skipWhile
|
|
31
14
|
};
|
package/prims/string.js
CHANGED
|
@@ -1,48 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
reader.next(state);
|
|
1
|
+
const string = (str, id = "string") => (ctx) => {
|
|
2
|
+
if (ctx.done)
|
|
3
|
+
return false;
|
|
4
|
+
const scope = ctx.start(id);
|
|
5
|
+
const state = scope.state;
|
|
6
|
+
const reader = ctx.reader;
|
|
7
|
+
for (let i = 0, n = str.length; i < n; i++) {
|
|
8
|
+
if (state.done)
|
|
9
|
+
return false;
|
|
10
|
+
const r = reader.read(state);
|
|
11
|
+
if (r !== str[i]) {
|
|
12
|
+
return ctx.discard();
|
|
15
13
|
}
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
reader.next(state);
|
|
15
|
+
}
|
|
16
|
+
scope.result = str;
|
|
17
|
+
return ctx.end();
|
|
18
18
|
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
reader.next(state);
|
|
19
|
+
const stringD = (str) => (ctx) => {
|
|
20
|
+
if (ctx.done)
|
|
21
|
+
return false;
|
|
22
|
+
const state = { ...ctx.state };
|
|
23
|
+
const reader = ctx.reader;
|
|
24
|
+
for (let i = 0, n = str.length; i < n; i++) {
|
|
25
|
+
if (state.done)
|
|
26
|
+
return false;
|
|
27
|
+
const r = reader.read(state);
|
|
28
|
+
if (r !== str[i]) {
|
|
29
|
+
return false;
|
|
32
30
|
}
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
reader.next(state);
|
|
32
|
+
}
|
|
33
|
+
ctx.state = state;
|
|
34
|
+
return true;
|
|
35
35
|
};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
36
|
+
const stringOf = (pred, id = "string", reduce = (x) => x.join("")) => (ctx) => {
|
|
37
|
+
const state = { ...ctx.state };
|
|
38
|
+
const reader = ctx.reader;
|
|
39
|
+
let acc = [];
|
|
40
|
+
while (!state.done) {
|
|
41
|
+
const r = reader.read(state);
|
|
42
|
+
if (!pred(r))
|
|
43
|
+
break;
|
|
44
|
+
acc.push(r);
|
|
45
|
+
reader.next(state);
|
|
46
|
+
}
|
|
47
|
+
return ctx.addChild(id, reduce(acc), state);
|
|
48
|
+
};
|
|
49
|
+
export {
|
|
50
|
+
string,
|
|
51
|
+
stringD,
|
|
52
|
+
stringOf
|
|
48
53
|
};
|
package/readers/array-reader.js
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
class ArrayReader {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
2
|
+
constructor(_src) {
|
|
3
|
+
this._src = _src;
|
|
4
|
+
}
|
|
5
|
+
read(state) {
|
|
6
|
+
return this._src[state.p];
|
|
7
|
+
}
|
|
8
|
+
next(state) {
|
|
9
|
+
if (state.done)
|
|
10
|
+
return;
|
|
11
|
+
state.last = this._src[state.p];
|
|
12
|
+
state.done = ++state.p >= this._src.length;
|
|
13
|
+
}
|
|
14
|
+
isDone(state) {
|
|
15
|
+
return state.done = state.p >= this._src.length;
|
|
16
|
+
}
|
|
17
|
+
format(state) {
|
|
18
|
+
return `offset ${state.p}`;
|
|
19
|
+
}
|
|
21
20
|
}
|
|
22
|
-
|
|
21
|
+
const defArrayReader = (input) => new ArrayReader(input);
|
|
22
|
+
export {
|
|
23
|
+
defArrayReader
|
|
24
|
+
};
|