@thi.ng/parse 2.4.41 → 2.4.43
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 +8 -1
- package/README.md +4 -2
- package/combinators/alt.js +1 -2
- package/combinators/check.js +1 -2
- package/combinators/dynamic.d.ts +6 -5
- package/combinators/lookahead.d.ts +14 -10
- package/combinators/lookahead.js +2 -4
- package/combinators/not.js +1 -2
- package/combinators/seq.js +1 -2
- package/context.js +5 -5
- package/grammar.js +41 -39
- package/package.json +12 -12
- package/presets/string.js +2 -2
- package/prims/satisfy.js +2 -4
- package/prims/skip.d.ts +5 -4
- package/prims/skip.js +1 -2
- package/prims/string.js +5 -10
- package/readers/array-reader.js +1 -2
- package/readers/string-reader.js +1 -2
- package/utils.d.ts +1 -1
- package/utils.js +3 -3
- package/xform/comp.d.ts +2 -2
- package/xform/comp.js +4 -4
- package/xform/join.js +2 -4
- package/xform/nest.js +1 -2
- package/xform/print.d.ts +6 -6
- package/xform/print.js +3 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2024-
|
|
3
|
+
- **Last updated**: 2024-06-21T19:34:38Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -9,6 +9,13 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
### [2.4.43](https://github.com/thi-ng/umbrella/tree/@thi.ng/parse@2.4.43) (2024-06-21)
|
|
13
|
+
|
|
14
|
+
#### ♻️ Refactoring
|
|
15
|
+
|
|
16
|
+
- rename various rest args to be more semantically meaningful ([8088a56](https://github.com/thi-ng/umbrella/commit/8088a56))
|
|
17
|
+
- enforce uniform naming convention of internal functions ([56992b2](https://github.com/thi-ng/umbrella/commit/56992b2))
|
|
18
|
+
|
|
12
19
|
### [2.4.5](https://github.com/thi-ng/umbrella/tree/@thi.ng/parse@2.4.5) (2023-11-09)
|
|
13
20
|
|
|
14
21
|
#### ♻️ Refactoring
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://mastodon.thi.ng/@toxi)
|
|
8
8
|
|
|
9
9
|
> [!NOTE]
|
|
10
|
-
> This is one of
|
|
10
|
+
> This is one of 193 standalone projects, maintained as part
|
|
11
11
|
> of the [@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo
|
|
12
12
|
> and anti-framework.
|
|
13
13
|
>
|
|
@@ -47,7 +47,9 @@
|
|
|
47
47
|
|
|
48
48
|
Purely functional parser combinators & AST generation for generic inputs.
|
|
49
49
|
|
|
50
|
-
There's a 2h 45m long video tutorial (live stream) introducing this package:
|
|
50
|
+
There's a 2h 45m long video tutorial (live stream) introducing this package:
|
|
51
|
+
[Building a web editor for creating/testing parse
|
|
52
|
+
grammars](https://makertube.net/w/ursFuQNJQQskmejx1ydL7q)
|
|
51
53
|
|
|
52
54
|
### Features
|
|
53
55
|
|
package/combinators/alt.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { string } from "../prims/string.js";
|
|
2
2
|
import { discard } from "../xform/discard.js";
|
|
3
3
|
const alt = (parsers) => (ctx) => {
|
|
4
|
-
if (ctx.done)
|
|
5
|
-
return false;
|
|
4
|
+
if (ctx.done) return false;
|
|
6
5
|
for (let i = 0, n = parsers.length; i < n; i++) {
|
|
7
6
|
if (parsers[i](ctx)) {
|
|
8
7
|
return true;
|
package/combinators/check.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { parseError } from "../error.js";
|
|
2
2
|
import { xform } from "./xform.js";
|
|
3
3
|
const check = (parser, pred, msg = "check failed") => xform(parser, (scope, ctx) => {
|
|
4
|
-
if (!pred(scope))
|
|
5
|
-
parseError(ctx, msg);
|
|
4
|
+
if (!pred(scope)) parseError(ctx, msg);
|
|
6
5
|
return scope;
|
|
7
6
|
});
|
|
8
7
|
export {
|
package/combinators/dynamic.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import type { DynamicParser } from "../api.js";
|
|
2
2
|
/**
|
|
3
|
-
* Returns a parser function placeholder, whose implementation can be
|
|
4
|
-
*
|
|
3
|
+
* Returns a parser function placeholder, whose implementation can be set at a
|
|
4
|
+
* later stage via calling `.set()`. The parser always fails until set, after
|
|
5
|
+
* which it then delegates to the chosen impl.
|
|
5
6
|
*
|
|
6
7
|
* @examples
|
|
7
|
-
* ```ts
|
|
8
|
-
* import { defContext, dynamic
|
|
8
|
+
* ```ts tangle:../../export/dynamic.ts
|
|
9
|
+
* import { defContext, dynamic,lit } from "@thi.ng/parse";
|
|
9
10
|
*
|
|
10
11
|
* const parser = dynamic<string>();
|
|
11
12
|
* parser.set(lit("a"));
|
|
12
13
|
*
|
|
13
|
-
* parser(defContext("a"));
|
|
14
|
+
* console.log(parser(defContext("a")));
|
|
14
15
|
* // true
|
|
15
16
|
* ```
|
|
16
17
|
*/
|
|
@@ -25,8 +25,8 @@ import type { Parser } from "../api.js";
|
|
|
25
25
|
* behavior and not a bug.
|
|
26
26
|
*
|
|
27
27
|
* @example
|
|
28
|
-
* ```ts
|
|
29
|
-
* import { defContext, lookahead, oneOf, stringD } from "@thi.ng/parse";
|
|
28
|
+
* ```ts tangle:../../export/lookahead.ts
|
|
29
|
+
* import { defContext, join, lookahead, oneOf, stringD } from "@thi.ng/parse";
|
|
30
30
|
*
|
|
31
31
|
* const ctx = defContext("ababaaabbabba");
|
|
32
32
|
*
|
|
@@ -34,30 +34,34 @@ import type { Parser } from "../api.js";
|
|
|
34
34
|
* // note the use of `stringD()` to discard lookahead result
|
|
35
35
|
*
|
|
36
36
|
* // non-capturing lookahead
|
|
37
|
-
*
|
|
37
|
+
* console.log(
|
|
38
|
+
* join(lookahead(oneOf("ab"), stringD("abba")))(ctx)
|
|
39
|
+
* );
|
|
38
40
|
* // true
|
|
39
41
|
*
|
|
40
|
-
* ctx.result
|
|
42
|
+
* console.log(ctx.result);
|
|
41
43
|
* // "ababaa"
|
|
42
44
|
*
|
|
43
|
-
* ctx.state
|
|
45
|
+
* console.log(ctx.state);
|
|
44
46
|
* // { p: 6, l: 1, c: 7, done: false, last: 'a' }
|
|
45
47
|
* ```
|
|
46
48
|
*
|
|
47
49
|
* @example
|
|
48
|
-
* ```ts
|
|
49
|
-
* import { defContext, lookahead, oneOf, string } from "@thi.ng/parse";
|
|
50
|
+
* ```ts tangle:../../export/lookahead-2.ts
|
|
51
|
+
* import { defContext, join, lookahead, oneOf, string } from "@thi.ng/parse";
|
|
50
52
|
*
|
|
51
53
|
* const ctx = defContext("ababaaabbabba");
|
|
52
54
|
*
|
|
53
55
|
* // capturing lookahead
|
|
54
|
-
*
|
|
56
|
+
* console.log(
|
|
57
|
+
* join(lookahead(oneOf("ab"), string("abba"), true))(ctx)
|
|
58
|
+
* );
|
|
55
59
|
* // true
|
|
56
60
|
*
|
|
57
|
-
* ctx.result
|
|
61
|
+
* console.log(ctx.result);
|
|
58
62
|
* // "ababaaabba"
|
|
59
63
|
*
|
|
60
|
-
* ctx.state
|
|
64
|
+
* console.log(ctx.state);
|
|
61
65
|
* // { p: 10, l: 1, c: 11, done: false, last: 'a' }
|
|
62
66
|
* ```
|
|
63
67
|
*
|
package/combinators/lookahead.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const lookahead = (parser, ahead, capture = false, id = "lookahead") => (ctx) => {
|
|
2
|
-
if (ctx.done)
|
|
3
|
-
return false;
|
|
2
|
+
if (ctx.done) return false;
|
|
4
3
|
ctx.start(id);
|
|
5
4
|
let pass = false;
|
|
6
5
|
while (true) {
|
|
@@ -9,8 +8,7 @@ const lookahead = (parser, ahead, capture = false, id = "lookahead") => (ctx) =>
|
|
|
9
8
|
!capture && (ctx.state = state);
|
|
10
9
|
return pass ? ctx.end() : ctx.discard();
|
|
11
10
|
}
|
|
12
|
-
if (!parser(ctx))
|
|
13
|
-
return ctx.discard();
|
|
11
|
+
if (!parser(ctx)) return ctx.discard();
|
|
14
12
|
pass = true;
|
|
15
13
|
}
|
|
16
14
|
};
|
package/combinators/not.js
CHANGED
package/combinators/seq.js
CHANGED
package/context.js
CHANGED
|
@@ -3,7 +3,7 @@ import { isString } from "@thi.ng/checks/is-string";
|
|
|
3
3
|
import { parseError } from "./error.js";
|
|
4
4
|
import { defArrayReader } from "./readers/array-reader.js";
|
|
5
5
|
import { defStringReader } from "./readers/string-reader.js";
|
|
6
|
-
import {
|
|
6
|
+
import { __indent } from "./utils.js";
|
|
7
7
|
class ParseContext {
|
|
8
8
|
constructor(reader, opts) {
|
|
9
9
|
this.reader = reader;
|
|
@@ -46,7 +46,7 @@ class ParseContext {
|
|
|
46
46
|
scopes.push(scope);
|
|
47
47
|
this._peakDepth = Math.max(this._peakDepth, scopes.length);
|
|
48
48
|
this._debug && console.log(
|
|
49
|
-
`${
|
|
49
|
+
`${__indent(scopes.length)}start: ${id} (${scope.state.p})`
|
|
50
50
|
);
|
|
51
51
|
return this._curr = scope;
|
|
52
52
|
}
|
|
@@ -54,7 +54,7 @@ class ParseContext {
|
|
|
54
54
|
const scopes = this._scopes;
|
|
55
55
|
const child = scopes.pop();
|
|
56
56
|
this._curr = scopes[scopes.length - 1];
|
|
57
|
-
this._debug && console.log(`${
|
|
57
|
+
this._debug && console.log(`${__indent(scopes.length + 1)}discard: ${child.id}`);
|
|
58
58
|
return false;
|
|
59
59
|
}
|
|
60
60
|
end() {
|
|
@@ -64,7 +64,7 @@ class ParseContext {
|
|
|
64
64
|
const cstate = child.state;
|
|
65
65
|
let pstate;
|
|
66
66
|
this._debug && console.log(
|
|
67
|
-
`${
|
|
67
|
+
`${__indent(scopes.length + 1)}end: ${child.id} (${cstate.p})`
|
|
68
68
|
);
|
|
69
69
|
child.state = this._retain ? (pstate = parent.state, { p: pstate.p, l: pstate.l, c: pstate.c }) : null;
|
|
70
70
|
parent.state = cstate;
|
|
@@ -83,7 +83,7 @@ class ParseContext {
|
|
|
83
83
|
result
|
|
84
84
|
};
|
|
85
85
|
this._debug && console.log(
|
|
86
|
-
`${
|
|
86
|
+
`${__indent(this._scopes.length + 1)}addChild: ${id} (${cstate.p})`
|
|
87
87
|
);
|
|
88
88
|
const children = curr.children;
|
|
89
89
|
children ? children.push(child) : curr.children = [child];
|
package/grammar.js
CHANGED
|
@@ -43,8 +43,8 @@ import { print, xfPrint } from "./xform/print.js";
|
|
|
43
43
|
import { xfReplace } from "./xform/replace.js";
|
|
44
44
|
import { xfTrim } from "./xform/trim.js";
|
|
45
45
|
import { withID } from "./xform/with-id.js";
|
|
46
|
-
const
|
|
47
|
-
const
|
|
46
|
+
const APOS = litD("'");
|
|
47
|
+
const DASH = litD("-");
|
|
48
48
|
const REPEAT = maybe(
|
|
49
49
|
alt([
|
|
50
50
|
oneOf("?*+", "repeat"),
|
|
@@ -58,7 +58,7 @@ const REPEAT = maybe(
|
|
|
58
58
|
);
|
|
59
59
|
const DISCARD = maybe(lit("!"), void 0, "discard");
|
|
60
60
|
const CHAR_OR_ESC = alt([UNICODE, ESC, always()]);
|
|
61
|
-
const CHAR_RANGE = seq([CHAR_OR_ESC,
|
|
61
|
+
const CHAR_RANGE = seq([CHAR_OR_ESC, DASH, CHAR_OR_ESC], "charRange");
|
|
62
62
|
const CHAR_SEL = seq(
|
|
63
63
|
[
|
|
64
64
|
litD("["),
|
|
@@ -69,7 +69,7 @@ const CHAR_SEL = seq(
|
|
|
69
69
|
"charSel"
|
|
70
70
|
);
|
|
71
71
|
const ANY = lit(".", "any");
|
|
72
|
-
const LIT = hoistResult(seq([
|
|
72
|
+
const LIT = hoistResult(seq([APOS, CHAR_OR_ESC, APOS], "char"));
|
|
73
73
|
const SYM = join(oneOrMore(alt([ALPHA_NUM, oneOf(".-_$")]), "sym"));
|
|
74
74
|
const RULE_REF = seq([litD("<"), SYM, litD(">")], "ref");
|
|
75
75
|
const TERM_BODY = alt([RULE_REF, ANY, LIT, STRING, CHAR_SEL]);
|
|
@@ -119,9 +119,9 @@ const RULE = seq(
|
|
|
119
119
|
);
|
|
120
120
|
const COMMENT = seqD([WS0, litD("#"), lookahead(always(), DNL)]);
|
|
121
121
|
const GRAMMAR = zeroOrMore(alt([RULE, COMMENT]), "rules");
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
const
|
|
122
|
+
const __first = ($) => $.children[0];
|
|
123
|
+
const __nth = ($, n) => $.children[n];
|
|
124
|
+
const __compile = defmulti(
|
|
125
125
|
(scope) => scope.id,
|
|
126
126
|
{
|
|
127
127
|
unicode: "char"
|
|
@@ -129,15 +129,15 @@ const compile = defmulti(
|
|
|
129
129
|
{
|
|
130
130
|
[DEFAULT]: ($) => unsupported(`unknown op: ${$.id}`),
|
|
131
131
|
root: ($, lang, opts, flags) => {
|
|
132
|
-
const rules =
|
|
132
|
+
const rules = __first($).children;
|
|
133
133
|
rules.reduce(
|
|
134
|
-
(acc, r) => (acc[
|
|
134
|
+
(acc, r) => (acc[__first(r).result] = dynamic(), acc),
|
|
135
135
|
lang.rules
|
|
136
136
|
);
|
|
137
137
|
for (let r of rules) {
|
|
138
|
-
const id =
|
|
138
|
+
const id = __first(r).result;
|
|
139
139
|
lang.rules[id].set(
|
|
140
|
-
|
|
140
|
+
__compile(r, lang, opts, flags)
|
|
141
141
|
);
|
|
142
142
|
}
|
|
143
143
|
return lang;
|
|
@@ -147,22 +147,19 @@ const compile = defmulti(
|
|
|
147
147
|
opts.debug && console.log(`rule: ${id.result}`, xf);
|
|
148
148
|
const acc = [];
|
|
149
149
|
for (let b of body.children) {
|
|
150
|
-
const c =
|
|
150
|
+
const c = __compile(b, lang, opts, flags);
|
|
151
151
|
c && acc.push(c);
|
|
152
152
|
}
|
|
153
153
|
let parser = acc.length > 1 ? seq(acc, id.result) : withID(id.result, acc[0]);
|
|
154
154
|
if (xf.id === "sym") {
|
|
155
155
|
const $xf = lang.env[xf.result];
|
|
156
|
-
if (!$xf)
|
|
157
|
-
illegalArgs(`missing xform: ${xf.result}`);
|
|
156
|
+
if (!$xf) illegalArgs(`missing xform: ${xf.result}`);
|
|
158
157
|
parser = xform(parser, $xf);
|
|
159
158
|
} else if (xf.id === "ref") {
|
|
160
|
-
const $id =
|
|
161
|
-
if ($id === id)
|
|
162
|
-
illegalArgs(`self-referential: ${$id}`);
|
|
159
|
+
const $id = __first(xf).result;
|
|
160
|
+
if ($id === id) illegalArgs(`self-referential: ${$id}`);
|
|
163
161
|
const $xf = lang.rules[$id];
|
|
164
|
-
if (!$xf)
|
|
165
|
-
illegalArgs(`missing xform rule: ${$id}`);
|
|
162
|
+
if (!$xf) illegalArgs(`missing xform rule: ${$id}`);
|
|
166
163
|
parser = nest(parser, $xf);
|
|
167
164
|
} else if (xf.id === "string") {
|
|
168
165
|
parser = xform(parser, xfReplace(xf.result));
|
|
@@ -170,7 +167,7 @@ const compile = defmulti(
|
|
|
170
167
|
return parser;
|
|
171
168
|
},
|
|
172
169
|
ref: ($, lang, opts, flags) => {
|
|
173
|
-
const id =
|
|
170
|
+
const id = __first($).result;
|
|
174
171
|
opts.debug && console.log(`ref: ${id}`, flags);
|
|
175
172
|
const ref = lang.rules[id];
|
|
176
173
|
return ref ? flags.discard ? discard(ref) : ref : illegalArgs(`invalid rule ref: ${id}`);
|
|
@@ -178,8 +175,8 @@ const compile = defmulti(
|
|
|
178
175
|
term: ($, lang, opts, flags) => {
|
|
179
176
|
const [term, repeat2, discard2, lookahead2] = $.children;
|
|
180
177
|
opts.debug && console.log(`term: ${term.id}`, flags);
|
|
181
|
-
return
|
|
182
|
-
(discard3) =>
|
|
178
|
+
return __compileRDL(
|
|
179
|
+
(discard3) => __compile(term, lang, opts, { ...flags, discard: discard3 }),
|
|
183
180
|
repeat2,
|
|
184
181
|
discard2,
|
|
185
182
|
lookahead2,
|
|
@@ -190,8 +187,8 @@ const compile = defmulti(
|
|
|
190
187
|
lhterm: ($, lang, opts, flags) => {
|
|
191
188
|
const [term, repeat2, discard2] = $.children;
|
|
192
189
|
opts.debug && console.log(`lhterm: ${term.id}`);
|
|
193
|
-
return
|
|
194
|
-
(discard3) =>
|
|
190
|
+
return __compileRD(
|
|
191
|
+
(discard3) => __compile(term, lang, opts, { ...flags, discard: discard3 }),
|
|
195
192
|
repeat2,
|
|
196
193
|
discard2,
|
|
197
194
|
opts
|
|
@@ -200,13 +197,13 @@ const compile = defmulti(
|
|
|
200
197
|
alt: ($, lang, opts, flags) => {
|
|
201
198
|
opts.debug && console.log(`alt: ${$.id}`, flags);
|
|
202
199
|
const [term0, { children: terms }, repeat2, disc, lookahead2] = $.children;
|
|
203
|
-
const acc = [
|
|
200
|
+
const acc = [__compile(term0, lang, opts, flags)];
|
|
204
201
|
if (terms) {
|
|
205
202
|
for (let c of terms) {
|
|
206
|
-
acc.push(
|
|
203
|
+
acc.push(__compile(__first(c), lang, opts, flags));
|
|
207
204
|
}
|
|
208
205
|
}
|
|
209
|
-
return
|
|
206
|
+
return __compileRDL(
|
|
210
207
|
(optimize) => optimize || flags.discard ? acc.length > 1 ? altD(acc) : discard(acc[0]) : acc.length > 1 ? alt(acc) : acc[0],
|
|
211
208
|
repeat2,
|
|
212
209
|
disc,
|
|
@@ -236,17 +233,17 @@ const compile = defmulti(
|
|
|
236
233
|
},
|
|
237
234
|
charSel: ($, lang, opts, flags) => {
|
|
238
235
|
opts.debug && console.log("charSel", flags);
|
|
239
|
-
const choices =
|
|
240
|
-
(c) =>
|
|
236
|
+
const choices = __nth($, 1).children.map(
|
|
237
|
+
(c) => __compile(c, lang, opts, flags)
|
|
241
238
|
);
|
|
242
|
-
const invert =
|
|
239
|
+
const invert = __first($).result;
|
|
243
240
|
const parser = choices.length > 1 ? alt(choices) : choices[0];
|
|
244
241
|
opts.debug && console.log(`invert: ${invert}`);
|
|
245
242
|
return invert ? not(parser, flags.discard ? alwaysD() : always()) : parser;
|
|
246
243
|
}
|
|
247
244
|
}
|
|
248
245
|
);
|
|
249
|
-
const
|
|
246
|
+
const __compileRepeat = (parser, rspec, opts) => {
|
|
250
247
|
opts.debug && console.log(`repeat: ${rspec.id}`);
|
|
251
248
|
if (rspec.id === "repeat") {
|
|
252
249
|
switch (rspec.result) {
|
|
@@ -265,24 +262,29 @@ const compileRepeat = (parser, rspec, opts) => {
|
|
|
265
262
|
}
|
|
266
263
|
return parser;
|
|
267
264
|
};
|
|
268
|
-
const
|
|
265
|
+
const __compileDiscard = (parser, dspec, opts) => {
|
|
269
266
|
opts.debug && console.log(`discard:`, dspec.result);
|
|
270
267
|
return dspec.result === "!" ? discard(parser) : parser;
|
|
271
268
|
};
|
|
272
|
-
const
|
|
269
|
+
const __compileLookahead = (parser, spec, lang, opts) => {
|
|
273
270
|
opts.debug && console.log(`lookahead:`, spec.id);
|
|
274
271
|
return spec.id === "lhspec" ? lookahead(
|
|
275
272
|
parser,
|
|
276
|
-
|
|
277
|
-
|
|
273
|
+
__compile(__nth(spec, 1), lang, opts, {}),
|
|
274
|
+
__first(spec).result === "+"
|
|
278
275
|
) : parser;
|
|
279
276
|
};
|
|
280
|
-
const
|
|
281
|
-
|
|
277
|
+
const __compileRD = (parser, rspec, dspec, opts) => dspec.result != null && rspec.result == null ? parser(true) : __compileDiscard(
|
|
278
|
+
__compileRepeat(parser(false), rspec, opts),
|
|
282
279
|
dspec,
|
|
283
280
|
opts
|
|
284
281
|
);
|
|
285
|
-
const
|
|
282
|
+
const __compileRDL = (parser, rspec, dspec, lhspec, lang, opts) => __compileLookahead(
|
|
283
|
+
__compileRD(parser, rspec, dspec, opts),
|
|
284
|
+
lhspec,
|
|
285
|
+
lang,
|
|
286
|
+
opts
|
|
287
|
+
);
|
|
286
288
|
const defGrammar = (rules, env, opts) => {
|
|
287
289
|
opts = { debug: false, optimize: true, ...opts };
|
|
288
290
|
env = {
|
|
@@ -304,7 +306,7 @@ const defGrammar = (rules, env, opts) => {
|
|
|
304
306
|
const ctx = defContext(rules);
|
|
305
307
|
const result = (opts.debug ? print(GRAMMAR) : GRAMMAR)(ctx);
|
|
306
308
|
if (result) {
|
|
307
|
-
return
|
|
309
|
+
return __compile(
|
|
308
310
|
ctx.root,
|
|
309
311
|
{
|
|
310
312
|
env,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/parse",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.43",
|
|
4
4
|
"description": "Purely functional parser combinators & AST generation for generic inputs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"type": "git",
|
|
11
11
|
"url": "https://github.com/thi-ng/umbrella.git"
|
|
12
12
|
},
|
|
13
|
-
"homepage": "https://
|
|
13
|
+
"homepage": "https://thi.ng/parse",
|
|
14
14
|
"funding": [
|
|
15
15
|
{
|
|
16
16
|
"type": "github",
|
|
@@ -36,17 +36,17 @@
|
|
|
36
36
|
"tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@thi.ng/api": "^8.11.
|
|
40
|
-
"@thi.ng/checks": "^3.6.
|
|
41
|
-
"@thi.ng/defmulti": "^3.0.
|
|
42
|
-
"@thi.ng/errors": "^2.5.
|
|
43
|
-
"@thi.ng/strings": "^3.7.
|
|
39
|
+
"@thi.ng/api": "^8.11.3",
|
|
40
|
+
"@thi.ng/checks": "^3.6.5",
|
|
41
|
+
"@thi.ng/defmulti": "^3.0.40",
|
|
42
|
+
"@thi.ng/errors": "^2.5.8",
|
|
43
|
+
"@thi.ng/strings": "^3.7.34"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@microsoft/api-extractor": "^7.
|
|
47
|
-
"esbuild": "^0.
|
|
48
|
-
"typedoc": "^0.25.
|
|
49
|
-
"typescript": "^5.
|
|
46
|
+
"@microsoft/api-extractor": "^7.47.0",
|
|
47
|
+
"esbuild": "^0.21.5",
|
|
48
|
+
"typedoc": "^0.25.13",
|
|
49
|
+
"typescript": "^5.5.2"
|
|
50
50
|
},
|
|
51
51
|
"keywords": [
|
|
52
52
|
"ast",
|
|
@@ -241,5 +241,5 @@
|
|
|
241
241
|
],
|
|
242
242
|
"year": 2020
|
|
243
243
|
},
|
|
244
|
-
"gitHead": "
|
|
244
|
+
"gitHead": "154c95cf9d6bab32174498ec3b5b5d87e42be7f9\n"
|
|
245
245
|
}
|
package/presets/string.js
CHANGED
|
@@ -5,9 +5,9 @@ import { litD } from "../prims/lit.js";
|
|
|
5
5
|
import { noneOf } from "../prims/none-of.js";
|
|
6
6
|
import { join } from "../xform/join.js";
|
|
7
7
|
import { ESC, UNICODE } from "./escape.js";
|
|
8
|
-
const
|
|
8
|
+
const QUOTE = litD('"');
|
|
9
9
|
const STRING = join(
|
|
10
|
-
seq([
|
|
10
|
+
seq([QUOTE, zeroOrMore(alt([UNICODE, ESC, noneOf('"')])), QUOTE], "string")
|
|
11
11
|
);
|
|
12
12
|
export {
|
|
13
13
|
STRING
|
package/prims/satisfy.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
const satisfy = (pred, id = "satisfy") => (ctx) => {
|
|
2
|
-
if (ctx.done)
|
|
3
|
-
return false;
|
|
2
|
+
if (ctx.done) return false;
|
|
4
3
|
const r = ctx.reader.read(ctx.state);
|
|
5
4
|
return pred(r) ? ctx.addChild(id, r, true) : false;
|
|
6
5
|
};
|
|
7
6
|
const satisfyD = (pred) => (ctx) => {
|
|
8
|
-
if (ctx.done)
|
|
9
|
-
return false;
|
|
7
|
+
if (ctx.done) return false;
|
|
10
8
|
const state = ctx.state;
|
|
11
9
|
const reader = ctx.reader;
|
|
12
10
|
return pred(reader.read(state)) ? (reader.next(state), true) : false;
|
package/prims/skip.d.ts
CHANGED
|
@@ -7,16 +7,17 @@ import type { Parser } from "../api.js";
|
|
|
7
7
|
* of the input is reached, this parser will return true.
|
|
8
8
|
*
|
|
9
9
|
* @example
|
|
10
|
-
* ```ts
|
|
11
|
-
* import { defContext, litD, noneOfP, seqD, skipWhile } from "@thi.ng/parse";
|
|
10
|
+
* ```ts tangle:../../export/skip-while.ts
|
|
11
|
+
* import { defContext, litD, NL, noneOfP, seqD, skipWhile } from "@thi.ng/parse";
|
|
12
12
|
*
|
|
13
13
|
* const comment = seqD([litD("#"), skipWhile(noneOfP("\n")), NL]);
|
|
14
14
|
*
|
|
15
15
|
* const ctx = defContext("# ignore more!\n");
|
|
16
|
-
*
|
|
16
|
+
*
|
|
17
|
+
* console.log(comment(ctx));
|
|
17
18
|
* // true
|
|
18
19
|
*
|
|
19
|
-
* ctx.state
|
|
20
|
+
* console.log(ctx.state);
|
|
20
21
|
* // { p: 15, l: 2, c: 1, done: true, last: '\n' }
|
|
21
22
|
* ```
|
|
22
23
|
*
|
package/prims/skip.js
CHANGED
package/prims/string.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
const string = (str, id = "string") => (ctx) => {
|
|
2
|
-
if (ctx.done)
|
|
3
|
-
return false;
|
|
2
|
+
if (ctx.done) return false;
|
|
4
3
|
const scope = ctx.start(id);
|
|
5
4
|
const state = scope.state;
|
|
6
5
|
const reader = ctx.reader;
|
|
7
6
|
for (let i = 0, n = str.length; i < n; i++) {
|
|
8
|
-
if (state.done)
|
|
9
|
-
return false;
|
|
7
|
+
if (state.done) return false;
|
|
10
8
|
const r = reader.read(state);
|
|
11
9
|
if (r !== str[i]) {
|
|
12
10
|
return ctx.discard();
|
|
@@ -17,13 +15,11 @@ const string = (str, id = "string") => (ctx) => {
|
|
|
17
15
|
return ctx.end();
|
|
18
16
|
};
|
|
19
17
|
const stringD = (str) => (ctx) => {
|
|
20
|
-
if (ctx.done)
|
|
21
|
-
return false;
|
|
18
|
+
if (ctx.done) return false;
|
|
22
19
|
const state = { ...ctx.state };
|
|
23
20
|
const reader = ctx.reader;
|
|
24
21
|
for (let i = 0, n = str.length; i < n; i++) {
|
|
25
|
-
if (state.done)
|
|
26
|
-
return false;
|
|
22
|
+
if (state.done) return false;
|
|
27
23
|
const r = reader.read(state);
|
|
28
24
|
if (r !== str[i]) {
|
|
29
25
|
return false;
|
|
@@ -39,8 +35,7 @@ const stringOf = (pred, id = "string", reduce = (x) => x.join("")) => (ctx) => {
|
|
|
39
35
|
let acc = [];
|
|
40
36
|
while (!state.done) {
|
|
41
37
|
const r = reader.read(state);
|
|
42
|
-
if (!pred(r))
|
|
43
|
-
break;
|
|
38
|
+
if (!pred(r)) break;
|
|
44
39
|
acc.push(r);
|
|
45
40
|
reader.next(state);
|
|
46
41
|
}
|
package/readers/array-reader.js
CHANGED
package/readers/string-reader.js
CHANGED
package/utils.d.ts
CHANGED
package/utils.js
CHANGED
package/xform/comp.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ScopeTransform } from "../api.js";
|
|
|
3
3
|
* Takes any number of {@link ScopeTransform}s and composes them into
|
|
4
4
|
* new xform w/ left to right order of execution.
|
|
5
5
|
*
|
|
6
|
-
* @param
|
|
6
|
+
* @param xforms -
|
|
7
7
|
*/
|
|
8
|
-
export declare const comp: <T>(...
|
|
8
|
+
export declare const comp: <T>(...xforms: ScopeTransform<T>[]) => ScopeTransform<T>;
|
|
9
9
|
//# sourceMappingURL=comp.d.ts.map
|
package/xform/comp.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const comp = (...
|
|
2
|
-
const [a, b, c, d] =
|
|
3
|
-
switch (
|
|
1
|
+
const comp = (...xforms) => {
|
|
2
|
+
const [a, b, c, d] = xforms;
|
|
3
|
+
switch (xforms.length) {
|
|
4
4
|
case 0:
|
|
5
5
|
return (x) => x;
|
|
6
6
|
case 1:
|
|
@@ -12,7 +12,7 @@ const comp = (...xs) => {
|
|
|
12
12
|
case 4:
|
|
13
13
|
return (scope, ctx, user) => d(c(b(a(scope, ctx, user), ctx, user), ctx, user), ctx, user);
|
|
14
14
|
default:
|
|
15
|
-
return (scope, ctx, user) =>
|
|
15
|
+
return (scope, ctx, user) => xforms.reduce((scope2, x) => x(scope2, ctx, user), scope);
|
|
16
16
|
}
|
|
17
17
|
};
|
|
18
18
|
export {
|
package/xform/join.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { xform } from "../combinators/xform.js";
|
|
2
2
|
const xfJoin = (scope) => {
|
|
3
|
-
if (!scope || !scope.children)
|
|
4
|
-
return null;
|
|
3
|
+
if (!scope || !scope.children) return null;
|
|
5
4
|
const res = [];
|
|
6
5
|
for (let c of scope.children) {
|
|
7
6
|
xfJoin(c);
|
|
8
|
-
if (c.result)
|
|
9
|
-
res.push(c.result);
|
|
7
|
+
if (c.result) res.push(c.result);
|
|
10
8
|
}
|
|
11
9
|
scope.result = res.join("");
|
|
12
10
|
scope.children = null;
|
package/xform/nest.js
CHANGED
|
@@ -2,8 +2,7 @@ import { xform } from "../combinators/xform.js";
|
|
|
2
2
|
import { defContext } from "../context.js";
|
|
3
3
|
import { xfJoin } from "./join.js";
|
|
4
4
|
const xfNest = (parser) => (scope, ctx) => {
|
|
5
|
-
if (!scope)
|
|
6
|
-
return;
|
|
5
|
+
if (!scope) return;
|
|
7
6
|
const src = scope.result || xfJoin({ ...scope }).result;
|
|
8
7
|
const inner = defContext(src, ctx.opts);
|
|
9
8
|
const state = scope.state;
|
package/xform/print.d.ts
CHANGED
|
@@ -18,16 +18,16 @@ export declare const xfPrint: (fn?: Fn<string, void>) => ScopeTransform<any>;
|
|
|
18
18
|
* Syntax sugar for `xform(parser, xfPrint)`.
|
|
19
19
|
*
|
|
20
20
|
* @example
|
|
21
|
-
* ```ts
|
|
22
|
-
* import { defContext, lit, oneOrMore,
|
|
21
|
+
* ```ts tangle:../../export/print.ts
|
|
22
|
+
* import { ALPHA, defContext, lit, oneOrMore, print, seq } from "@thi.ng/parse";
|
|
23
23
|
*
|
|
24
|
-
* print(seq([lit("["), oneOrMore(ALPHA), lit("]")]))(defContext("[abc]"))
|
|
24
|
+
* print(seq([lit("["), oneOrMore(ALPHA), lit("]")]))(defContext("[abc]"));
|
|
25
25
|
* // seq: null
|
|
26
26
|
* // lit: "["
|
|
27
27
|
* // repeat1: null
|
|
28
|
-
* //
|
|
29
|
-
* //
|
|
30
|
-
* //
|
|
28
|
+
* // oneOf: "a"
|
|
29
|
+
* // oneOf: "b"
|
|
30
|
+
* // oneOf: "c"
|
|
31
31
|
* // lit: "]"
|
|
32
32
|
* ```
|
|
33
33
|
*
|
package/xform/print.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { xform } from "../combinators/xform.js";
|
|
2
|
-
import {
|
|
2
|
+
import { __indent } from "../utils.js";
|
|
3
3
|
const xfPrint = (fn = console.log) => {
|
|
4
4
|
const $print = (scope, _, level = 0) => {
|
|
5
|
-
if (!scope)
|
|
6
|
-
|
|
7
|
-
const prefix = indent(level);
|
|
5
|
+
if (!scope) return;
|
|
6
|
+
const prefix = __indent(level);
|
|
8
7
|
const state = scope.state;
|
|
9
8
|
const info = state ? ` (${state.l}:${state.c})` : "";
|
|
10
9
|
fn(`${prefix}${scope.id}${info}: ${JSON.stringify(scope.result)}`);
|