@thi.ng/parse 2.4.51 → 2.4.53
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 +10 -1
- package/README.md +3 -1
- package/api.d.ts +1 -14
- package/combinators/check.d.ts +2 -1
- package/combinators/lookahead.js +1 -1
- package/context.d.ts +20 -2
- package/context.js +44 -23
- package/package.json +4 -2
- package/prims/skip.js +1 -1
- package/prims/string.js +2 -2
- package/readers/array-reader.d.ts +2 -1
- package/readers/string-reader.d.ts +2 -1
- package/xform/count.js +1 -1
- package/xform/join.d.ts +2 -1
- package/xform/nest.d.ts +1 -1
- package/xform/nest.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2024-
|
|
3
|
+
- **Last updated**: 2024-09-05T12:23:14Z
|
|
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,15 @@ 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.52](https://github.com/thi-ng/umbrella/tree/@thi.ng/parse@2.4.52) (2024-08-29)
|
|
13
|
+
|
|
14
|
+
#### ⏱ Performance improvements
|
|
15
|
+
|
|
16
|
+
- update ParseState & ParseScope handling (result: 1.2-1.6x faster) ([c94b5cf](https://github.com/thi-ng/umbrella/commit/c94b5cf))
|
|
17
|
+
- refactor ParseState/Scope as data classes (keep same structure)
|
|
18
|
+
- minor update scope transforms
|
|
19
|
+
- update tests
|
|
20
|
+
|
|
12
21
|
### [2.4.43](https://github.com/thi-ng/umbrella/tree/@thi.ng/parse@2.4.43) (2024-06-21)
|
|
13
22
|
|
|
14
23
|
#### ♻️ Refactoring
|
package/README.md
CHANGED
|
@@ -73,6 +73,8 @@ grammars](https://makertube.net/w/ursFuQNJQQskmejx1ydL7q)
|
|
|
73
73
|
|
|
74
74
|
## Related packages
|
|
75
75
|
|
|
76
|
+
- [@thi.ng/hiccup-markdown](https://github.com/thi-ng/umbrella/tree/develop/packages/hiccup-markdown) - Markdown parser & serializer from/to Hiccup format
|
|
77
|
+
- [@thi.ng/proctext](https://github.com/thi-ng/umbrella/tree/develop/packages/proctext) - Extensible procedural text generation engine with dynamic, mutable state, indirection, randomizable & recursive variable expansions
|
|
76
78
|
- [@thi.ng/transducers-fsm](https://github.com/thi-ng/umbrella/tree/develop/packages/transducers-fsm) - Transducer-based Finite State Machine transformer
|
|
77
79
|
|
|
78
80
|
## Installation
|
|
@@ -101,7 +103,7 @@ For Node.js REPL:
|
|
|
101
103
|
const parse = await import("@thi.ng/parse");
|
|
102
104
|
```
|
|
103
105
|
|
|
104
|
-
Package sizes (brotli'd, pre-treeshake): ESM: 5.
|
|
106
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 5.27 KB
|
|
105
107
|
|
|
106
108
|
## Dependencies
|
|
107
109
|
|
package/api.d.ts
CHANGED
|
@@ -1,18 +1,5 @@
|
|
|
1
1
|
import type { Fn, Fn0, IObjectOf, Nullable } from "@thi.ng/api";
|
|
2
|
-
import type { ParseContext } from "./context.js";
|
|
3
|
-
export interface ParseScope<T> {
|
|
4
|
-
id: string;
|
|
5
|
-
state: Nullable<ParseState<T>>;
|
|
6
|
-
children: Nullable<ParseScope<T>[]>;
|
|
7
|
-
result: any;
|
|
8
|
-
}
|
|
9
|
-
export interface ParseState<T> {
|
|
10
|
-
p: number;
|
|
11
|
-
l: number;
|
|
12
|
-
c: number;
|
|
13
|
-
done?: boolean;
|
|
14
|
-
last?: T;
|
|
15
|
-
}
|
|
2
|
+
import type { ParseContext, ParseScope, ParseState } from "./context.js";
|
|
16
3
|
export interface IReader<T> {
|
|
17
4
|
read(state: ParseState<T>): T;
|
|
18
5
|
next(state: ParseState<T>): void;
|
package/combinators/check.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Predicate } from "@thi.ng/api";
|
|
2
|
-
import type { Parser
|
|
2
|
+
import type { Parser } from "../api.js";
|
|
3
|
+
import type { ParseScope } from "../context.js";
|
|
3
4
|
export declare const check: <T>(parser: Parser<T>, pred: Predicate<ParseScope<T>>, msg?: string) => Parser<T>;
|
|
4
5
|
//# sourceMappingURL=check.d.ts.map
|
package/combinators/lookahead.js
CHANGED
|
@@ -3,7 +3,7 @@ const lookahead = (parser, ahead, capture = false, id = "lookahead") => (ctx) =>
|
|
|
3
3
|
ctx.start(id);
|
|
4
4
|
let pass = false;
|
|
5
5
|
while (true) {
|
|
6
|
-
const state = capture ? null :
|
|
6
|
+
const state = capture ? null : ctx.state.copy();
|
|
7
7
|
if (ahead(ctx)) {
|
|
8
8
|
!capture && (ctx.state = state);
|
|
9
9
|
return pass ? ctx.end() : ctx.discard();
|
package/context.d.ts
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ICopy, Nullable } from "@thi.ng/api";
|
|
2
|
+
import type { ContextOpts, IReader } from "./api.js";
|
|
3
|
+
export declare class ParseState<T> implements ICopy<ParseState<T>> {
|
|
4
|
+
p: number;
|
|
5
|
+
l: number;
|
|
6
|
+
c: number;
|
|
7
|
+
done?: boolean | undefined;
|
|
8
|
+
last?: T | undefined;
|
|
9
|
+
constructor(p: number, l: number, c: number, done?: boolean | undefined, last?: T | undefined);
|
|
10
|
+
copy(): ParseState<T>;
|
|
11
|
+
}
|
|
12
|
+
export declare class ParseScope<T> implements ICopy<ParseScope<T>> {
|
|
13
|
+
id: string;
|
|
14
|
+
state?: Nullable<ParseState<T>>;
|
|
15
|
+
children?: Nullable<ParseScope<T>[]>;
|
|
16
|
+
result?: any;
|
|
17
|
+
constructor(id: string, state?: Nullable<ParseState<T>>, children?: Nullable<ParseScope<T>[]>, result?: any);
|
|
18
|
+
copy(): ParseScope<T>;
|
|
19
|
+
}
|
|
2
20
|
export declare class ParseContext<T> {
|
|
3
21
|
reader: IReader<T>;
|
|
4
22
|
opts: ContextOpts;
|
|
@@ -29,7 +47,7 @@ export declare class ParseContext<T> {
|
|
|
29
47
|
/**
|
|
30
48
|
* Returns root node's children or `undefined`.
|
|
31
49
|
*/
|
|
32
|
-
get children():
|
|
50
|
+
get children(): Nullable<ParseScope<T>[]>;
|
|
33
51
|
/**
|
|
34
52
|
* Returns max. recursion depth which was actually reached. Will always be
|
|
35
53
|
* less or equal configured {@link ContextOpts.maxDepth}.
|
package/context.js
CHANGED
|
@@ -4,6 +4,34 @@ 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
|
+
class ParseState {
|
|
8
|
+
constructor(p, l, c, done, last) {
|
|
9
|
+
this.p = p;
|
|
10
|
+
this.l = l;
|
|
11
|
+
this.c = c;
|
|
12
|
+
this.done = done;
|
|
13
|
+
this.last = last;
|
|
14
|
+
}
|
|
15
|
+
copy() {
|
|
16
|
+
return new ParseState(this.p, this.l, this.c, this.done, this.last);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
class ParseScope {
|
|
20
|
+
constructor(id, state, children, result) {
|
|
21
|
+
this.id = id;
|
|
22
|
+
this.state = state;
|
|
23
|
+
this.children = children;
|
|
24
|
+
this.result = result;
|
|
25
|
+
}
|
|
26
|
+
copy() {
|
|
27
|
+
return new ParseScope(
|
|
28
|
+
this.id,
|
|
29
|
+
this.state,
|
|
30
|
+
this.children,
|
|
31
|
+
this.result
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
7
35
|
class ParseContext {
|
|
8
36
|
constructor(reader, opts) {
|
|
9
37
|
this.reader = reader;
|
|
@@ -21,28 +49,21 @@ class ParseContext {
|
|
|
21
49
|
_debug;
|
|
22
50
|
_retain;
|
|
23
51
|
reset() {
|
|
24
|
-
this._curr =
|
|
25
|
-
id: "root",
|
|
26
|
-
state: { p: 0, l: 1, c: 1 },
|
|
27
|
-
children: null,
|
|
28
|
-
result: null
|
|
29
|
-
};
|
|
52
|
+
this._curr = new ParseScope("root", new ParseState(0, 1, 1));
|
|
30
53
|
this._scopes = [this._curr];
|
|
31
54
|
this._peakDepth = 1;
|
|
32
55
|
this.reader.isDone(this._curr.state);
|
|
33
56
|
return this;
|
|
34
57
|
}
|
|
35
58
|
start(id) {
|
|
36
|
-
|
|
37
|
-
|
|
59
|
+
const { _scopes: scopes, _maxDepth } = this;
|
|
60
|
+
if (scopes.length >= _maxDepth) {
|
|
61
|
+
parseError(this, `recursion limit reached ${_maxDepth}`);
|
|
38
62
|
}
|
|
39
|
-
const
|
|
40
|
-
const scope = {
|
|
63
|
+
const scope = new ParseScope(
|
|
41
64
|
id,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
result: null
|
|
45
|
-
};
|
|
65
|
+
scopes[scopes.length - 1].state.copy()
|
|
66
|
+
);
|
|
46
67
|
scopes.push(scope);
|
|
47
68
|
this._peakDepth = Math.max(this._peakDepth, scopes.length);
|
|
48
69
|
this._debug && console.log(
|
|
@@ -62,11 +83,10 @@ class ParseContext {
|
|
|
62
83
|
const child = scopes.pop();
|
|
63
84
|
const parent = scopes[scopes.length - 1];
|
|
64
85
|
const cstate = child.state;
|
|
65
|
-
let pstate;
|
|
66
86
|
this._debug && console.log(
|
|
67
87
|
`${__indent(scopes.length + 1)}end: ${child.id} (${cstate.p})`
|
|
68
88
|
);
|
|
69
|
-
child.state = this._retain ?
|
|
89
|
+
child.state = this._retain ? parent.state.copy() : null;
|
|
70
90
|
parent.state = cstate;
|
|
71
91
|
const children = parent.children;
|
|
72
92
|
children ? children.push(child) : parent.children = [child];
|
|
@@ -75,20 +95,19 @@ class ParseContext {
|
|
|
75
95
|
}
|
|
76
96
|
addChild(id, result = null, newState = false) {
|
|
77
97
|
const curr = this._curr;
|
|
78
|
-
const
|
|
79
|
-
const child = {
|
|
98
|
+
const child = new ParseScope(
|
|
80
99
|
id,
|
|
81
|
-
|
|
82
|
-
|
|
100
|
+
this._retain ? curr.state.copy() : null,
|
|
101
|
+
null,
|
|
83
102
|
result
|
|
84
|
-
|
|
103
|
+
);
|
|
85
104
|
this._debug && console.log(
|
|
86
|
-
`${__indent(this._scopes.length + 1)}addChild: ${id} (${
|
|
105
|
+
`${__indent(this._scopes.length + 1)}addChild: ${id} (${curr.state.p})`
|
|
87
106
|
);
|
|
88
107
|
const children = curr.children;
|
|
89
108
|
children ? children.push(child) : curr.children = [child];
|
|
90
109
|
if (newState !== false) {
|
|
91
|
-
newState === true ? this.reader.next(
|
|
110
|
+
newState === true ? this.reader.next(curr.state) : this._curr.state = newState;
|
|
92
111
|
}
|
|
93
112
|
return true;
|
|
94
113
|
}
|
|
@@ -140,5 +159,7 @@ function defContext(input, opts) {
|
|
|
140
159
|
}
|
|
141
160
|
export {
|
|
142
161
|
ParseContext,
|
|
162
|
+
ParseScope,
|
|
163
|
+
ParseState,
|
|
143
164
|
defContext
|
|
144
165
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/parse",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.53",
|
|
4
4
|
"description": "Purely functional parser combinators & AST generation for generic inputs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -236,9 +236,11 @@
|
|
|
236
236
|
},
|
|
237
237
|
"thi.ng": {
|
|
238
238
|
"related": [
|
|
239
|
+
"hiccup-markdown",
|
|
240
|
+
"proctext",
|
|
239
241
|
"transducers-fsm"
|
|
240
242
|
],
|
|
241
243
|
"year": 2020
|
|
242
244
|
},
|
|
243
|
-
"gitHead": "
|
|
245
|
+
"gitHead": "9f71f7f82fed2a980078a96bdafd2e706f526c75\n"
|
|
244
246
|
}
|
package/prims/skip.js
CHANGED
package/prims/string.js
CHANGED
|
@@ -16,7 +16,7 @@ const string = (str, id = "string") => (ctx) => {
|
|
|
16
16
|
};
|
|
17
17
|
const stringD = (str) => (ctx) => {
|
|
18
18
|
if (ctx.done) return false;
|
|
19
|
-
const state =
|
|
19
|
+
const state = ctx.state.copy();
|
|
20
20
|
const reader = ctx.reader;
|
|
21
21
|
for (let i = 0, n = str.length; i < n; i++) {
|
|
22
22
|
if (state.done) return false;
|
|
@@ -30,7 +30,7 @@ const stringD = (str) => (ctx) => {
|
|
|
30
30
|
return true;
|
|
31
31
|
};
|
|
32
32
|
const stringOf = (pred, id = "string", reduce = (x) => x.join("")) => (ctx) => {
|
|
33
|
-
const state =
|
|
33
|
+
const state = ctx.state.copy();
|
|
34
34
|
const reader = ctx.reader;
|
|
35
35
|
let acc = [];
|
|
36
36
|
while (!state.done) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IReader } from "../api.js";
|
|
2
|
+
import type { ParseState } from "../context.js";
|
|
2
3
|
export declare class ArrayReader<T> implements IReader<T> {
|
|
3
4
|
protected _src: ArrayLike<T>;
|
|
4
5
|
constructor(_src: ArrayLike<T>);
|
package/xform/count.js
CHANGED
package/xform/join.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Nullable } from "@thi.ng/api";
|
|
2
|
-
import type { Parser
|
|
2
|
+
import type { Parser } from "../api.js";
|
|
3
|
+
import type { ParseScope } from "../context.js";
|
|
3
4
|
/**
|
|
4
5
|
* Recursively joins non-null results of all children into a single
|
|
5
6
|
* string, then discards children. Also see {@link join}.
|
package/xform/nest.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { Parser, ScopeTransform } from "../api.js";
|
|
|
5
5
|
*
|
|
6
6
|
* @remarks
|
|
7
7
|
* The nested parser is applied to a separate {@link ParseContext} and if
|
|
8
|
-
* successful, the resulting AST will be
|
|
8
|
+
* successful, the resulting AST will be transplanted into the current parse
|
|
9
9
|
* scope. If the nested parser fails, the scope will remain untouched.
|
|
10
10
|
*
|
|
11
11
|
* If the current parse context retains line/column details, the inner parse
|
package/xform/nest.js
CHANGED
|
@@ -3,7 +3,7 @@ import { defContext } from "../context.js";
|
|
|
3
3
|
import { xfJoin } from "./join.js";
|
|
4
4
|
const xfNest = (parser) => (scope, ctx) => {
|
|
5
5
|
if (!scope) return;
|
|
6
|
-
const src = scope.result || xfJoin(
|
|
6
|
+
const src = scope.result || xfJoin(scope.copy()).result;
|
|
7
7
|
const inner = defContext(src, ctx.opts);
|
|
8
8
|
const state = scope.state;
|
|
9
9
|
if (state) {
|