@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.
Files changed (54) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +1 -1
  3. package/api.js +0 -1
  4. package/combinators/alt.js +15 -21
  5. package/combinators/boundary.js +10 -4
  6. package/combinators/check.js +7 -4
  7. package/combinators/dynamic.js +8 -18
  8. package/combinators/expect.js +4 -1
  9. package/combinators/lookahead.js +17 -77
  10. package/combinators/maybe.js +4 -1
  11. package/combinators/not.js +10 -17
  12. package/combinators/repeat.js +26 -18
  13. package/combinators/seq.js +14 -10
  14. package/combinators/wrap.js +4 -1
  15. package/combinators/xform.js +16 -14
  16. package/context.js +134 -137
  17. package/error.js +6 -3
  18. package/grammar.js +241 -185
  19. package/package.json +12 -9
  20. package/presets/alpha.js +14 -17
  21. package/presets/bits.js +6 -2
  22. package/presets/digits.js +6 -8
  23. package/presets/escape.js +14 -11
  24. package/presets/hex.js +8 -13
  25. package/presets/numbers.js +12 -23
  26. package/presets/string.js +6 -1
  27. package/presets/whitespace.js +18 -32
  28. package/prims/always.js +6 -2
  29. package/prims/anchor.js +24 -21
  30. package/prims/fail.js +4 -1
  31. package/prims/lit.js +8 -19
  32. package/prims/none-of.js +10 -15
  33. package/prims/one-of.js +10 -14
  34. package/prims/pass.js +6 -12
  35. package/prims/range.js +18 -37
  36. package/prims/satisfy.js +17 -19
  37. package/prims/skip.js +13 -30
  38. package/prims/string.js +48 -43
  39. package/readers/array-reader.js +22 -20
  40. package/readers/string-reader.js +27 -26
  41. package/utils.js +4 -9
  42. package/xform/collect.js +9 -16
  43. package/xform/comp.js +19 -22
  44. package/xform/count.js +9 -16
  45. package/xform/discard.js +6 -10
  46. package/xform/hoist.js +15 -30
  47. package/xform/join.js +17 -24
  48. package/xform/json.js +8 -15
  49. package/xform/nest.js +21 -32
  50. package/xform/number.js +16 -36
  51. package/xform/print.js +21 -47
  52. package/xform/replace.js +9 -17
  53. package/xform/trim.js +8 -17
  54. package/xform/with-id.js +6 -8
@@ -1,29 +1,30 @@
1
1
  class StringReader {
2
- _src;
3
- constructor(_src) {
4
- this._src = _src;
5
- }
6
- read(state) {
7
- return this._src[state.p];
8
- }
9
- next(state) {
10
- if (state.done)
11
- return;
12
- state.last = this._src[state.p];
13
- if (state.last === "\n") {
14
- state.l++;
15
- state.c = 1;
16
- }
17
- else {
18
- state.c++;
19
- }
20
- state.done = ++state.p >= this._src.length;
21
- }
22
- isDone(state) {
23
- return (state.done = state.p >= this._src.length);
24
- }
25
- format(state) {
26
- return `offset ${state.p} (${state.l}:${state.c})`;
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
+ if (state.last === "\n") {
13
+ state.l++;
14
+ state.c = 1;
15
+ } else {
16
+ state.c++;
27
17
  }
18
+ state.done = ++state.p >= this._src.length;
19
+ }
20
+ isDone(state) {
21
+ return state.done = state.p >= this._src.length;
22
+ }
23
+ format(state) {
24
+ return `offset ${state.p} (${state.l}:${state.c})`;
25
+ }
28
26
  }
29
- export const defStringReader = (input) => new StringReader(input);
27
+ const defStringReader = (input) => new StringReader(input);
28
+ export {
29
+ defStringReader
30
+ };
package/utils.js CHANGED
@@ -1,10 +1,5 @@
1
- // thing:no-export
2
1
  const cache = [];
3
- /**
4
- * Memoized indentation.
5
- *
6
- * @param x -
7
- *
8
- * @internal
9
- */
10
- export const indent = (x) => (cache[x] = " ".repeat(x));
2
+ const indent = (x) => cache[x] = " ".repeat(x);
3
+ export {
4
+ indent
5
+ };
package/xform/collect.js CHANGED
@@ -1,18 +1,11 @@
1
1
  import { xform } from "../combinators/xform.js";
2
- /**
3
- * Collects results of all direct children into an array, then discards
4
- * children. Also see {@link collect}.
5
- *
6
- * @param scope -
7
- */
8
- export const xfCollect = (scope) => {
9
- scope.result = scope.children.map((c) => c.result);
10
- scope.children = null;
11
- return scope;
2
+ const xfCollect = (scope) => {
3
+ scope.result = scope.children.map((c) => c.result);
4
+ scope.children = null;
5
+ return scope;
6
+ };
7
+ const collect = (parser) => xform(parser, xfCollect);
8
+ export {
9
+ collect,
10
+ xfCollect
12
11
  };
13
- /**
14
- * Syntax sugar for `xform(parser, xfCollect)`.
15
- *
16
- * @param parser -
17
- */
18
- export const collect = (parser) => xform(parser, xfCollect);
package/xform/comp.js CHANGED
@@ -1,23 +1,20 @@
1
- /**
2
- * Takes any number of {@link ScopeTransform}s and composes them into
3
- * new xform w/ left to right order of execution.
4
- *
5
- * @param xs -
6
- */
7
- export const comp = (...xs) => {
8
- const [a, b, c, d] = xs;
9
- switch (xs.length) {
10
- case 0:
11
- return (x) => x;
12
- case 1:
13
- return a;
14
- case 2:
15
- return (scope, ctx, user) => b(a(scope, ctx, user), ctx, user);
16
- case 3:
17
- return (scope, ctx, user) => c(b(a(scope, ctx, user), ctx, user), ctx, user);
18
- case 4:
19
- return (scope, ctx, user) => d(c(b(a(scope, ctx, user), ctx, user), ctx, user), ctx, user);
20
- default:
21
- return (scope, ctx, user) => xs.reduce((scope, x) => x(scope, ctx, user), scope);
22
- }
1
+ const comp = (...xs) => {
2
+ const [a, b, c, d] = xs;
3
+ switch (xs.length) {
4
+ case 0:
5
+ return (x) => x;
6
+ case 1:
7
+ return a;
8
+ case 2:
9
+ return (scope, ctx, user) => b(a(scope, ctx, user), ctx, user);
10
+ case 3:
11
+ return (scope, ctx, user) => c(b(a(scope, ctx, user), ctx, user), ctx, user);
12
+ case 4:
13
+ return (scope, ctx, user) => d(c(b(a(scope, ctx, user), ctx, user), ctx, user), ctx, user);
14
+ default:
15
+ return (scope, ctx, user) => xs.reduce((scope2, x) => x(scope2, ctx, user), scope);
16
+ }
17
+ };
18
+ export {
19
+ comp
23
20
  };
package/xform/count.js CHANGED
@@ -1,18 +1,11 @@
1
1
  import { xform } from "../combinators/xform.js";
2
- /**
3
- * Stores number of children as result, then discards children. Also see
4
- * {@link count}.
5
- *
6
- * @param scope -
7
- */
8
- export const xfCount = (scope) => {
9
- scope.result = scope.children ? scope.children.length : 0;
10
- scope.children = null;
11
- return scope;
2
+ const xfCount = (scope) => {
3
+ scope.result = scope.children ? scope.children.length : 0;
4
+ scope.children = null;
5
+ return scope;
6
+ };
7
+ const count = (parser) => xform(parser, xfCount);
8
+ export {
9
+ count,
10
+ xfCount
12
11
  };
13
- /**
14
- * Syntax sugar for `xform(parser, xfCount)`.
15
- *
16
- * @param parser -
17
- */
18
- export const count = (parser) => xform(parser, xfCount);
package/xform/discard.js CHANGED
@@ -1,11 +1,7 @@
1
1
  import { xform } from "../combinators/xform.js";
2
- /**
3
- * Discards AST node and any of its children.
4
- */
5
- export const xfDiscard = () => null;
6
- /**
7
- * Syntax sugar for `xform(parser, xfDiscard)`.
8
- *
9
- * @param parser -
10
- */
11
- export const discard = (parser) => xform(parser, xfDiscard);
2
+ const xfDiscard = () => null;
3
+ const discard = (parser) => xform(parser, xfDiscard);
4
+ export {
5
+ discard,
6
+ xfDiscard
7
+ };
package/xform/hoist.js CHANGED
@@ -1,33 +1,18 @@
1
1
  import { xform } from "../combinators/xform.js";
2
- /**
3
- * Replace AST node with its first child node. Also see {@link hoist}.
4
- *
5
- * @param scope -
6
- */
7
- export const xfHoist = (scope) => {
8
- Object.assign(scope, scope.children[0]);
9
- return scope;
2
+ const xfHoist = (scope) => {
3
+ Object.assign(scope, scope.children[0]);
4
+ return scope;
10
5
  };
11
- /**
12
- * Moves the result of first child node to this node, then discards all
13
- * children. Also see {@link hoistR}.
14
- *
15
- * @param scope -
16
- */
17
- export const xfHoistResult = (scope) => {
18
- scope.result = scope.children[0].result;
19
- scope.children = null;
20
- return scope;
6
+ const xfHoistResult = (scope) => {
7
+ scope.result = scope.children[0].result;
8
+ scope.children = null;
9
+ return scope;
10
+ };
11
+ const hoist = (parser) => xform(parser, xfHoist);
12
+ const hoistResult = (parser) => xform(parser, xfHoistResult);
13
+ export {
14
+ hoist,
15
+ hoistResult,
16
+ xfHoist,
17
+ xfHoistResult
21
18
  };
22
- /**
23
- * Syntax sugar for `xform(parser, xfHoist)`.
24
- *
25
- * @param parser -
26
- */
27
- export const hoist = (parser) => xform(parser, xfHoist);
28
- /**
29
- * Syntax sugar for `xform(parser, xfHoistR)`.
30
- *
31
- * @param parser -
32
- */
33
- export const hoistResult = (parser) => xform(parser, xfHoistResult);
package/xform/join.js CHANGED
@@ -1,26 +1,19 @@
1
1
  import { xform } from "../combinators/xform.js";
2
- /**
3
- * Recursively joins non-null results of all children into a single
4
- * string, then discards children. Also see {@link join}.
5
- *
6
- * @param scope -
7
- */
8
- export const xfJoin = (scope) => {
9
- if (!scope || !scope.children)
10
- return null;
11
- const res = [];
12
- for (let c of scope.children) {
13
- xfJoin(c);
14
- if (c.result)
15
- res.push(c.result);
16
- }
17
- scope.result = res.join("");
18
- scope.children = null;
19
- return scope;
2
+ const xfJoin = (scope) => {
3
+ if (!scope || !scope.children)
4
+ return null;
5
+ const res = [];
6
+ for (let c of scope.children) {
7
+ xfJoin(c);
8
+ if (c.result)
9
+ res.push(c.result);
10
+ }
11
+ scope.result = res.join("");
12
+ scope.children = null;
13
+ return scope;
14
+ };
15
+ const join = (parser) => xform(parser, xfJoin);
16
+ export {
17
+ join,
18
+ xfJoin
20
19
  };
21
- /**
22
- * Syntax sugar for `xform(parser, xfJoin)`.
23
- *
24
- * @param parser -
25
- */
26
- export const join = (parser) => xform(parser, xfJoin);
package/xform/json.js CHANGED
@@ -1,18 +1,11 @@
1
1
  import { xform } from "../combinators/xform.js";
2
2
  import { xfJoin } from "./join.js";
3
- /**
4
- * First joins all children via {@link xfJoin}, then parses resulting string
5
- * using `JSON.parse()`.
6
- *
7
- * @param scope -
8
- */
9
- export const xfJson = (scope) => {
10
- scope.result = JSON.parse(xfJoin(scope).result);
11
- return scope;
3
+ const xfJson = (scope) => {
4
+ scope.result = JSON.parse(xfJoin(scope).result);
5
+ return scope;
6
+ };
7
+ const json = (parser) => xform(parser, xfJson);
8
+ export {
9
+ json,
10
+ xfJson
12
11
  };
13
- /**
14
- * Syntax sugar for `xform(parser, xfJson)`.
15
- *
16
- * @param parser -
17
- */
18
- export const json = (parser) => xform(parser, xfJson);
package/xform/nest.js CHANGED
@@ -1,36 +1,25 @@
1
1
  import { xform } from "../combinators/xform.js";
2
2
  import { defContext } from "../context.js";
3
3
  import { xfJoin } from "./join.js";
4
- /**
5
- * HOF scope transform which applies given parser to result of given scope's
6
- * result, or if result is null, first joins children using {@link xfJoin}.
7
- *
8
- * @remarks
9
- * The nested parser is applied to a separate {@link ParseContext} and if
10
- * successful, the resulting AST will be transplated into the current parse
11
- * scope. If the nested parser fails, the scope will remain untouched.
12
- *
13
- * If the current parse context retains line/column details, the inner parse
14
- * context will be configured to produce true absolute offsets for its results
15
- * as if they were in the main context.
16
- *
17
- * @param parser -
18
- */
19
- export const xfNest = (parser) => (scope, ctx) => {
20
- if (!scope)
21
- return;
22
- const src = scope.result || xfJoin({ ...scope }).result;
23
- const inner = defContext(src, ctx.opts);
24
- const state = scope.state;
25
- if (state) {
26
- const istate = inner.scope.state;
27
- istate.l = state.l;
28
- istate.c = state.c;
29
- }
30
- if (parser(inner)) {
31
- scope.result = null;
32
- scope.children = inner.children;
33
- }
34
- return scope;
4
+ const xfNest = (parser) => (scope, ctx) => {
5
+ if (!scope)
6
+ return;
7
+ const src = scope.result || xfJoin({ ...scope }).result;
8
+ const inner = defContext(src, ctx.opts);
9
+ const state = scope.state;
10
+ if (state) {
11
+ const istate = inner.scope.state;
12
+ istate.l = state.l;
13
+ istate.c = state.c;
14
+ }
15
+ if (parser(inner)) {
16
+ scope.result = null;
17
+ scope.children = inner.children;
18
+ }
19
+ return scope;
20
+ };
21
+ const nest = (outer, inner) => xform(outer, xfNest(inner));
22
+ export {
23
+ nest,
24
+ xfNest
35
25
  };
36
- export const nest = (outer, inner) => xform(outer, xfNest(inner));
package/xform/number.js CHANGED
@@ -1,40 +1,20 @@
1
1
  import { xform } from "../combinators/xform.js";
2
2
  import { xfJoin } from "./join.js";
3
- /**
4
- * Higher order transform. First joins all children via {@link xfJoin},
5
- * then parses resulting string into an integer with given `radix`.
6
- *
7
- * @param radix -
8
- */
9
- export const xfInt = (radix = 10) => (scope) => {
10
- scope.result = parseInt(xfJoin(scope).result, radix);
11
- return scope;
3
+ const xfInt = (radix = 10) => (scope) => {
4
+ scope.result = parseInt(xfJoin(scope).result, radix);
5
+ return scope;
12
6
  };
13
- /**
14
- * Syntax sugar for `xform(parser, xfInt(10))`
15
- *
16
- * @param parser
17
- */
18
- export const int = (parser) => xform(parser, xfInt(10));
19
- /**
20
- * Syntax sugar for `xform(parser, xfInt(16))`
21
- *
22
- * @param parser
23
- */
24
- export const hexInt = (parser) => xform(parser, xfInt(16));
25
- /**
26
- * First joins all children via {@link xfJoin}, then parses resulting
27
- * string into a floating point value.
28
- *
29
- * @param scope -
30
- */
31
- export const xfFloat = (scope) => {
32
- scope.result = parseFloat(xfJoin(scope).result);
33
- return scope;
7
+ const int = (parser) => xform(parser, xfInt(10));
8
+ const hexInt = (parser) => xform(parser, xfInt(16));
9
+ const xfFloat = (scope) => {
10
+ scope.result = parseFloat(xfJoin(scope).result);
11
+ return scope;
12
+ };
13
+ const float = (parser) => xform(parser, xfFloat);
14
+ export {
15
+ float,
16
+ hexInt,
17
+ int,
18
+ xfFloat,
19
+ xfInt
34
20
  };
35
- /**
36
- * Syntax sugar for `xform(parser, xfFloat)`
37
- *
38
- * @param parser
39
- */
40
- export const float = (parser) => xform(parser, xfFloat);
package/xform/print.js CHANGED
@@ -1,50 +1,24 @@
1
1
  import { xform } from "../combinators/xform.js";
2
2
  import { indent } from "../utils.js";
3
- /**
4
- * Side effect only. Higher order scope transform. Traverses current AST
5
- * node and all children and prints each node's ID, result and reader
6
- * state (if available). Also see {@link print}.
7
- *
8
- * @remarks
9
- * The optional `fn` function is used to print each AST node (default:
10
- * `console.log`).
11
- *
12
- * @param scope -
13
- * @param ctx -
14
- * @param level -
15
- */
16
- export const xfPrint = (fn = console.log) => {
17
- const $print = (scope, _, level = 0) => {
18
- if (!scope)
19
- return;
20
- const prefix = indent(level);
21
- const state = scope.state;
22
- const info = state ? ` (${state.l}:${state.c})` : "";
23
- fn(`${prefix}${scope.id}${info}: ${JSON.stringify(scope.result)}`);
24
- if (scope.children) {
25
- for (let c of scope.children) {
26
- $print(c, _, level + 1);
27
- }
28
- }
29
- return scope;
30
- };
31
- return $print;
3
+ const xfPrint = (fn = console.log) => {
4
+ const $print = (scope, _, level = 0) => {
5
+ if (!scope)
6
+ return;
7
+ const prefix = indent(level);
8
+ const state = scope.state;
9
+ const info = state ? ` (${state.l}:${state.c})` : "";
10
+ fn(`${prefix}${scope.id}${info}: ${JSON.stringify(scope.result)}`);
11
+ if (scope.children) {
12
+ for (let c of scope.children) {
13
+ $print(c, _, level + 1);
14
+ }
15
+ }
16
+ return scope;
17
+ };
18
+ return $print;
19
+ };
20
+ const print = (parser, fn) => xform(parser, xfPrint(fn));
21
+ export {
22
+ print,
23
+ xfPrint
32
24
  };
33
- /**
34
- * Syntax sugar for `xform(parser, xfPrint)`.
35
- *
36
- * @example
37
- * ```ts
38
- * print(seq([lit("["), oneOrMore(ALPHA), lit("]")]))(defContext("[abc]"))
39
- * // seq: null
40
- * // lit: "["
41
- * // repeat1: null
42
- * // lit: "a"
43
- * // lit: "b"
44
- * // lit: "c"
45
- * // lit: "]"
46
- * ```
47
- *
48
- * @param parser -
49
- */
50
- export const print = (parser, fn) => xform(parser, xfPrint(fn));
package/xform/replace.js CHANGED
@@ -1,19 +1,11 @@
1
1
  import { xform } from "../combinators/xform.js";
2
- /**
3
- * HOF scope transform which replaces a node's result with given pre-configured
4
- * value and discards node's children. Also see {@link replace}.
5
- *
6
- * @param result - replacement value
7
- */
8
- export const xfReplace = (result) => (scope) => {
9
- scope.result = result;
10
- scope.children = null;
11
- return scope;
2
+ const xfReplace = (result) => (scope) => {
3
+ scope.result = result;
4
+ scope.children = null;
5
+ return scope;
6
+ };
7
+ const replace = (parser, result) => xform(parser, xfReplace(result));
8
+ export {
9
+ replace,
10
+ xfReplace
12
11
  };
13
- /**
14
- * Syntax sugar for `xform(parser, xfReplace(result))`.
15
- *
16
- * @param parser -
17
- * @param result -
18
- */
19
- export const replace = (parser, result) => xform(parser, xfReplace(result));
package/xform/trim.js CHANGED
@@ -1,19 +1,10 @@
1
1
  import { xform } from "../combinators/xform.js";
2
- /**
3
- * Uses `String.trim()` to remove leading and trailing white space and
4
- * linebreak chars from node result.
5
- *
6
- * {@link trim}.
7
- *
8
- * @param scope -
9
- */
10
- export const xfTrim = (scope) => {
11
- scope.result = scope.result.trim();
12
- return scope;
2
+ const xfTrim = (scope) => {
3
+ scope.result = scope.result.trim();
4
+ return scope;
5
+ };
6
+ const trim = (parser) => xform(parser, xfTrim);
7
+ export {
8
+ trim,
9
+ xfTrim
13
10
  };
14
- /**
15
- * Syntax sugar for `xform(parser, xfTrim)`.
16
- *
17
- * @param parser -
18
- */
19
- export const trim = (parser) => xform(parser, xfTrim);
package/xform/with-id.js CHANGED
@@ -1,9 +1,7 @@
1
1
  import { xform } from "../combinators/xform.js";
2
- /**
3
- * Assigns given `id` to AST node. E.g. used for re-labeling parser
4
- * results defined by {@link defGrammar}.
5
- *
6
- * @param id -
7
- */
8
- export const xfID = (id) => (scope) => ((scope.id = id), scope);
9
- export const withID = (id, parser) => xform(parser, xfID(id));
2
+ const xfID = (id) => (scope) => (scope.id = id, scope);
3
+ const withID = (id, parser) => xform(parser, xfID(id));
4
+ export {
5
+ withID,
6
+ xfID
7
+ };