@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/CHANGELOG.md
CHANGED
package/README.md
CHANGED
package/api.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/combinators/alt.js
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
import { string } from "../prims/string.js";
|
|
2
2
|
import { discard } from "../xform/discard.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
return false;
|
|
6
|
-
for (let i = 0, n = parsers.length; i < n; i++) {
|
|
7
|
-
if (parsers[i](ctx)) {
|
|
8
|
-
return true;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
3
|
+
const alt = (parsers) => (ctx) => {
|
|
4
|
+
if (ctx.done)
|
|
11
5
|
return false;
|
|
6
|
+
for (let i = 0, n = parsers.length; i < n; i++) {
|
|
7
|
+
if (parsers[i](ctx)) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return false;
|
|
12
|
+
};
|
|
13
|
+
const altS = (strings) => alt(strings.map((x) => string(x)));
|
|
14
|
+
const altD = (parsers) => discard(alt(parsers));
|
|
15
|
+
export {
|
|
16
|
+
alt,
|
|
17
|
+
altD,
|
|
18
|
+
altS
|
|
12
19
|
};
|
|
13
|
-
/**
|
|
14
|
-
* Syntax sugar for {@link alt}. Takes an array of strings to match and creates
|
|
15
|
-
* parsers for each before passing them to `alt()`.
|
|
16
|
-
*
|
|
17
|
-
* @param strings
|
|
18
|
-
*/
|
|
19
|
-
export const altS = (strings) => alt(strings.map((x) => string(x)));
|
|
20
|
-
/**
|
|
21
|
-
* Wrapped version of {@link alt} which discards results if successful match.
|
|
22
|
-
*
|
|
23
|
-
* @param parsers
|
|
24
|
-
*/
|
|
25
|
-
export const altD = (parsers) => discard(alt(parsers));
|
package/combinators/boundary.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { inputEnd, inputStart, lineEnd, lineStart } from "../prims/anchor.js";
|
|
2
2
|
import { seq } from "./seq.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
const startsWith = (parser) => seq([inputStart, parser]);
|
|
4
|
+
const endsWith = (parser) => seq([parser, inputEnd]);
|
|
5
|
+
const entireLine = (parser) => seq([lineStart, parser, lineEnd]);
|
|
6
|
+
const entirely = (parser) => seq([inputStart, parser, inputEnd]);
|
|
7
|
+
export {
|
|
8
|
+
endsWith,
|
|
9
|
+
entireLine,
|
|
10
|
+
entirely,
|
|
11
|
+
startsWith
|
|
12
|
+
};
|
package/combinators/check.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { parseError } from "../error.js";
|
|
2
2
|
import { xform } from "./xform.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
const check = (parser, pred, msg = "check failed") => xform(parser, (scope, ctx) => {
|
|
4
|
+
if (!pred(scope))
|
|
5
|
+
parseError(ctx, msg);
|
|
6
|
+
return scope;
|
|
7
7
|
});
|
|
8
|
+
export {
|
|
9
|
+
check
|
|
10
|
+
};
|
package/combinators/dynamic.js
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*
|
|
10
|
-
* parser(defContext("a"));
|
|
11
|
-
* // true
|
|
12
|
-
* ```
|
|
13
|
-
*/
|
|
14
|
-
export const dynamic = () => {
|
|
15
|
-
let impl;
|
|
16
|
-
const wrapper = (ctx) => (impl ? impl(ctx) : false);
|
|
17
|
-
wrapper.set = (p) => (impl = p);
|
|
18
|
-
return wrapper;
|
|
1
|
+
const dynamic = () => {
|
|
2
|
+
let impl;
|
|
3
|
+
const wrapper = (ctx) => impl ? impl(ctx) : false;
|
|
4
|
+
wrapper.set = (p) => impl = p;
|
|
5
|
+
return wrapper;
|
|
6
|
+
};
|
|
7
|
+
export {
|
|
8
|
+
dynamic
|
|
19
9
|
};
|
package/combinators/expect.js
CHANGED
package/combinators/lookahead.js
CHANGED
|
@@ -1,79 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*
|
|
12
|
-
* Currently, iff `capture` is disabled, the `ahead` parser MUST discard
|
|
13
|
-
* its own result (e.g. via {@link discard}). On successful match the
|
|
14
|
-
* final read position will then be restored to the beginning of `ahead`
|
|
15
|
-
* pattern.
|
|
16
|
-
*
|
|
17
|
-
* Iff `capture` is enabled, the `ahead` parser MAY discard its own
|
|
18
|
-
* result, but the final read position will not be re-adjusted as in the
|
|
19
|
-
* non-capturing version.
|
|
20
|
-
*
|
|
21
|
-
* **Important:** Since the main term will be repeated automatically, DO
|
|
22
|
-
* NOT use repetition modifiers `?` or `*`, since both of these will
|
|
23
|
-
* cause the parser to go into an infinite loop. This is expected
|
|
24
|
-
* behavior and not a bug.
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```ts
|
|
28
|
-
* const ctx = defContext("ababaaabbabba");
|
|
29
|
-
*
|
|
30
|
-
* // consume while 'a' or `b` and until 1st occurrence of "abba"...
|
|
31
|
-
* // note the use of `stringD()` to discard lookahead result
|
|
32
|
-
*
|
|
33
|
-
* // non-capturing lookahead
|
|
34
|
-
* join(lookahead(oneOf("ab"), stringD("abba")))(ctx)
|
|
35
|
-
* // true
|
|
36
|
-
*
|
|
37
|
-
* ctx.result
|
|
38
|
-
* // "ababaa"
|
|
39
|
-
*
|
|
40
|
-
* ctx.state
|
|
41
|
-
* // { p: 6, l: 1, c: 7, done: false, last: 'a' }
|
|
42
|
-
* ```
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* ```ts
|
|
46
|
-
* const ctx = defContext("ababaaabbabba");
|
|
47
|
-
*
|
|
48
|
-
* // capturing lookahead
|
|
49
|
-
* join(lookahead(oneOf("ab"), string("abba"), true))(ctx)
|
|
50
|
-
* // true
|
|
51
|
-
*
|
|
52
|
-
* ctx.result
|
|
53
|
-
* // "ababaaabba"
|
|
54
|
-
*
|
|
55
|
-
* ctx.state
|
|
56
|
-
* // { p: 10, l: 1, c: 11, done: false, last: 'a' }
|
|
57
|
-
* ```
|
|
58
|
-
*
|
|
59
|
-
* @param parser -
|
|
60
|
-
* @param ahead -
|
|
61
|
-
* @param capture -
|
|
62
|
-
* @param id -
|
|
63
|
-
*/
|
|
64
|
-
export const lookahead = (parser, ahead, capture = false, id = "lookahead") => (ctx) => {
|
|
65
|
-
if (ctx.done)
|
|
66
|
-
return false;
|
|
67
|
-
ctx.start(id);
|
|
68
|
-
let pass = false;
|
|
69
|
-
while (true) {
|
|
70
|
-
const state = capture ? null : { ...ctx.state };
|
|
71
|
-
if (ahead(ctx)) {
|
|
72
|
-
!capture && (ctx.state = state);
|
|
73
|
-
return pass ? ctx.end() : ctx.discard();
|
|
74
|
-
}
|
|
75
|
-
if (!parser(ctx))
|
|
76
|
-
return ctx.discard();
|
|
77
|
-
pass = true;
|
|
1
|
+
const lookahead = (parser, ahead, capture = false, id = "lookahead") => (ctx) => {
|
|
2
|
+
if (ctx.done)
|
|
3
|
+
return false;
|
|
4
|
+
ctx.start(id);
|
|
5
|
+
let pass = false;
|
|
6
|
+
while (true) {
|
|
7
|
+
const state = capture ? null : { ...ctx.state };
|
|
8
|
+
if (ahead(ctx)) {
|
|
9
|
+
!capture && (ctx.state = state);
|
|
10
|
+
return pass ? ctx.end() : ctx.discard();
|
|
78
11
|
}
|
|
12
|
+
if (!parser(ctx))
|
|
13
|
+
return ctx.discard();
|
|
14
|
+
pass = true;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
export {
|
|
18
|
+
lookahead
|
|
79
19
|
};
|
package/combinators/maybe.js
CHANGED
package/combinators/not.js
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import { always } from "../prims/always.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export const not = (parser, fail = always()) => (ctx) => {
|
|
13
|
-
if (ctx.done)
|
|
14
|
-
return false;
|
|
15
|
-
ctx.start("");
|
|
16
|
-
const res = parser(ctx);
|
|
17
|
-
ctx.discard();
|
|
18
|
-
return res ? false : fail(ctx);
|
|
2
|
+
const not = (parser, fail = always()) => (ctx) => {
|
|
3
|
+
if (ctx.done)
|
|
4
|
+
return false;
|
|
5
|
+
ctx.start("");
|
|
6
|
+
const res = parser(ctx);
|
|
7
|
+
ctx.discard();
|
|
8
|
+
return res ? false : fail(ctx);
|
|
9
|
+
};
|
|
10
|
+
export {
|
|
11
|
+
not
|
|
19
12
|
};
|
package/combinators/repeat.js
CHANGED
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
import { discard } from "../xform/discard.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
const repeat = (parser, min, max, id = "repeat") => (ctx) => {
|
|
3
|
+
if (ctx.done) {
|
|
4
|
+
return min < 1 ? ctx.addChild(id) : false;
|
|
5
|
+
}
|
|
6
|
+
ctx.start(id);
|
|
7
|
+
for (let i = 0; i < max; i++) {
|
|
8
|
+
if (!parser(ctx)) {
|
|
9
|
+
if (i < min) {
|
|
10
|
+
return ctx.discard();
|
|
11
|
+
}
|
|
12
|
+
break;
|
|
5
13
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
}
|
|
15
|
+
return ctx.end();
|
|
16
|
+
};
|
|
17
|
+
const zeroOrMore = (parser, id = "repeat0", max = Infinity) => repeat(parser, 0, max, id);
|
|
18
|
+
const oneOrMore = (parser, id = "repeat1", max = Infinity) => repeat(parser, 1, max, id);
|
|
19
|
+
const repeatD = (parser, min, max) => discard(repeat(parser, min, max));
|
|
20
|
+
const zeroOrMoreD = (parser, max = Infinity) => repeatD(parser, 0, max);
|
|
21
|
+
const oneOrMoreD = (parser, max = Infinity) => repeatD(parser, 1, max);
|
|
22
|
+
export {
|
|
23
|
+
oneOrMore,
|
|
24
|
+
oneOrMoreD,
|
|
25
|
+
repeat,
|
|
26
|
+
repeatD,
|
|
27
|
+
zeroOrMore,
|
|
28
|
+
zeroOrMoreD
|
|
16
29
|
};
|
|
17
|
-
export const zeroOrMore = (parser, id = "repeat0", max = Infinity) => repeat(parser, 0, max, id);
|
|
18
|
-
export const oneOrMore = (parser, id = "repeat1", max = Infinity) => repeat(parser, 1, max, id);
|
|
19
|
-
export const repeatD = (parser, min, max) => discard(repeat(parser, min, max));
|
|
20
|
-
export const zeroOrMoreD = (parser, max = Infinity) => repeatD(parser, 0, max);
|
|
21
|
-
export const oneOrMoreD = (parser, max = Infinity) => repeatD(parser, 1, max);
|
package/combinators/seq.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { discard } from "../xform/discard.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
2
|
+
const seq = (parsers, id = "seq") => (ctx) => {
|
|
3
|
+
if (ctx.done)
|
|
4
|
+
return false;
|
|
5
|
+
ctx.start(id);
|
|
6
|
+
for (let i = 0, n = parsers.length; i < n; i++) {
|
|
7
|
+
if (!parsers[i](ctx)) {
|
|
8
|
+
return ctx.discard();
|
|
10
9
|
}
|
|
11
|
-
|
|
10
|
+
}
|
|
11
|
+
return ctx.end();
|
|
12
|
+
};
|
|
13
|
+
const seqD = (parsers) => discard(seq(parsers));
|
|
14
|
+
export {
|
|
15
|
+
seq,
|
|
16
|
+
seqD
|
|
12
17
|
};
|
|
13
|
-
export const seqD = (parsers) => discard(seq(parsers));
|
package/combinators/wrap.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { litD } from "../prims/lit.js";
|
|
2
2
|
import { hoist } from "../xform/hoist.js";
|
|
3
3
|
import { seq } from "./seq.js";
|
|
4
|
-
|
|
4
|
+
const wrap = (parser, pre, post = pre) => hoist(seq([litD(pre), parser, litD(post)]));
|
|
5
|
+
export {
|
|
6
|
+
wrap
|
|
7
|
+
};
|
package/combinators/xform.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
children.pop();
|
|
12
|
-
}
|
|
13
|
-
return true;
|
|
1
|
+
const xform = (parser, xf, user) => (ctx) => {
|
|
2
|
+
if (parser(ctx)) {
|
|
3
|
+
const children = ctx.scope.children;
|
|
4
|
+
const scope = children[children.length - 1];
|
|
5
|
+
if (xf(scope, ctx, user)) {
|
|
6
|
+
if (scope.children && !scope.children.length) {
|
|
7
|
+
scope.children = null;
|
|
8
|
+
}
|
|
9
|
+
} else {
|
|
10
|
+
children.pop();
|
|
14
11
|
}
|
|
15
|
-
return
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
};
|
|
16
|
+
export {
|
|
17
|
+
xform
|
|
16
18
|
};
|
package/context.js
CHANGED
|
@@ -4,144 +4,141 @@ import { parseError } from "./error.js";
|
|
|
4
4
|
import { defArrayReader } from "./readers/array-reader.js";
|
|
5
5
|
import { defStringReader } from "./readers/string-reader.js";
|
|
6
6
|
import { indent } from "./utils.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
7
|
+
class ParseContext {
|
|
8
|
+
constructor(reader, opts) {
|
|
9
|
+
this.reader = reader;
|
|
10
|
+
this.opts = { maxDepth: 64, debug: false, retain: false, ...opts };
|
|
11
|
+
this._maxDepth = this.opts.maxDepth;
|
|
12
|
+
this._debug = this.opts.debug;
|
|
13
|
+
this._retain = this.opts.retain;
|
|
14
|
+
this.reset();
|
|
15
|
+
}
|
|
16
|
+
opts;
|
|
17
|
+
_scopes;
|
|
18
|
+
_curr;
|
|
19
|
+
_maxDepth;
|
|
20
|
+
_peakDepth;
|
|
21
|
+
_debug;
|
|
22
|
+
_retain;
|
|
23
|
+
reset() {
|
|
24
|
+
this._curr = {
|
|
25
|
+
id: "root",
|
|
26
|
+
state: { p: 0, l: 1, c: 1 },
|
|
27
|
+
children: null,
|
|
28
|
+
result: null
|
|
29
|
+
};
|
|
30
|
+
this._scopes = [this._curr];
|
|
31
|
+
this._peakDepth = 1;
|
|
32
|
+
this.reader.isDone(this._curr.state);
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
start(id) {
|
|
36
|
+
if (this._scopes.length >= this._maxDepth) {
|
|
37
|
+
parseError(this, `recursion limit reached ${this._maxDepth}`);
|
|
23
38
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
addChild(id, result = null, newState = false) {
|
|
80
|
-
const curr = this._curr;
|
|
81
|
-
const cstate = curr.state;
|
|
82
|
-
const child = {
|
|
83
|
-
id,
|
|
84
|
-
state: this._retain
|
|
85
|
-
? { p: cstate.p, l: cstate.l, c: cstate.c }
|
|
86
|
-
: null,
|
|
87
|
-
children: null,
|
|
88
|
-
result,
|
|
89
|
-
};
|
|
90
|
-
this._debug &&
|
|
91
|
-
console.log(`${indent(this._scopes.length + 1)}addChild: ${id} (${cstate.p})`);
|
|
92
|
-
const children = curr.children;
|
|
93
|
-
children ? children.push(child) : (curr.children = [child]);
|
|
94
|
-
if (newState !== false) {
|
|
95
|
-
newState === true
|
|
96
|
-
? this.reader.next(cstate)
|
|
97
|
-
: (this._curr.state = newState);
|
|
98
|
-
}
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
101
|
-
get scope() {
|
|
102
|
-
return this._curr;
|
|
103
|
-
}
|
|
104
|
-
get state() {
|
|
105
|
-
return this._curr.state;
|
|
106
|
-
}
|
|
107
|
-
set state(state) {
|
|
108
|
-
this._curr.state = state;
|
|
109
|
-
}
|
|
110
|
-
get done() {
|
|
111
|
-
return this._curr.state.done;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Returns root node.
|
|
115
|
-
*/
|
|
116
|
-
get root() {
|
|
117
|
-
return this._scopes[0];
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Returns root node's `result` or `undefined`.
|
|
121
|
-
*/
|
|
122
|
-
get result() {
|
|
123
|
-
const children = this.root.children;
|
|
124
|
-
return children ? children[0].result : undefined;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Returns root node's children or `undefined`.
|
|
128
|
-
*/
|
|
129
|
-
get children() {
|
|
130
|
-
const children = this.root.children;
|
|
131
|
-
return children ? children[0].children : undefined;
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Returns max. recursion depth which was actually reached. Will always be
|
|
135
|
-
* less or equal configured {@link ContextOpts.maxDepth}.
|
|
136
|
-
*/
|
|
137
|
-
get peakDepth() {
|
|
138
|
-
return this._peakDepth;
|
|
39
|
+
const scopes = this._scopes;
|
|
40
|
+
const scope = {
|
|
41
|
+
id,
|
|
42
|
+
state: { ...scopes[scopes.length - 1].state },
|
|
43
|
+
children: null,
|
|
44
|
+
result: null
|
|
45
|
+
};
|
|
46
|
+
scopes.push(scope);
|
|
47
|
+
this._peakDepth = Math.max(this._peakDepth, scopes.length);
|
|
48
|
+
this._debug && console.log(
|
|
49
|
+
`${indent(scopes.length)}start: ${id} (${scope.state.p})`
|
|
50
|
+
);
|
|
51
|
+
return this._curr = scope;
|
|
52
|
+
}
|
|
53
|
+
discard() {
|
|
54
|
+
const scopes = this._scopes;
|
|
55
|
+
const child = scopes.pop();
|
|
56
|
+
this._curr = scopes[scopes.length - 1];
|
|
57
|
+
this._debug && console.log(`${indent(scopes.length + 1)}discard: ${child.id}`);
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
end() {
|
|
61
|
+
const scopes = this._scopes;
|
|
62
|
+
const child = scopes.pop();
|
|
63
|
+
const parent = scopes[scopes.length - 1];
|
|
64
|
+
const cstate = child.state;
|
|
65
|
+
let pstate;
|
|
66
|
+
this._debug && console.log(
|
|
67
|
+
`${indent(scopes.length + 1)}end: ${child.id} (${cstate.p})`
|
|
68
|
+
);
|
|
69
|
+
child.state = this._retain ? (pstate = parent.state, { p: pstate.p, l: pstate.l, c: pstate.c }) : null;
|
|
70
|
+
parent.state = cstate;
|
|
71
|
+
const children = parent.children;
|
|
72
|
+
children ? children.push(child) : parent.children = [child];
|
|
73
|
+
this._curr = parent;
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
addChild(id, result = null, newState = false) {
|
|
77
|
+
const curr = this._curr;
|
|
78
|
+
const cstate = curr.state;
|
|
79
|
+
const child = {
|
|
80
|
+
id,
|
|
81
|
+
state: this._retain ? { p: cstate.p, l: cstate.l, c: cstate.c } : null,
|
|
82
|
+
children: null,
|
|
83
|
+
result
|
|
84
|
+
};
|
|
85
|
+
this._debug && console.log(
|
|
86
|
+
`${indent(this._scopes.length + 1)}addChild: ${id} (${cstate.p})`
|
|
87
|
+
);
|
|
88
|
+
const children = curr.children;
|
|
89
|
+
children ? children.push(child) : curr.children = [child];
|
|
90
|
+
if (newState !== false) {
|
|
91
|
+
newState === true ? this.reader.next(cstate) : this._curr.state = newState;
|
|
139
92
|
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
get scope() {
|
|
96
|
+
return this._curr;
|
|
97
|
+
}
|
|
98
|
+
get state() {
|
|
99
|
+
return this._curr.state;
|
|
100
|
+
}
|
|
101
|
+
set state(state) {
|
|
102
|
+
this._curr.state = state;
|
|
103
|
+
}
|
|
104
|
+
get done() {
|
|
105
|
+
return this._curr.state.done;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Returns root node.
|
|
109
|
+
*/
|
|
110
|
+
get root() {
|
|
111
|
+
return this._scopes[0];
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Returns root node's `result` or `undefined`.
|
|
115
|
+
*/
|
|
116
|
+
get result() {
|
|
117
|
+
const children = this.root.children;
|
|
118
|
+
return children ? children[0].result : void 0;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Returns root node's children or `undefined`.
|
|
122
|
+
*/
|
|
123
|
+
get children() {
|
|
124
|
+
const children = this.root.children;
|
|
125
|
+
return children ? children[0].children : void 0;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Returns max. recursion depth which was actually reached. Will always be
|
|
129
|
+
* less or equal configured {@link ContextOpts.maxDepth}.
|
|
130
|
+
*/
|
|
131
|
+
get peakDepth() {
|
|
132
|
+
return this._peakDepth;
|
|
133
|
+
}
|
|
140
134
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
: input, opts);
|
|
135
|
+
function defContext(input, opts) {
|
|
136
|
+
return new ParseContext(
|
|
137
|
+
isString(input) ? defStringReader(input) : isArrayLike(input) ? defArrayReader(input) : input,
|
|
138
|
+
opts
|
|
139
|
+
);
|
|
147
140
|
}
|
|
141
|
+
export {
|
|
142
|
+
ParseContext,
|
|
143
|
+
defContext
|
|
144
|
+
};
|