parsanol 0.10.0
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/LICENSE +21 -0
- package/README.md +39 -0
- package/dist/runtime.d.ts +86 -0
- package/dist/runtime.js +182 -0
- package/dist/suite.d.ts +20 -0
- package/dist/suite.js +86 -0
- package/package.json +43 -0
- package/vendor/parsanol-wasm/BUILT_FROM +2 -0
- package/vendor/parsanol-wasm/parsanol.cjs +528 -0
- package/vendor/parsanol-wasm/parsanol.d.ts +124 -0
- package/vendor/parsanol-wasm/parsanol_bg.wasm +0 -0
- package/vendor/parsanol-wasm/parsanol_bg.wasm.d.ts +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Ribose Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# parsanol-ts
|
|
2
|
+
|
|
3
|
+
The PARG artifact runtime for TypeScript: load a checksum-verified
|
|
4
|
+
`.parg` artifact, parse through the parsanol wasm engine, apply the
|
|
5
|
+
artifact's bindings, and materialize schema-driven models.
|
|
6
|
+
|
|
7
|
+
The engine is the vendored parsanol wasm build (`vendor/parsanol-wasm/`,
|
|
8
|
+
nodejs target) — **no grammar code lives here**; the baked artifact is
|
|
9
|
+
the contract.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { PargRuntime } from "parsanol";
|
|
15
|
+
|
|
16
|
+
// PARG_ARTIFACT_DIR (or an explicit dir) holds the baked artifacts.
|
|
17
|
+
const rt = PargRuntime.load("iso", undefined, process.env.PARG_ARTIFACT_DIR);
|
|
18
|
+
|
|
19
|
+
const bound = rt.parseAndBind("ISO 5537:2025"); // bound capture map
|
|
20
|
+
const shape = rt.parseShape("ISO 5537:2025"); // parsanol-shape tree
|
|
21
|
+
const text = rt.renderString("ISO 5537:2025"); // F6 render
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Construction throws unless the artifact's embedded checksum verifies.
|
|
25
|
+
|
|
26
|
+
## Vendored engine freshness
|
|
27
|
+
|
|
28
|
+
`vendor/parsanol-wasm/BUILT_FROM` records the parsanol-rs commit the
|
|
29
|
+
wasm was built from; `scripts/check-wasm-freshness.sh` fails when
|
|
30
|
+
parsanol-rs has moved. Refresh with `npm run refresh-wasm`.
|
|
31
|
+
|
|
32
|
+
## Conformance
|
|
33
|
+
|
|
34
|
+
`PargRuntime` parses with the same wasm binary the Rust and Ruby
|
|
35
|
+
engines validate against, so artifact-level conformance is inherited:
|
|
36
|
+
any baked artifact that passes its embedded tests on the other engines
|
|
37
|
+
passes here identically. Run the runtime tests with
|
|
38
|
+
`PARG_ARTIFACT_DIR=<artifacts> npm test` (the artifact-gated case
|
|
39
|
+
skips when no artifacts dir is set).
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
type PargArtifactJs = any;
|
|
2
|
+
/** A field requirement from the binding-requirements schema. */
|
|
3
|
+
export interface FieldRequirement {
|
|
4
|
+
type: string;
|
|
5
|
+
card: string;
|
|
6
|
+
preprocess?: string;
|
|
7
|
+
}
|
|
8
|
+
/** The binding-requirements schema record for one entry. */
|
|
9
|
+
export interface EntrySchema {
|
|
10
|
+
root: string;
|
|
11
|
+
fields: Record<string, FieldRequirement>;
|
|
12
|
+
examples: {
|
|
13
|
+
input: string;
|
|
14
|
+
captures: Record<string, unknown>;
|
|
15
|
+
}[];
|
|
16
|
+
}
|
|
17
|
+
export type Schema = Record<string, EntrySchema>;
|
|
18
|
+
/**
|
|
19
|
+
* A loaded, checksum-verified PG artifact with its schema.
|
|
20
|
+
* Construction throws when the checksum does not verify.
|
|
21
|
+
*/
|
|
22
|
+
export declare class PargRuntime {
|
|
23
|
+
readonly artifact: PargArtifactJs;
|
|
24
|
+
readonly schema: Schema;
|
|
25
|
+
readonly renderSpec: Record<string, RenderSegment[]>;
|
|
26
|
+
readonly entry: string;
|
|
27
|
+
readonly defaultEntry: string | null;
|
|
28
|
+
readonly envelope: Record<string, unknown>;
|
|
29
|
+
constructor(artifactJson: string, entry?: string);
|
|
30
|
+
/** Load an artifact JSON file and verify its checksum. */
|
|
31
|
+
static fromFile(path: string, entry?: string): PargRuntime;
|
|
32
|
+
/** The artifacts directory: PARG_ARTIFACT_DIR when set. */
|
|
33
|
+
static artifactsDir(): string | null;
|
|
34
|
+
/** Load `<dir>/<grammar>.json`; throws when no artifacts dir is set. */
|
|
35
|
+
static load(grammar: string, entry?: string, dir?: string): PargRuntime;
|
|
36
|
+
/** Parse with the native wasm engine; returns the parsanol-shape tree. */
|
|
37
|
+
parseShape(input: string): unknown;
|
|
38
|
+
/** Apply the entry's bindings to a parsanol-shape tree. */
|
|
39
|
+
applyBindings(shape: unknown): Record<string, unknown>;
|
|
40
|
+
/** Parse and bind in one step. */
|
|
41
|
+
parseAndBind(input: string): Record<string, unknown> | null;
|
|
42
|
+
/**
|
|
43
|
+
* Schema-driven materialization: the schema (from the artifact, not
|
|
44
|
+
* hand-written model code) declares the fields a data model must
|
|
45
|
+
* implement; the bound captures populate a structurally-typed object.
|
|
46
|
+
* Card `1*`/`*` fields become arrays; `0..1` fields become nullable.
|
|
47
|
+
*/
|
|
48
|
+
materialize(input: string): Materialized | null;
|
|
49
|
+
/** Render the identifier string from a bound map (F6). */
|
|
50
|
+
render(bound: Record<string, unknown>, variant?: string): string;
|
|
51
|
+
/** Parse, bind, and render in one step. */
|
|
52
|
+
renderString(input: string, variant?: string): string | null;
|
|
53
|
+
/** Evaluate a named derive spec against a bound map (F6). */
|
|
54
|
+
derive(name: string, bound: Record<string, unknown>): string;
|
|
55
|
+
/** Parse, bind, and evaluate a derive spec in one step. */
|
|
56
|
+
deriveString(input: string, name: string): string | null;
|
|
57
|
+
/** Run the artifact's embedded tests; empty list means green. */
|
|
58
|
+
runTests(): string[];
|
|
59
|
+
}
|
|
60
|
+
/** F6 v1 derive evaluator: {field} interpolates from the bound map. */
|
|
61
|
+
export declare function deriveTemplate(derive: Record<string, string>, name: string, bound: Record<string, unknown>): string;
|
|
62
|
+
export type RenderSegment = {
|
|
63
|
+
type: "field";
|
|
64
|
+
field: string;
|
|
65
|
+
} | {
|
|
66
|
+
type: "literal";
|
|
67
|
+
text: string;
|
|
68
|
+
} | {
|
|
69
|
+
type: "cond";
|
|
70
|
+
field: string;
|
|
71
|
+
then: RenderSegment[];
|
|
72
|
+
};
|
|
73
|
+
/** F6 v1 generic renderer: field / literal / cond-presence segments. */
|
|
74
|
+
export declare function renderSegments(segments: RenderSegment[] | null, bound: Record<string, unknown>): string;
|
|
75
|
+
/** A schema-materialized identifier: typed fields plus provenance. */
|
|
76
|
+
export interface Materialized {
|
|
77
|
+
entry: string;
|
|
78
|
+
attributes: Record<string, unknown>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Schema-driven materialization independent of any wasm handle —
|
|
82
|
+
* the same function the model layer will build on (T2 codegen emits the
|
|
83
|
+
* static view of exactly these fields).
|
|
84
|
+
*/
|
|
85
|
+
export declare function materializeFromSchema(schema: EntrySchema, bound: Record<string, unknown>): Materialized;
|
|
86
|
+
export {};
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
//! The PARG artifact runtime for TypeScript: checksum-verified artifact
|
|
2
|
+
//! load, native wasm parse, bindings application, and schema-driven
|
|
3
|
+
//! materialization. The engine is the vendored parsanol wasm build
|
|
4
|
+
//! (PargArtifactJs) — no grammar code lives in this package; the baked
|
|
5
|
+
//! artifact is the contract.
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
10
|
+
/** Walk up from this module to the package root (which holds package.json). */
|
|
11
|
+
const packageRootCache = (() => {
|
|
12
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
for (; !existsSync(join(dir, "package.json")); dir = dirname(dir)) {
|
|
14
|
+
if (dir === dirname(dir))
|
|
15
|
+
throw new Error("package.json not found above the parg runtime");
|
|
16
|
+
}
|
|
17
|
+
return dir;
|
|
18
|
+
})();
|
|
19
|
+
function packageRoot() {
|
|
20
|
+
return packageRootCache;
|
|
21
|
+
}
|
|
22
|
+
// The vendored wasm glue is CommonJS and lives outside the compiled tree,
|
|
23
|
+
// so resolve it against the package root at runtime. Loading is deferred
|
|
24
|
+
// to the first artifact construction: importing this module costs
|
|
25
|
+
// nothing, and the ~1.5 MB wasm compiles only when parsing is real.
|
|
26
|
+
const require = createRequire(import.meta.url);
|
|
27
|
+
let wasmModule = null;
|
|
28
|
+
function wasm() {
|
|
29
|
+
if (wasmModule === null) {
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
31
|
+
wasmModule = require(join(packageRoot(), "vendor", "parsanol-wasm", "parsanol.cjs"));
|
|
32
|
+
}
|
|
33
|
+
return wasmModule;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A loaded, checksum-verified PG artifact with its schema.
|
|
37
|
+
* Construction throws when the checksum does not verify.
|
|
38
|
+
*/
|
|
39
|
+
export class PargRuntime {
|
|
40
|
+
artifact;
|
|
41
|
+
schema;
|
|
42
|
+
renderSpec;
|
|
43
|
+
entry;
|
|
44
|
+
defaultEntry;
|
|
45
|
+
envelope;
|
|
46
|
+
constructor(artifactJson, entry) {
|
|
47
|
+
const parsed = JSON.parse(artifactJson);
|
|
48
|
+
this.envelope = parsed;
|
|
49
|
+
this.artifact = new (wasm().PargArtifactJs)(artifactJson);
|
|
50
|
+
this.schema = JSON.parse(this.artifact.schema());
|
|
51
|
+
this.renderSpec =
|
|
52
|
+
parsed["render"] ?? {};
|
|
53
|
+
// The compiler bakes default_entry: JSON key order is not preserved
|
|
54
|
+
// across engines, so the sorted entry list cannot rederive it.
|
|
55
|
+
this.defaultEntry = parsed["default_entry"] ?? null;
|
|
56
|
+
this.entry = entry ?? this.defaultEntry ?? this.artifact.entryNames()[0];
|
|
57
|
+
}
|
|
58
|
+
/** Load an artifact JSON file and verify its checksum. */
|
|
59
|
+
static fromFile(path, entry) {
|
|
60
|
+
return new PargRuntime(readFileSync(path, "utf8"), entry);
|
|
61
|
+
}
|
|
62
|
+
/** The artifacts directory: PARG_ARTIFACT_DIR when set. */
|
|
63
|
+
static artifactsDir() {
|
|
64
|
+
return process.env.PARG_ARTIFACT_DIR ?? null;
|
|
65
|
+
}
|
|
66
|
+
/** Load `<dir>/<grammar>.json`; throws when no artifacts dir is set. */
|
|
67
|
+
static load(grammar, entry, dir) {
|
|
68
|
+
const base = dir ?? PargRuntime.artifactsDir();
|
|
69
|
+
if (!base) {
|
|
70
|
+
throw new Error("no artifacts directory: set PARG_ARTIFACT_DIR or pass dir");
|
|
71
|
+
}
|
|
72
|
+
return PargRuntime.fromFile(join(base, `${grammar}.json`), entry);
|
|
73
|
+
}
|
|
74
|
+
/** Parse with the native wasm engine; returns the parsanol-shape tree. */
|
|
75
|
+
parseShape(input) {
|
|
76
|
+
return JSON.parse(this.artifact.parseShape(this.entry, input));
|
|
77
|
+
}
|
|
78
|
+
/** Apply the entry's bindings to a parsanol-shape tree. */
|
|
79
|
+
applyBindings(shape) {
|
|
80
|
+
return JSON.parse(this.artifact.applyBindings(this.entry, JSON.stringify(shape)));
|
|
81
|
+
}
|
|
82
|
+
/** Parse and bind in one step. */
|
|
83
|
+
parseAndBind(input) {
|
|
84
|
+
try {
|
|
85
|
+
return JSON.parse(this.artifact.parseAndBind(this.entry, input));
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Schema-driven materialization: the schema (from the artifact, not
|
|
93
|
+
* hand-written model code) declares the fields a data model must
|
|
94
|
+
* implement; the bound captures populate a structurally-typed object.
|
|
95
|
+
* Card `1*`/`*` fields become arrays; `0..1` fields become nullable.
|
|
96
|
+
*/
|
|
97
|
+
materialize(input) {
|
|
98
|
+
const bound = this.parseAndBind(input);
|
|
99
|
+
if (bound === null)
|
|
100
|
+
return null;
|
|
101
|
+
const schema = this.schema[this.entry];
|
|
102
|
+
if (!schema)
|
|
103
|
+
throw new Error(`artifact has no schema for entry ${this.entry}`);
|
|
104
|
+
return materializeFromSchema(schema, bound);
|
|
105
|
+
}
|
|
106
|
+
/** Render the identifier string from a bound map (F6). */
|
|
107
|
+
render(bound, variant = "default") {
|
|
108
|
+
return renderSegments((this.renderSpec[variant] ?? null), bound);
|
|
109
|
+
}
|
|
110
|
+
/** Parse, bind, and render in one step. */
|
|
111
|
+
renderString(input, variant = "default") {
|
|
112
|
+
const bound = this.parseAndBind(input);
|
|
113
|
+
return bound === null ? null : this.render(bound, variant);
|
|
114
|
+
}
|
|
115
|
+
/** Evaluate a named derive spec against a bound map (F6). */
|
|
116
|
+
derive(name, bound) {
|
|
117
|
+
return deriveTemplate((this.envelope["derive"] ?? {}), name, bound);
|
|
118
|
+
}
|
|
119
|
+
/** Parse, bind, and evaluate a derive spec in one step. */
|
|
120
|
+
deriveString(input, name) {
|
|
121
|
+
const bound = this.parseAndBind(input);
|
|
122
|
+
return bound === null ? null : this.derive(name, bound);
|
|
123
|
+
}
|
|
124
|
+
/** Run the artifact's embedded tests; empty list means green. */
|
|
125
|
+
runTests() {
|
|
126
|
+
return JSON.parse(this.artifact.runTests());
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** F6 v1 derive evaluator: {field} interpolates from the bound map. */
|
|
130
|
+
export function deriveTemplate(derive, name, bound) {
|
|
131
|
+
const template = derive[name];
|
|
132
|
+
if (template === undefined)
|
|
133
|
+
throw new Error(`derive spec ${name} not declared`);
|
|
134
|
+
return template.replace(/\{(\w+)\}/g, (_, field) => {
|
|
135
|
+
const value = bound[field];
|
|
136
|
+
return value === undefined || value === null ? "" : String(value);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/** F6 v1 generic renderer: field / literal / cond-presence segments. */
|
|
140
|
+
export function renderSegments(segments, bound) {
|
|
141
|
+
let out = "";
|
|
142
|
+
for (const segment of segments ?? []) {
|
|
143
|
+
if (segment.type === "field") {
|
|
144
|
+
const value = bound[segment.field];
|
|
145
|
+
out += value === undefined || value === null ? "" : String(value);
|
|
146
|
+
}
|
|
147
|
+
else if (segment.type === "literal") {
|
|
148
|
+
out += segment.text;
|
|
149
|
+
}
|
|
150
|
+
else if (segment.type === "cond") {
|
|
151
|
+
const value = bound[segment.field];
|
|
152
|
+
if (value !== undefined && value !== null)
|
|
153
|
+
out += renderSegments(segment.then, bound);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Schema-driven materialization independent of any wasm handle —
|
|
160
|
+
* the same function the model layer will build on (T2 codegen emits the
|
|
161
|
+
* static view of exactly these fields).
|
|
162
|
+
*/
|
|
163
|
+
export function materializeFromSchema(schema, bound) {
|
|
164
|
+
const attributes = {};
|
|
165
|
+
for (const [path, requirements] of Object.entries(schema.fields)) {
|
|
166
|
+
const leaf = path.includes("[]")
|
|
167
|
+
? (path.split("].").pop() ?? path)
|
|
168
|
+
: path;
|
|
169
|
+
const value = bound[leaf];
|
|
170
|
+
if (requirements.card.endsWith("*")) {
|
|
171
|
+
const list = Array.isArray(value) ? value : value === undefined ? [] : [value];
|
|
172
|
+
attributes[leaf] = list;
|
|
173
|
+
}
|
|
174
|
+
else if (requirements.card === "0..1") {
|
|
175
|
+
attributes[leaf] = value === undefined ? null : value;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
attributes[leaf] = value;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return { entry: schema.root, attributes };
|
|
182
|
+
}
|
package/dist/suite.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { PargRuntime } from "./runtime.js";
|
|
2
|
+
export type TestKind = "accept" | "reject" | "example";
|
|
3
|
+
export interface SuiteTest {
|
|
4
|
+
kind: TestKind;
|
|
5
|
+
input: string;
|
|
6
|
+
expect?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
export interface Suite {
|
|
9
|
+
name: string;
|
|
10
|
+
entry?: string;
|
|
11
|
+
tests: SuiteTest[];
|
|
12
|
+
}
|
|
13
|
+
/** Parse one *.pgtest file (same grammar as Parsanol::PG::Suite#read_file). */
|
|
14
|
+
export declare function readSuite(text: string, name: string): Suite;
|
|
15
|
+
/** Load every *.pgtest file in a directory. */
|
|
16
|
+
export declare function loadSuites(dir: string): Suite[];
|
|
17
|
+
/** Run a suite against a runtime; returns failure descriptions. */
|
|
18
|
+
export declare function runSuite(runtime: PargRuntime, suite: Suite): string[];
|
|
19
|
+
/** The default suites directory: PARG_SUITES_DIR when set. */
|
|
20
|
+
export declare function suitesDir(): string | null;
|
package/dist/suite.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
//! T3: external *.pgtest suites run through the wasm runtime. The suite
|
|
2
|
+
//! syntax matches the Ruby loader (Parsanol::PG::Suite): a
|
|
3
|
+
//! `suite <name> [for <entry>] { ... }` header with accept / reject /
|
|
4
|
+
//! example lines. Green means Ruby and TypeScript agree on the contract.
|
|
5
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
const LINE = /^\s*(accept|reject|example)\s+"((?:[^"\\]|\\.)*)"(?:\s*\{([^}]*)\})?\s*$/;
|
|
8
|
+
const HEADER = /suite\s+(\w+)(?:\s+for\s+entry\s+(\w+))?\s*\{/;
|
|
9
|
+
/** Parse one *.pgtest file (same grammar as Parsanol::PG::Suite#read_file). */
|
|
10
|
+
export function readSuite(text, name) {
|
|
11
|
+
const body = text.replace(/^#[^\n]*\n/gm, "");
|
|
12
|
+
const header = HEADER.exec(body);
|
|
13
|
+
if (!header) {
|
|
14
|
+
throw new Error(`${name}: expected 'suite <name> [for <entry>] { ... }'`);
|
|
15
|
+
}
|
|
16
|
+
const tests = [];
|
|
17
|
+
for (const line of body.slice((header.index ?? 0) + header[0].length).split("\n")) {
|
|
18
|
+
if (line.trim() === "}")
|
|
19
|
+
break;
|
|
20
|
+
const match = LINE.exec(line);
|
|
21
|
+
if (!match)
|
|
22
|
+
continue;
|
|
23
|
+
const kind = match[1];
|
|
24
|
+
const rawInput = match[2] ?? "";
|
|
25
|
+
const input = JSON.parse(`"${rawInput}"`);
|
|
26
|
+
const expect = {};
|
|
27
|
+
if (match[3]) {
|
|
28
|
+
for (const pair of match[3].split(",")) {
|
|
29
|
+
const kv = /(\w+)\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(pair);
|
|
30
|
+
const key = kv?.[1];
|
|
31
|
+
const raw = kv?.[2];
|
|
32
|
+
if (key && raw !== undefined)
|
|
33
|
+
expect[key] = JSON.parse(`"${raw}"`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
tests.push(kind === "example" ? { kind, input, expect } : { kind, input });
|
|
37
|
+
}
|
|
38
|
+
const entry = header[2];
|
|
39
|
+
return entry === undefined
|
|
40
|
+
? { name: header[1] ?? "suite", tests }
|
|
41
|
+
: { name: header[1] ?? "suite", entry, tests };
|
|
42
|
+
}
|
|
43
|
+
/** Load every *.pgtest file in a directory. */
|
|
44
|
+
export function loadSuites(dir) {
|
|
45
|
+
return readdirSync(dir)
|
|
46
|
+
.filter((file) => file.endsWith(".pgtest"))
|
|
47
|
+
.map((file) => readSuite(readFileSync(join(dir, file), "utf8"), file.replace(/\.pgtest$/, "")));
|
|
48
|
+
}
|
|
49
|
+
/** Run a suite against a runtime; returns failure descriptions. */
|
|
50
|
+
export function runSuite(runtime, suite) {
|
|
51
|
+
const failures = [];
|
|
52
|
+
const entry = suite.entry ?? runtime.entry;
|
|
53
|
+
for (const test of suite.tests) {
|
|
54
|
+
// The wasm runtime throws on parse failure; that is the reject signal.
|
|
55
|
+
let bound = null;
|
|
56
|
+
try {
|
|
57
|
+
bound = runtime.artifact.parseAndBind(entry, test.input);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
bound = null;
|
|
61
|
+
}
|
|
62
|
+
if (test.kind === "reject") {
|
|
63
|
+
if (bound !== null) {
|
|
64
|
+
failures.push(`test ${JSON.stringify(test.input)}: expected the input to be rejected`);
|
|
65
|
+
}
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (bound === null) {
|
|
69
|
+
failures.push(`test ${JSON.stringify(test.input)}: expected the input to parse`);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (test.kind === "example") {
|
|
73
|
+
const parsed = JSON.parse(bound);
|
|
74
|
+
for (const [key, value] of Object.entries(test.expect ?? {})) {
|
|
75
|
+
if (parsed[key] !== value) {
|
|
76
|
+
failures.push(`test ${JSON.stringify(test.input)}: expected captures ${key}: ${JSON.stringify(value)}, got ${JSON.stringify(parsed[key])}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return failures;
|
|
82
|
+
}
|
|
83
|
+
/** The default suites directory: PARG_SUITES_DIR when set. */
|
|
84
|
+
export function suitesDir() {
|
|
85
|
+
return process.env.PARG_SUITES_DIR ?? null;
|
|
86
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "parsanol",
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "PARG artifact runtime for TypeScript — checksum-verified artifact load, wasm parse, bindings, schema-driven materialization",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/runtime.js",
|
|
7
|
+
"types": "dist/runtime.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/runtime.js",
|
|
10
|
+
"./suite": "./dist/suite.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist/",
|
|
14
|
+
"vendor/parsanol-wasm/"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p tsconfig.json",
|
|
18
|
+
"test": "npm run build && npx tsc -p tsconfig.test.json && node --test dist-test/test/*.test.js",
|
|
19
|
+
"refresh-wasm": "bash scripts/refresh-wasm.sh",
|
|
20
|
+
"prepublishOnly": "npm run build",
|
|
21
|
+
"bench": "node bench/bench.mjs"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=22"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/parsanol/parsanol-ts.git"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"parser",
|
|
33
|
+
"peg",
|
|
34
|
+
"parg",
|
|
35
|
+
"wasm",
|
|
36
|
+
"rust"
|
|
37
|
+
],
|
|
38
|
+
"private": false,
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^26.6.3",
|
|
41
|
+
"typescript": "^7.0.2"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
/* @ts-self-types="./parsanol.d.ts" */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A verified PARG artifact exposed to JavaScript: checksum-verified load,
|
|
5
|
+
* native parse, bindings application, embedded-suite runs and the
|
|
6
|
+
* binding-requirements schema (PN 2/4).
|
|
7
|
+
*/
|
|
8
|
+
class PargArtifactJs {
|
|
9
|
+
__destroy_into_raw() {
|
|
10
|
+
const ptr = this.__wbg_ptr;
|
|
11
|
+
this.__wbg_ptr = 0;
|
|
12
|
+
PargArtifactJsFinalization.unregister(this);
|
|
13
|
+
return ptr;
|
|
14
|
+
}
|
|
15
|
+
free() {
|
|
16
|
+
const ptr = this.__destroy_into_raw();
|
|
17
|
+
wasm.__wbg_pargartifactjs_free(ptr, 0);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Apply an entry's bindings to a parsanol-shape tree (JSON text).
|
|
21
|
+
* @param {string} entry
|
|
22
|
+
* @param {string} shape_json
|
|
23
|
+
* @returns {string}
|
|
24
|
+
*/
|
|
25
|
+
applyBindings(entry, shape_json) {
|
|
26
|
+
const ptr0 = passStringToWasm0(entry, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
27
|
+
const len0 = WASM_VECTOR_LEN;
|
|
28
|
+
const ptr1 = passStringToWasm0(shape_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
29
|
+
const len1 = WASM_VECTOR_LEN;
|
|
30
|
+
const ret = wasm.pargartifactjs_applyBindings(this.__wbg_ptr, ptr0, len0, ptr1, len1);
|
|
31
|
+
if (ret[2]) {
|
|
32
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
33
|
+
}
|
|
34
|
+
return takeFromExternrefTable0(ret[0]);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Declared entry point names, sorted.
|
|
38
|
+
* @returns {string[]}
|
|
39
|
+
*/
|
|
40
|
+
entryNames() {
|
|
41
|
+
const ret = wasm.pargartifactjs_entryNames(this.__wbg_ptr);
|
|
42
|
+
var v1 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
|
|
43
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
|
|
44
|
+
return v1;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Load and checksum-verify an artifact envelope.
|
|
48
|
+
* @param {string} artifact_json
|
|
49
|
+
*/
|
|
50
|
+
constructor(artifact_json) {
|
|
51
|
+
const ptr0 = passStringToWasm0(artifact_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
52
|
+
const len0 = WASM_VECTOR_LEN;
|
|
53
|
+
const ret = wasm.pargartifactjs_new(ptr0, len0);
|
|
54
|
+
if (ret[2]) {
|
|
55
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
56
|
+
}
|
|
57
|
+
this.__wbg_ptr = ret[0] >>> 0;
|
|
58
|
+
PargArtifactJsFinalization.register(this, this.__wbg_ptr, this);
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse and bind in one step.
|
|
63
|
+
* @param {string} entry
|
|
64
|
+
* @param {string} input
|
|
65
|
+
* @returns {string}
|
|
66
|
+
*/
|
|
67
|
+
parseAndBind(entry, input) {
|
|
68
|
+
const ptr0 = passStringToWasm0(entry, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
69
|
+
const len0 = WASM_VECTOR_LEN;
|
|
70
|
+
const ptr1 = passStringToWasm0(input, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
71
|
+
const len1 = WASM_VECTOR_LEN;
|
|
72
|
+
const ret = wasm.pargartifactjs_parseAndBind(this.__wbg_ptr, ptr0, len0, ptr1, len1);
|
|
73
|
+
if (ret[2]) {
|
|
74
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
75
|
+
}
|
|
76
|
+
return takeFromExternrefTable0(ret[0]);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Parse an entry with the native engine; returns the parsanol-shape
|
|
80
|
+
* tree as JSON text.
|
|
81
|
+
* @param {string} entry
|
|
82
|
+
* @param {string} input
|
|
83
|
+
* @returns {string}
|
|
84
|
+
*/
|
|
85
|
+
parseShape(entry, input) {
|
|
86
|
+
const ptr0 = passStringToWasm0(entry, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
87
|
+
const len0 = WASM_VECTOR_LEN;
|
|
88
|
+
const ptr1 = passStringToWasm0(input, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
89
|
+
const len1 = WASM_VECTOR_LEN;
|
|
90
|
+
const ret = wasm.pargartifactjs_parseShape(this.__wbg_ptr, ptr0, len0, ptr1, len1);
|
|
91
|
+
if (ret[2]) {
|
|
92
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
93
|
+
}
|
|
94
|
+
return takeFromExternrefTable0(ret[0]);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Run the artifact's embedded tests; returns the failure list as
|
|
98
|
+
* JSON (empty array means green).
|
|
99
|
+
* @returns {string}
|
|
100
|
+
*/
|
|
101
|
+
runTests() {
|
|
102
|
+
const ret = wasm.pargartifactjs_runTests(this.__wbg_ptr);
|
|
103
|
+
if (ret[2]) {
|
|
104
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
105
|
+
}
|
|
106
|
+
return takeFromExternrefTable0(ret[0]);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The binding-requirements schema as JSON text.
|
|
110
|
+
* @returns {string}
|
|
111
|
+
*/
|
|
112
|
+
schema() {
|
|
113
|
+
const ret = wasm.pargartifactjs_schema(this.__wbg_ptr);
|
|
114
|
+
if (ret[2]) {
|
|
115
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
116
|
+
}
|
|
117
|
+
return takeFromExternrefTable0(ret[0]);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The binding-requirements schema as TypeScript source.
|
|
121
|
+
* @returns {string}
|
|
122
|
+
*/
|
|
123
|
+
schemaTypescript() {
|
|
124
|
+
const ret = wasm.pargartifactjs_schemaTypescript(this.__wbg_ptr);
|
|
125
|
+
if (ret[2]) {
|
|
126
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
127
|
+
}
|
|
128
|
+
return takeFromExternrefTable0(ret[0]);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (Symbol.dispose) PargArtifactJs.prototype[Symbol.dispose] = PargArtifactJs.prototype.free;
|
|
132
|
+
exports.PargArtifactJs = PargArtifactJs;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* WASM parser instance
|
|
136
|
+
*
|
|
137
|
+
* Create with `new WasmParser(grammarJson)` and parse with `parse(input)`.
|
|
138
|
+
*/
|
|
139
|
+
class WasmParser {
|
|
140
|
+
static __wrap(ptr) {
|
|
141
|
+
ptr = ptr >>> 0;
|
|
142
|
+
const obj = Object.create(WasmParser.prototype);
|
|
143
|
+
obj.__wbg_ptr = ptr;
|
|
144
|
+
WasmParserFinalization.register(obj, obj.__wbg_ptr, obj);
|
|
145
|
+
return obj;
|
|
146
|
+
}
|
|
147
|
+
__destroy_into_raw() {
|
|
148
|
+
const ptr = this.__wbg_ptr;
|
|
149
|
+
this.__wbg_ptr = 0;
|
|
150
|
+
WasmParserFinalization.unregister(this);
|
|
151
|
+
return ptr;
|
|
152
|
+
}
|
|
153
|
+
free() {
|
|
154
|
+
const ptr = this.__destroy_into_raw();
|
|
155
|
+
wasm.__wbg_wasmparser_free(ptr, 0);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Create a new parser from a PARG artifact envelope and entry name.
|
|
159
|
+
*
|
|
160
|
+
* The artifact's canonical checksum is verified before any parsing;
|
|
161
|
+
* a mismatched or corrupt artifact is rejected (PN 2).
|
|
162
|
+
*
|
|
163
|
+
* # Arguments
|
|
164
|
+
* * `artifact_json` - JSON text of the PARG artifact envelope
|
|
165
|
+
* * `entry` - entry point name declared in the artifact
|
|
166
|
+
* @param {string} artifact_json
|
|
167
|
+
* @param {string} entry
|
|
168
|
+
* @returns {WasmParser}
|
|
169
|
+
*/
|
|
170
|
+
static fromArtifact(artifact_json, entry) {
|
|
171
|
+
const ptr0 = passStringToWasm0(artifact_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
172
|
+
const len0 = WASM_VECTOR_LEN;
|
|
173
|
+
const ptr1 = passStringToWasm0(entry, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
174
|
+
const len1 = WASM_VECTOR_LEN;
|
|
175
|
+
const ret = wasm.wasmparser_fromArtifact(ptr0, len0, ptr1, len1);
|
|
176
|
+
if (ret[2]) {
|
|
177
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
178
|
+
}
|
|
179
|
+
return WasmParser.__wrap(ret[0]);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Create a new parser from grammar JSON
|
|
183
|
+
*
|
|
184
|
+
* # Arguments
|
|
185
|
+
* * `grammar_json` - JSON string representing the grammar
|
|
186
|
+
*
|
|
187
|
+
* # Returns
|
|
188
|
+
* A new WasmParser instance
|
|
189
|
+
*
|
|
190
|
+
* # Throws
|
|
191
|
+
* If the grammar JSON is invalid
|
|
192
|
+
* @param {string} grammar_json
|
|
193
|
+
*/
|
|
194
|
+
constructor(grammar_json) {
|
|
195
|
+
const ptr0 = passStringToWasm0(grammar_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
196
|
+
const len0 = WASM_VECTOR_LEN;
|
|
197
|
+
const ret = wasm.wasmparser_new(ptr0, len0);
|
|
198
|
+
if (ret[2]) {
|
|
199
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
200
|
+
}
|
|
201
|
+
this.__wbg_ptr = ret[0] >>> 0;
|
|
202
|
+
WasmParserFinalization.register(this, this.__wbg_ptr, this);
|
|
203
|
+
return this;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Parse input and return JavaScript AST
|
|
207
|
+
*
|
|
208
|
+
* # Arguments
|
|
209
|
+
* * `input` - The input string to parse
|
|
210
|
+
*
|
|
211
|
+
* # Returns
|
|
212
|
+
* A JavaScript object representing the parsed AST
|
|
213
|
+
*
|
|
214
|
+
* # Throws
|
|
215
|
+
* If parsing fails
|
|
216
|
+
* @param {string} input
|
|
217
|
+
* @returns {any}
|
|
218
|
+
*/
|
|
219
|
+
parse(input) {
|
|
220
|
+
const ptr0 = passStringToWasm0(input, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
221
|
+
const len0 = WASM_VECTOR_LEN;
|
|
222
|
+
const ret = wasm.wasmparser_parse(this.__wbg_ptr, ptr0, len0);
|
|
223
|
+
if (ret[2]) {
|
|
224
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
225
|
+
}
|
|
226
|
+
return takeFromExternrefTable0(ret[0]);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Parse and return flat array (for Opal compatibility)
|
|
230
|
+
*
|
|
231
|
+
* # Arguments
|
|
232
|
+
* * `input` - The input string to parse
|
|
233
|
+
*
|
|
234
|
+
* # Returns
|
|
235
|
+
* A Uint32Array containing the flattened AST
|
|
236
|
+
*
|
|
237
|
+
* # Throws
|
|
238
|
+
* If parsing fails
|
|
239
|
+
* @param {string} input
|
|
240
|
+
* @returns {BigUint64Array}
|
|
241
|
+
*/
|
|
242
|
+
parse_flat(input) {
|
|
243
|
+
const ptr0 = passStringToWasm0(input, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
244
|
+
const len0 = WASM_VECTOR_LEN;
|
|
245
|
+
const ret = wasm.wasmparser_parse_flat(this.__wbg_ptr, ptr0, len0);
|
|
246
|
+
if (ret[3]) {
|
|
247
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
248
|
+
}
|
|
249
|
+
var v2 = getArrayU64FromWasm0(ret[0], ret[1]).slice();
|
|
250
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
|
|
251
|
+
return v2;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Parse and return JSON string
|
|
255
|
+
*
|
|
256
|
+
* # Arguments
|
|
257
|
+
* * `input` - The input string to parse
|
|
258
|
+
*
|
|
259
|
+
* # Returns
|
|
260
|
+
* A JSON string representing the parsed AST
|
|
261
|
+
*
|
|
262
|
+
* # Throws
|
|
263
|
+
* If parsing fails
|
|
264
|
+
* @param {string} input
|
|
265
|
+
* @returns {string}
|
|
266
|
+
*/
|
|
267
|
+
parse_json(input) {
|
|
268
|
+
let deferred3_0;
|
|
269
|
+
let deferred3_1;
|
|
270
|
+
try {
|
|
271
|
+
const ptr0 = passStringToWasm0(input, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
272
|
+
const len0 = WASM_VECTOR_LEN;
|
|
273
|
+
const ret = wasm.wasmparser_parse_json(this.__wbg_ptr, ptr0, len0);
|
|
274
|
+
var ptr2 = ret[0];
|
|
275
|
+
var len2 = ret[1];
|
|
276
|
+
if (ret[3]) {
|
|
277
|
+
ptr2 = 0; len2 = 0;
|
|
278
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
279
|
+
}
|
|
280
|
+
deferred3_0 = ptr2;
|
|
281
|
+
deferred3_1 = len2;
|
|
282
|
+
return getStringFromWasm0(ptr2, len2);
|
|
283
|
+
} finally {
|
|
284
|
+
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (Symbol.dispose) WasmParser.prototype[Symbol.dispose] = WasmParser.prototype.free;
|
|
289
|
+
exports.WasmParser = WasmParser;
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Initialize function for WASM
|
|
293
|
+
*/
|
|
294
|
+
function init() {
|
|
295
|
+
wasm.init();
|
|
296
|
+
}
|
|
297
|
+
exports.init = init;
|
|
298
|
+
|
|
299
|
+
function __wbg_get_imports() {
|
|
300
|
+
const import0 = {
|
|
301
|
+
__proto__: null,
|
|
302
|
+
__wbg___wbindgen_string_get_395e606bd0ee4427: function(arg0, arg1) {
|
|
303
|
+
const obj = arg1;
|
|
304
|
+
const ret = typeof(obj) === 'string' ? obj : undefined;
|
|
305
|
+
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
306
|
+
var len1 = WASM_VECTOR_LEN;
|
|
307
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
308
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
309
|
+
},
|
|
310
|
+
__wbg___wbindgen_throw_6ddd609b62940d55: function(arg0, arg1) {
|
|
311
|
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
312
|
+
},
|
|
313
|
+
__wbg_error_a6fa202b58aa1cd3: function(arg0, arg1) {
|
|
314
|
+
let deferred0_0;
|
|
315
|
+
let deferred0_1;
|
|
316
|
+
try {
|
|
317
|
+
deferred0_0 = arg0;
|
|
318
|
+
deferred0_1 = arg1;
|
|
319
|
+
console.error(getStringFromWasm0(arg0, arg1));
|
|
320
|
+
} finally {
|
|
321
|
+
wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
__wbg_getRandomValues_3f44b700395062e5: function() { return handleError(function (arg0, arg1) {
|
|
325
|
+
globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
|
|
326
|
+
}, arguments); },
|
|
327
|
+
__wbg_new_227d7c05414eb861: function() {
|
|
328
|
+
const ret = new Error();
|
|
329
|
+
return ret;
|
|
330
|
+
},
|
|
331
|
+
__wbg_new_a70fbab9066b301f: function() {
|
|
332
|
+
const ret = new Array();
|
|
333
|
+
return ret;
|
|
334
|
+
},
|
|
335
|
+
__wbg_new_ab79df5bd7c26067: function() {
|
|
336
|
+
const ret = new Object();
|
|
337
|
+
return ret;
|
|
338
|
+
},
|
|
339
|
+
__wbg_push_e87b0e732085a946: function(arg0, arg1) {
|
|
340
|
+
const ret = arg0.push(arg1);
|
|
341
|
+
return ret;
|
|
342
|
+
},
|
|
343
|
+
__wbg_set_7eaa4f96924fd6b3: function() { return handleError(function (arg0, arg1, arg2) {
|
|
344
|
+
const ret = Reflect.set(arg0, arg1, arg2);
|
|
345
|
+
return ret;
|
|
346
|
+
}, arguments); },
|
|
347
|
+
__wbg_stack_3b0d974bbf31e44f: function(arg0, arg1) {
|
|
348
|
+
const ret = arg1.stack;
|
|
349
|
+
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
350
|
+
const len1 = WASM_VECTOR_LEN;
|
|
351
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
352
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
353
|
+
},
|
|
354
|
+
__wbg_stringify_5ae93966a84901ac: function() { return handleError(function (arg0) {
|
|
355
|
+
const ret = JSON.stringify(arg0);
|
|
356
|
+
return ret;
|
|
357
|
+
}, arguments); },
|
|
358
|
+
__wbindgen_cast_0000000000000001: function(arg0) {
|
|
359
|
+
// Cast intrinsic for `F64 -> Externref`.
|
|
360
|
+
const ret = arg0;
|
|
361
|
+
return ret;
|
|
362
|
+
},
|
|
363
|
+
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
364
|
+
// Cast intrinsic for `Ref(String) -> Externref`.
|
|
365
|
+
const ret = getStringFromWasm0(arg0, arg1);
|
|
366
|
+
return ret;
|
|
367
|
+
},
|
|
368
|
+
__wbindgen_init_externref_table: function() {
|
|
369
|
+
const table = wasm.__wbindgen_externrefs;
|
|
370
|
+
const offset = table.grow(4);
|
|
371
|
+
table.set(0, undefined);
|
|
372
|
+
table.set(offset + 0, undefined);
|
|
373
|
+
table.set(offset + 1, null);
|
|
374
|
+
table.set(offset + 2, true);
|
|
375
|
+
table.set(offset + 3, false);
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
return {
|
|
379
|
+
__proto__: null,
|
|
380
|
+
"./parsanol_bg.js": import0,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const PargArtifactJsFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
385
|
+
? { register: () => {}, unregister: () => {} }
|
|
386
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_pargartifactjs_free(ptr >>> 0, 1));
|
|
387
|
+
const WasmParserFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
388
|
+
? { register: () => {}, unregister: () => {} }
|
|
389
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_wasmparser_free(ptr >>> 0, 1));
|
|
390
|
+
|
|
391
|
+
function addToExternrefTable0(obj) {
|
|
392
|
+
const idx = wasm.__externref_table_alloc();
|
|
393
|
+
wasm.__wbindgen_externrefs.set(idx, obj);
|
|
394
|
+
return idx;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function getArrayJsValueFromWasm0(ptr, len) {
|
|
398
|
+
ptr = ptr >>> 0;
|
|
399
|
+
const mem = getDataViewMemory0();
|
|
400
|
+
const result = [];
|
|
401
|
+
for (let i = ptr; i < ptr + 4 * len; i += 4) {
|
|
402
|
+
result.push(wasm.__wbindgen_externrefs.get(mem.getUint32(i, true)));
|
|
403
|
+
}
|
|
404
|
+
wasm.__externref_drop_slice(ptr, len);
|
|
405
|
+
return result;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function getArrayU64FromWasm0(ptr, len) {
|
|
409
|
+
ptr = ptr >>> 0;
|
|
410
|
+
return getBigUint64ArrayMemory0().subarray(ptr / 8, ptr / 8 + len);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function getArrayU8FromWasm0(ptr, len) {
|
|
414
|
+
ptr = ptr >>> 0;
|
|
415
|
+
return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
let cachedBigUint64ArrayMemory0 = null;
|
|
419
|
+
function getBigUint64ArrayMemory0() {
|
|
420
|
+
if (cachedBigUint64ArrayMemory0 === null || cachedBigUint64ArrayMemory0.byteLength === 0) {
|
|
421
|
+
cachedBigUint64ArrayMemory0 = new BigUint64Array(wasm.memory.buffer);
|
|
422
|
+
}
|
|
423
|
+
return cachedBigUint64ArrayMemory0;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
let cachedDataViewMemory0 = null;
|
|
427
|
+
function getDataViewMemory0() {
|
|
428
|
+
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
|
|
429
|
+
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
|
430
|
+
}
|
|
431
|
+
return cachedDataViewMemory0;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function getStringFromWasm0(ptr, len) {
|
|
435
|
+
ptr = ptr >>> 0;
|
|
436
|
+
return decodeText(ptr, len);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
let cachedUint8ArrayMemory0 = null;
|
|
440
|
+
function getUint8ArrayMemory0() {
|
|
441
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
442
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
443
|
+
}
|
|
444
|
+
return cachedUint8ArrayMemory0;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function handleError(f, args) {
|
|
448
|
+
try {
|
|
449
|
+
return f.apply(this, args);
|
|
450
|
+
} catch (e) {
|
|
451
|
+
const idx = addToExternrefTable0(e);
|
|
452
|
+
wasm.__wbindgen_exn_store(idx);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function isLikeNone(x) {
|
|
457
|
+
return x === undefined || x === null;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
461
|
+
if (realloc === undefined) {
|
|
462
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
463
|
+
const ptr = malloc(buf.length, 1) >>> 0;
|
|
464
|
+
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
465
|
+
WASM_VECTOR_LEN = buf.length;
|
|
466
|
+
return ptr;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
let len = arg.length;
|
|
470
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
471
|
+
|
|
472
|
+
const mem = getUint8ArrayMemory0();
|
|
473
|
+
|
|
474
|
+
let offset = 0;
|
|
475
|
+
|
|
476
|
+
for (; offset < len; offset++) {
|
|
477
|
+
const code = arg.charCodeAt(offset);
|
|
478
|
+
if (code > 0x7F) break;
|
|
479
|
+
mem[ptr + offset] = code;
|
|
480
|
+
}
|
|
481
|
+
if (offset !== len) {
|
|
482
|
+
if (offset !== 0) {
|
|
483
|
+
arg = arg.slice(offset);
|
|
484
|
+
}
|
|
485
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
486
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
487
|
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
488
|
+
|
|
489
|
+
offset += ret.written;
|
|
490
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
WASM_VECTOR_LEN = offset;
|
|
494
|
+
return ptr;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function takeFromExternrefTable0(idx) {
|
|
498
|
+
const value = wasm.__wbindgen_externrefs.get(idx);
|
|
499
|
+
wasm.__externref_table_dealloc(idx);
|
|
500
|
+
return value;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
504
|
+
cachedTextDecoder.decode();
|
|
505
|
+
function decodeText(ptr, len) {
|
|
506
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const cachedTextEncoder = new TextEncoder();
|
|
510
|
+
|
|
511
|
+
if (!('encodeInto' in cachedTextEncoder)) {
|
|
512
|
+
cachedTextEncoder.encodeInto = function (arg, view) {
|
|
513
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
514
|
+
view.set(buf);
|
|
515
|
+
return {
|
|
516
|
+
read: arg.length,
|
|
517
|
+
written: buf.length
|
|
518
|
+
};
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
let WASM_VECTOR_LEN = 0;
|
|
523
|
+
|
|
524
|
+
const wasmPath = `${__dirname}/parsanol_bg.wasm`;
|
|
525
|
+
const wasmBytes = require('fs').readFileSync(wasmPath);
|
|
526
|
+
const wasmModule = new WebAssembly.Module(wasmBytes);
|
|
527
|
+
let wasm = new WebAssembly.Instance(wasmModule, __wbg_get_imports()).exports;
|
|
528
|
+
wasm.__wbindgen_start();
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A verified PARG artifact exposed to JavaScript: checksum-verified load,
|
|
6
|
+
* native parse, bindings application, embedded-suite runs and the
|
|
7
|
+
* binding-requirements schema (PN 2/4).
|
|
8
|
+
*/
|
|
9
|
+
export class PargArtifactJs {
|
|
10
|
+
free(): void;
|
|
11
|
+
[Symbol.dispose](): void;
|
|
12
|
+
/**
|
|
13
|
+
* Apply an entry's bindings to a parsanol-shape tree (JSON text).
|
|
14
|
+
*/
|
|
15
|
+
applyBindings(entry: string, shape_json: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Declared entry point names, sorted.
|
|
18
|
+
*/
|
|
19
|
+
entryNames(): string[];
|
|
20
|
+
/**
|
|
21
|
+
* Load and checksum-verify an artifact envelope.
|
|
22
|
+
*/
|
|
23
|
+
constructor(artifact_json: string);
|
|
24
|
+
/**
|
|
25
|
+
* Parse and bind in one step.
|
|
26
|
+
*/
|
|
27
|
+
parseAndBind(entry: string, input: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Parse an entry with the native engine; returns the parsanol-shape
|
|
30
|
+
* tree as JSON text.
|
|
31
|
+
*/
|
|
32
|
+
parseShape(entry: string, input: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Run the artifact's embedded tests; returns the failure list as
|
|
35
|
+
* JSON (empty array means green).
|
|
36
|
+
*/
|
|
37
|
+
runTests(): string;
|
|
38
|
+
/**
|
|
39
|
+
* The binding-requirements schema as JSON text.
|
|
40
|
+
*/
|
|
41
|
+
schema(): string;
|
|
42
|
+
/**
|
|
43
|
+
* The binding-requirements schema as TypeScript source.
|
|
44
|
+
*/
|
|
45
|
+
schemaTypescript(): string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* WASM parser instance
|
|
50
|
+
*
|
|
51
|
+
* Create with `new WasmParser(grammarJson)` and parse with `parse(input)`.
|
|
52
|
+
*/
|
|
53
|
+
export class WasmParser {
|
|
54
|
+
free(): void;
|
|
55
|
+
[Symbol.dispose](): void;
|
|
56
|
+
/**
|
|
57
|
+
* Create a new parser from a PARG artifact envelope and entry name.
|
|
58
|
+
*
|
|
59
|
+
* The artifact's canonical checksum is verified before any parsing;
|
|
60
|
+
* a mismatched or corrupt artifact is rejected (PN 2).
|
|
61
|
+
*
|
|
62
|
+
* # Arguments
|
|
63
|
+
* * `artifact_json` - JSON text of the PARG artifact envelope
|
|
64
|
+
* * `entry` - entry point name declared in the artifact
|
|
65
|
+
*/
|
|
66
|
+
static fromArtifact(artifact_json: string, entry: string): WasmParser;
|
|
67
|
+
/**
|
|
68
|
+
* Create a new parser from grammar JSON
|
|
69
|
+
*
|
|
70
|
+
* # Arguments
|
|
71
|
+
* * `grammar_json` - JSON string representing the grammar
|
|
72
|
+
*
|
|
73
|
+
* # Returns
|
|
74
|
+
* A new WasmParser instance
|
|
75
|
+
*
|
|
76
|
+
* # Throws
|
|
77
|
+
* If the grammar JSON is invalid
|
|
78
|
+
*/
|
|
79
|
+
constructor(grammar_json: string);
|
|
80
|
+
/**
|
|
81
|
+
* Parse input and return JavaScript AST
|
|
82
|
+
*
|
|
83
|
+
* # Arguments
|
|
84
|
+
* * `input` - The input string to parse
|
|
85
|
+
*
|
|
86
|
+
* # Returns
|
|
87
|
+
* A JavaScript object representing the parsed AST
|
|
88
|
+
*
|
|
89
|
+
* # Throws
|
|
90
|
+
* If parsing fails
|
|
91
|
+
*/
|
|
92
|
+
parse(input: string): any;
|
|
93
|
+
/**
|
|
94
|
+
* Parse and return flat array (for Opal compatibility)
|
|
95
|
+
*
|
|
96
|
+
* # Arguments
|
|
97
|
+
* * `input` - The input string to parse
|
|
98
|
+
*
|
|
99
|
+
* # Returns
|
|
100
|
+
* A Uint32Array containing the flattened AST
|
|
101
|
+
*
|
|
102
|
+
* # Throws
|
|
103
|
+
* If parsing fails
|
|
104
|
+
*/
|
|
105
|
+
parse_flat(input: string): BigUint64Array;
|
|
106
|
+
/**
|
|
107
|
+
* Parse and return JSON string
|
|
108
|
+
*
|
|
109
|
+
* # Arguments
|
|
110
|
+
* * `input` - The input string to parse
|
|
111
|
+
*
|
|
112
|
+
* # Returns
|
|
113
|
+
* A JSON string representing the parsed AST
|
|
114
|
+
*
|
|
115
|
+
* # Throws
|
|
116
|
+
* If parsing fails
|
|
117
|
+
*/
|
|
118
|
+
parse_json(input: string): string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Initialize function for WASM
|
|
123
|
+
*/
|
|
124
|
+
export function init(): void;
|
|
Binary file
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const __wbg_pargartifactjs_free: (a: number, b: number) => void;
|
|
5
|
+
export const __wbg_wasmparser_free: (a: number, b: number) => void;
|
|
6
|
+
export const pargartifactjs_applyBindings: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
7
|
+
export const pargartifactjs_entryNames: (a: number) => [number, number];
|
|
8
|
+
export const pargartifactjs_new: (a: number, b: number) => [number, number, number];
|
|
9
|
+
export const pargartifactjs_parseAndBind: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
10
|
+
export const pargartifactjs_parseShape: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
11
|
+
export const pargartifactjs_runTests: (a: number) => [number, number, number];
|
|
12
|
+
export const pargartifactjs_schema: (a: number) => [number, number, number];
|
|
13
|
+
export const pargartifactjs_schemaTypescript: (a: number) => [number, number, number];
|
|
14
|
+
export const parsanol_c_last_error: () => number;
|
|
15
|
+
export const parsanol_c_parse: (a: bigint, b: number, c: number, d: number) => number;
|
|
16
|
+
export const parsanol_c_parse_len: (a: bigint, b: number, c: number, d: number, e: number) => number;
|
|
17
|
+
export const parsanol_c_register: (a: number) => bigint;
|
|
18
|
+
export const parsanol_c_release: (a: bigint) => void;
|
|
19
|
+
export const parsanol_grammar_atom_count: (a: number) => number;
|
|
20
|
+
export const parsanol_grammar_free: (a: number) => void;
|
|
21
|
+
export const parsanol_grammar_new: (a: number) => number;
|
|
22
|
+
export const parsanol_grammar_new_with_error: (a: number, b: number) => number;
|
|
23
|
+
export const parsanol_grammar_root: (a: number) => number;
|
|
24
|
+
export const parsanol_parg_error: (a: number, b: number) => number;
|
|
25
|
+
export const parsanol_parg_free: (a: number) => void;
|
|
26
|
+
export const parsanol_parg_parse: (a: number, b: number) => number;
|
|
27
|
+
export const parsanol_parse: (a: number, b: number, c: number) => number;
|
|
28
|
+
export const parsanol_parse_end_pos: (a: number, b: number) => number;
|
|
29
|
+
export const parsanol_parse_simple: (a: number, b: number) => number;
|
|
30
|
+
export const parsanol_result_ast_json: (a: number) => number;
|
|
31
|
+
export const parsanol_result_end_pos: (a: number) => number;
|
|
32
|
+
export const parsanol_result_error: (a: number) => number;
|
|
33
|
+
export const parsanol_result_free: (a: number) => void;
|
|
34
|
+
export const parsanol_result_success: (a: number) => number;
|
|
35
|
+
export const parsanol_version: () => number;
|
|
36
|
+
export const wasmparser_fromArtifact: (a: number, b: number, c: number, d: number) => [number, number, number];
|
|
37
|
+
export const wasmparser_new: (a: number, b: number) => [number, number, number];
|
|
38
|
+
export const wasmparser_parse: (a: number, b: number, c: number) => [number, number, number];
|
|
39
|
+
export const wasmparser_parse_flat: (a: number, b: number, c: number) => [number, number, number, number];
|
|
40
|
+
export const wasmparser_parse_json: (a: number, b: number, c: number) => [number, number, number, number];
|
|
41
|
+
export const init: () => void;
|
|
42
|
+
export const parsanol_string_free: (a: number) => void;
|
|
43
|
+
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
44
|
+
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
45
|
+
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
|
46
|
+
export const __wbindgen_exn_store: (a: number) => void;
|
|
47
|
+
export const __externref_table_alloc: () => number;
|
|
48
|
+
export const __wbindgen_externrefs: WebAssembly.Table;
|
|
49
|
+
export const __externref_table_dealloc: (a: number) => void;
|
|
50
|
+
export const __externref_drop_slice: (a: number, b: number) => void;
|
|
51
|
+
export const __wbindgen_start: () => void;
|