@ohm-js/wasm 0.4.3 → 0.6.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.
@@ -0,0 +1,3 @@
1
+ export declare function assert(cond: boolean, message?: string): asserts cond;
2
+ export declare function checkNotNull<T>(x: T, msg?: string): NonNullable<T>;
3
+ //# sourceMappingURL=assert.d.ts.map
@@ -0,0 +1,9 @@
1
+ export function assert(cond, message = 'Assertion failed') {
2
+ if (!cond)
3
+ throw new Error(message);
4
+ }
5
+ export function checkNotNull(x, msg = 'unexpected null value') {
6
+ assert(x != null, msg);
7
+ return x;
8
+ }
9
+ //# sourceMappingURL=assert.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1,56 @@
1
+ /* global process */
2
+ import * as ohm from 'ohm-js';
3
+ import fs from 'node:fs';
4
+ import { basename } from 'node:path';
5
+ import { parseArgs } from 'node:util';
6
+ import { Compiler } from './Compiler.js';
7
+ // Compile an Ohm grammar file (.ohm) to WebAssembly (.wasm).
8
+ function main() {
9
+ const argsConfig = {
10
+ options: {
11
+ grammarName: { short: 'g', type: 'string' },
12
+ output: { short: 'o', type: 'string' },
13
+ },
14
+ allowPositionals: true,
15
+ };
16
+ let args;
17
+ try {
18
+ args = parseArgs(argsConfig);
19
+ }
20
+ catch (e) {
21
+ // eslint-disable-next-line no-console
22
+ console.error(e.message);
23
+ printUsage();
24
+ process.exit(1);
25
+ }
26
+ if (args.positionals.length !== 1) {
27
+ printUsage();
28
+ process.exit(1);
29
+ }
30
+ const filename = args.positionals[0];
31
+ const ns = ohm.grammars(fs.readFileSync(filename, 'utf8'));
32
+ // By default, use the last grammar in the file.
33
+ let g = Object.values(ns).at(-1);
34
+ const { grammarName } = args.values;
35
+ if (grammarName) {
36
+ if (!ns[grammarName]) {
37
+ // eslint-disable-next-line no-console
38
+ console.error(`Grammar '${grammarName}' not found in ${filename}`);
39
+ process.exit(1);
40
+ }
41
+ g = ns[grammarName];
42
+ }
43
+ const bytes = new Compiler(g).compile();
44
+ const outFilename = args.values.output ?? filename.replace('.ohm', '.wasm');
45
+ fs.writeFileSync(outFilename, bytes);
46
+ // eslint-disable-next-line no-console
47
+ console.log(`Wrote Wasm to ${outFilename}`);
48
+ }
49
+ // Print usage information
50
+ function printUsage() {
51
+ const exeName = basename(process.argv[1]);
52
+ // eslint-disable-next-line no-console
53
+ console.log(`usage: ${exeName} [(--grammarName|-g) <name>] [(--output|-o) <file>] <ohm-grammar-file>`);
54
+ }
55
+ main();
56
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1,4 @@
1
+ import { WasmGrammar } from './miniohm.ts';
2
+ export declare function grammar(source: string): WasmGrammar;
3
+ export declare function grammars(source: string): Record<string, WasmGrammar>;
4
+ //# sourceMappingURL=compat.d.ts.map
@@ -0,0 +1,18 @@
1
+ import { grammars as grammarsJs, grammar as grammarJs } from 'ohm-js';
2
+ import { Compiler } from './Compiler.js';
3
+ import { WasmGrammar } from "./miniohm.js";
4
+ // TODO: Support a namespace parameter.
5
+ export function grammar(source) {
6
+ const compiler = new Compiler(grammarJs(source));
7
+ return new WasmGrammar(compiler.compile());
8
+ }
9
+ // TODO: Support a namespace parameter.
10
+ export function grammars(source) {
11
+ const ans = {};
12
+ for (const g of Object.values(grammarsJs(source))) {
13
+ const compiler = new Compiler(g);
14
+ ans[g.name] = new WasmGrammar(compiler.compile());
15
+ }
16
+ return ans;
17
+ }
18
+ //# sourceMappingURL=compat.js.map
@@ -0,0 +1,121 @@
1
+ export type Expr = Alt | Any | Apply | ApplyGeneralized | CaseInsensitive | Dispatch | End | Lex | LiftedTerminal | Lookahead | Opt | Not | Param | Plus | Range | Seq | Star | Terminal | UnicodeChar;
2
+ export interface Alt {
3
+ type: 'Alt';
4
+ children: Expr[];
5
+ outArity: number;
6
+ }
7
+ export declare const alt: (children: Expr[]) => Alt;
8
+ export interface Any {
9
+ type: 'Any';
10
+ }
11
+ export declare const any: () => Any;
12
+ type ApplyLike = Extract<Expr, {
13
+ type: 'Apply' | 'LiftedTerminal' | 'Param';
14
+ }>;
15
+ export interface Apply {
16
+ type: 'Apply';
17
+ ruleName: string;
18
+ children: ApplyLike[];
19
+ }
20
+ export declare const apply: (ruleName: string, children?: ApplyLike[]) => Apply;
21
+ export interface ApplyGeneralized {
22
+ type: 'ApplyGeneralized';
23
+ ruleName: string;
24
+ caseIdx: number;
25
+ }
26
+ export declare const applyGeneralized: (ruleName: string, caseIdx: number) => ApplyGeneralized;
27
+ export interface CaseInsensitive {
28
+ type: 'CaseInsensitive';
29
+ value: string;
30
+ }
31
+ export declare const caseInsensitive: (value: string) => CaseInsensitive;
32
+ export interface Dispatch {
33
+ type: 'Dispatch';
34
+ child: Expr;
35
+ patterns: Expr[][];
36
+ }
37
+ export declare const dispatch: (child: Apply | Param, patterns: Expr[][]) => Dispatch;
38
+ export interface End {
39
+ type: 'End';
40
+ }
41
+ export declare const end: () => End;
42
+ export interface Lex {
43
+ type: 'Lex';
44
+ child: Expr;
45
+ outArity: number;
46
+ }
47
+ export declare const lex: (child: Expr) => Lex;
48
+ export interface Lookahead {
49
+ type: 'Lookahead';
50
+ child: Expr;
51
+ outArity: number;
52
+ }
53
+ export declare const lookahead: (child: Expr) => Lookahead;
54
+ export interface Opt {
55
+ type: 'Opt';
56
+ child: Expr;
57
+ }
58
+ export declare const opt: (child: Expr) => Opt;
59
+ export interface Not {
60
+ type: 'Not';
61
+ child: Expr;
62
+ }
63
+ export declare const not: (child: Expr) => Not;
64
+ export interface Param {
65
+ type: 'Param';
66
+ index: number;
67
+ }
68
+ export declare const param: (index: number) => Param;
69
+ export interface Plus {
70
+ type: 'Plus';
71
+ child: Expr;
72
+ }
73
+ export declare const plus: (child: Expr) => Plus;
74
+ export interface Range {
75
+ type: 'Range';
76
+ lo: number;
77
+ hi: number;
78
+ }
79
+ export declare const range: (lo: number, hi: number) => Range;
80
+ export interface Seq {
81
+ type: 'Seq';
82
+ children: Expr[];
83
+ outArity: number;
84
+ }
85
+ export declare const seq: (children: Expr[]) => Seq;
86
+ export interface Star {
87
+ type: 'Star';
88
+ child: Expr;
89
+ }
90
+ export declare const star: (child: Expr) => Star;
91
+ export interface Terminal {
92
+ type: 'Terminal';
93
+ value: string;
94
+ }
95
+ export declare const terminal: (value: string, caseInsensitive?: boolean) => Terminal;
96
+ export interface UnicodeChar {
97
+ type: 'UnicodeChar';
98
+ categoryOrProp: string;
99
+ }
100
+ export declare const unicodeChar: (categoryOrProp: string) => UnicodeChar;
101
+ export interface LiftedTerminal {
102
+ type: 'LiftedTerminal';
103
+ terminalId: number;
104
+ }
105
+ export declare const liftedTerminal: (terminalId: number) => LiftedTerminal;
106
+ export declare function collectParams(exp: Expr, seen?: Set<number>): Param[];
107
+ export declare function substituteParams<T extends Expr>(exp: T, actuals: Exclude<Expr, Param>[]): Exclude<Expr, Param>;
108
+ export declare function specializedName(app: Apply | LiftedTerminal): string;
109
+ export type ExprType = Expr extends {
110
+ type: infer U;
111
+ } ? U : never;
112
+ export type RewriteActions = {
113
+ [K in ExprType]?: (exp: Extract<Expr, {
114
+ type: K;
115
+ }>) => Expr;
116
+ };
117
+ export declare function rewrite(exp: Expr, actions: RewriteActions): Expr;
118
+ export declare function toString(exp: Expr): string;
119
+ export declare function outArity(exp: Expr): number;
120
+ export {};
121
+ //# sourceMappingURL=ir.d.ts.map
package/dist/src/ir.js ADDED
@@ -0,0 +1,297 @@
1
+ // Types
2
+ // -------
3
+ export const alt = (children) => ({
4
+ type: 'Alt',
5
+ children,
6
+ outArity: outArity(children[0]),
7
+ });
8
+ export const any = () => ({ type: 'Any' });
9
+ export const apply = (ruleName, children = []) => ({
10
+ type: 'Apply',
11
+ ruleName,
12
+ children,
13
+ });
14
+ export const applyGeneralized = (ruleName, caseIdx) => ({
15
+ type: 'ApplyGeneralized',
16
+ ruleName,
17
+ caseIdx,
18
+ });
19
+ export const caseInsensitive = (value) => ({
20
+ type: 'CaseInsensitive',
21
+ value,
22
+ });
23
+ export const dispatch = (child, patterns) => ({
24
+ type: 'Dispatch',
25
+ child,
26
+ patterns,
27
+ });
28
+ export const end = () => ({ type: 'End' });
29
+ export const lex = (child) => ({
30
+ type: 'Lex',
31
+ child,
32
+ outArity: outArity(child),
33
+ });
34
+ export const lookahead = (child) => ({
35
+ type: 'Lookahead',
36
+ child,
37
+ outArity: outArity(child),
38
+ });
39
+ export const opt = (child) => ({ type: 'Opt', child });
40
+ export const not = (child) => ({ type: 'Not', child });
41
+ export const param = (index) => ({ type: 'Param', index });
42
+ export const plus = (child) => ({ type: 'Plus', child });
43
+ export const range = (lo, hi) => ({ type: 'Range', lo, hi });
44
+ export const seq = (children) => ({
45
+ type: 'Seq',
46
+ children,
47
+ outArity: children.reduce((acc, child) => acc + outArity(child), 0),
48
+ });
49
+ export const star = (child) => ({ type: 'Star', child });
50
+ export const terminal = (value, caseInsensitive = false) => ({
51
+ type: 'Terminal',
52
+ value,
53
+ });
54
+ export const unicodeChar = (categoryOrProp) => ({
55
+ type: 'UnicodeChar',
56
+ categoryOrProp,
57
+ });
58
+ export const liftedTerminal = (terminalId) => ({
59
+ type: 'LiftedTerminal',
60
+ terminalId,
61
+ });
62
+ // Helpers
63
+ // -------
64
+ function unreachable(x, msg) {
65
+ throw new Error(msg);
66
+ }
67
+ function checkNotNull(x, msg = 'unexpected null value') {
68
+ if (x == null)
69
+ throw new Error(msg);
70
+ return x;
71
+ }
72
+ function checkApplyLike(exp) {
73
+ return checkExprType(exp, 'Apply', 'LiftedTerminal', 'Param');
74
+ }
75
+ function checkExprType(exp, ...types) {
76
+ if (!types.includes(exp.type)) {
77
+ throw new Error(`Expected one of [${types.join(', ')}], but got '${exp.type}'`);
78
+ }
79
+ return exp;
80
+ }
81
+ export function collectParams(exp, seen = new Set()) {
82
+ switch (exp.type) {
83
+ case 'Param':
84
+ if (!seen.has(exp.index)) {
85
+ seen.add(exp.index);
86
+ return [exp];
87
+ }
88
+ return [];
89
+ case 'Alt':
90
+ case 'Apply':
91
+ case 'Seq':
92
+ return exp.children.flatMap(c => collectParams(c, seen));
93
+ case 'Dispatch':
94
+ case 'Lex':
95
+ case 'Lookahead':
96
+ case 'Not':
97
+ case 'Opt':
98
+ case 'Plus':
99
+ case 'Star':
100
+ return collectParams(exp.child, seen);
101
+ case 'Any':
102
+ case 'ApplyGeneralized':
103
+ case 'CaseInsensitive':
104
+ case 'End':
105
+ case 'LiftedTerminal':
106
+ case 'Range':
107
+ case 'Terminal':
108
+ case 'UnicodeChar':
109
+ return [];
110
+ default:
111
+ unreachable(exp, `not handled: ${exp}`);
112
+ }
113
+ }
114
+ // TODO: Maybe make the types tighter here, to avoid the use checkApplyLike.
115
+ export function substituteParams(exp, actuals) {
116
+ switch (exp.type) {
117
+ case 'Param':
118
+ return checkNotNull(actuals[exp.index]);
119
+ case 'Apply':
120
+ if (exp.children.length === 0)
121
+ return exp;
122
+ return apply(exp.ruleName, exp.children.map((c) => {
123
+ const ans = substituteParams(c, actuals);
124
+ return checkApplyLike(ans);
125
+ }));
126
+ case 'Dispatch': {
127
+ const newChild = substituteParams(exp.child, actuals);
128
+ return dispatch(checkExprType(newChild, 'Apply'), exp.patterns);
129
+ }
130
+ case 'Alt':
131
+ case 'Seq':
132
+ return {
133
+ type: exp.type,
134
+ children: exp.children.map(c => substituteParams(c, actuals)),
135
+ outArity: exp.outArity,
136
+ };
137
+ case 'Lex':
138
+ case 'Lookahead':
139
+ return {
140
+ type: exp.type,
141
+ child: substituteParams(exp.child, actuals),
142
+ outArity: exp.outArity,
143
+ };
144
+ case 'Not':
145
+ case 'Opt':
146
+ case 'Plus':
147
+ case 'Star':
148
+ return {
149
+ type: exp.type,
150
+ child: substituteParams(exp.child, actuals),
151
+ };
152
+ case 'Any':
153
+ case 'ApplyGeneralized':
154
+ case 'CaseInsensitive':
155
+ case 'End':
156
+ case 'LiftedTerminal':
157
+ case 'Range':
158
+ case 'Terminal':
159
+ case 'UnicodeChar':
160
+ return exp;
161
+ default:
162
+ unreachable(exp, `not handled: ${exp}`);
163
+ }
164
+ }
165
+ export function specializedName(app) {
166
+ if (app.type === 'LiftedTerminal') {
167
+ return `$term$${app.terminalId}`;
168
+ }
169
+ const argsNames = app.children
170
+ .map(c => {
171
+ if (c.type === 'Param')
172
+ throw new Error(`unexpected Param`);
173
+ return specializedName(c);
174
+ })
175
+ .join(',');
176
+ return app.ruleName + (argsNames.length > 0 ? `<${argsNames}>` : '');
177
+ }
178
+ export function rewrite(exp, actions) {
179
+ const action = actions[exp.type];
180
+ if (action) {
181
+ return action(exp);
182
+ }
183
+ switch (exp.type) {
184
+ case 'Alt':
185
+ return alt(exp.children.map((e) => rewrite(e, actions)));
186
+ case 'Seq':
187
+ return seq(exp.children.map((e) => rewrite(e, actions)));
188
+ case 'Any':
189
+ case 'Apply':
190
+ case 'ApplyGeneralized':
191
+ case 'CaseInsensitive':
192
+ case 'End':
193
+ case 'LiftedTerminal':
194
+ case 'Param':
195
+ case 'Range':
196
+ case 'Terminal':
197
+ case 'UnicodeChar':
198
+ return exp;
199
+ case 'Dispatch':
200
+ // We don't use the constructor here, to avoid type checking issues.
201
+ return { type: exp.type, child: rewrite(exp.child, actions), patterns: exp.patterns };
202
+ case 'Lex':
203
+ return lex(rewrite(exp.child, actions));
204
+ case 'Lookahead':
205
+ return lookahead(rewrite(exp.child, actions));
206
+ case 'Not':
207
+ return not(rewrite(exp.child, actions));
208
+ case 'Opt':
209
+ return opt(rewrite(exp.child, actions));
210
+ case 'Plus':
211
+ return plus(rewrite(exp.child, actions));
212
+ case 'Star':
213
+ return star(rewrite(exp.child, actions));
214
+ default:
215
+ unreachable(exp, `not handled: ${exp}`);
216
+ }
217
+ }
218
+ export function toString(exp) {
219
+ switch (exp.type) {
220
+ case 'Alt':
221
+ return `(${exp.children.map(toString).join(' | ')})`;
222
+ case 'Seq':
223
+ return `(${exp.children.map(toString).join(' ')})`;
224
+ case 'Any':
225
+ return '$any';
226
+ case 'Apply':
227
+ return exp.children.length > 0
228
+ ? `${exp.ruleName}<${exp.children.map(toString).join(',')}>`
229
+ : exp.ruleName;
230
+ case 'ApplyGeneralized':
231
+ return `${exp.ruleName}<#${exp.caseIdx}>`;
232
+ case 'CaseInsensitive':
233
+ return `$caseInsensitive<${JSON.stringify(exp.value)}>`;
234
+ case 'End':
235
+ return '$end';
236
+ case 'LiftedTerminal':
237
+ return `$term$${exp.terminalId}`;
238
+ case 'Param':
239
+ return `$${exp.index}`;
240
+ case 'Range':
241
+ return `${JSON.stringify(exp.lo)}..${JSON.stringify(exp.hi)}`;
242
+ case 'Terminal':
243
+ return JSON.stringify(exp.value);
244
+ case 'UnicodeChar':
245
+ return `$unicodeChar<${JSON.stringify(exp.categoryOrProp)}>`;
246
+ case 'Dispatch':
247
+ return `$dispatch`; // TODO: Improve this.
248
+ case 'Lex':
249
+ return `#${toString(exp.child)}`;
250
+ case 'Lookahead':
251
+ return `&${toString(exp.child)}`;
252
+ case 'Not':
253
+ return `~${toString(exp.child)}`;
254
+ case 'Opt':
255
+ return `${toString(exp.child)}?`;
256
+ case 'Plus':
257
+ return `${toString(exp.child)}+`;
258
+ case 'Star':
259
+ return `${toString(exp.child)}*`;
260
+ default:
261
+ unreachable(exp, `not handled: ${exp}`);
262
+ }
263
+ }
264
+ // Returns the number of bindings that `expr` produces in its parent — the
265
+ // "out arity" or "upwards arity". Note that there is potential confusion
266
+ // with iter nodes: they produce a single binding, but an expression like
267
+ // `(letter digit)*` can be said to have "arity 2".
268
+ export function outArity(exp) {
269
+ switch (exp.type) {
270
+ case 'Alt':
271
+ case 'Seq':
272
+ case 'Lex':
273
+ case 'Lookahead':
274
+ return exp.outArity;
275
+ case 'Any':
276
+ case 'Apply':
277
+ case 'ApplyGeneralized':
278
+ case 'CaseInsensitive':
279
+ case 'End':
280
+ case 'LiftedTerminal':
281
+ case 'Param':
282
+ case 'Range':
283
+ case 'Terminal':
284
+ case 'UnicodeChar':
285
+ case 'Dispatch':
286
+ return 1;
287
+ case 'Not':
288
+ return 0;
289
+ case 'Opt':
290
+ case 'Plus':
291
+ case 'Star':
292
+ return 1;
293
+ default:
294
+ unreachable(exp, `not handled: ${exp}`);
295
+ }
296
+ }
297
+ //# sourceMappingURL=ir.js.map
@@ -0,0 +1,87 @@
1
+ export declare class WasmGrammar {
2
+ name: string;
3
+ private _instance?;
4
+ private _imports;
5
+ private _ruleIds;
6
+ private _ruleNames;
7
+ private _input;
8
+ private _resultStack;
9
+ private _managedResultCount;
10
+ /**
11
+ * Create a new WasmGrammar object.
12
+ * If `bytes` is specified, the WebAssembly module will be synchronously
13
+ * compiled and instantiated. Use `instantiate` or `instantiateStreaming`
14
+ * to instantiate asynchronously.
15
+ */
16
+ constructor(bytes?: BufferSource);
17
+ private _init;
18
+ _beginUse(result: MatchResult): void;
19
+ _endUse(result: MatchResult): void;
20
+ static instantiate(source: BufferSource): Promise<WasmGrammar>;
21
+ static instantiateStreaming(source: Response | Promise<Response>): Promise<WasmGrammar>;
22
+ _instantiate(source: BufferSource, debugImports?: any): Promise<this>;
23
+ _instantiateStreaming(source: Response | Promise<Response>, debugImports?: any): Promise<WasmGrammar>;
24
+ private _getGrammarName;
25
+ private _extractRuleIds;
26
+ private _detachMatchResult;
27
+ match<T>(input: string, ruleName?: string): MatchResult;
28
+ getMemorySizeBytes(): number;
29
+ getCstRoot(): CstNode;
30
+ private _fillInputBuffer;
31
+ getRightmostFailurePosition(): number;
32
+ }
33
+ export declare class CstNode {
34
+ _ruleNames: string[];
35
+ _view: DataView;
36
+ _children?: CstNode[];
37
+ _base: number;
38
+ _input: string;
39
+ startIdx: number;
40
+ leadingSpaces: CstNode | undefined;
41
+ source: {
42
+ startIdx: number;
43
+ endIdx: number;
44
+ };
45
+ constructor(ruleNames: string[], dataView: DataView, ptr: number, input: string, startIdx: number);
46
+ get type(): number;
47
+ isNonterminal(): boolean;
48
+ isTerminal(): boolean;
49
+ isIter(): boolean;
50
+ isOptional(): boolean;
51
+ get ctorName(): string;
52
+ get ruleName(): string;
53
+ get count(): number;
54
+ get matchLength(): number;
55
+ get _typeAndDetails(): number;
56
+ get arity(): number;
57
+ get children(): CstNode[];
58
+ _computeChildren(): CstNode[];
59
+ get sourceString(): string;
60
+ isSyntactic(ruleName?: string): boolean;
61
+ isLexical(ruleName?: string): boolean;
62
+ toString(): string;
63
+ map<T>(callbackFn: (...args: CstNode[]) => T): T[];
64
+ }
65
+ export declare function dumpCstNode(node: CstNode, depth?: number): void;
66
+ export declare class MatchResult {
67
+ grammar: WasmGrammar;
68
+ input: string;
69
+ startExpr: string;
70
+ _cst: CstNode | null;
71
+ _rightmostFailurePosition: number;
72
+ _rightmostFailures: any;
73
+ shortMessage?: string;
74
+ message?: string;
75
+ constructor(matcher: WasmGrammar, input: string, startExpr: string, cst: CstNode | null, rightmostFailurePosition: number, optRecordedFailures?: any);
76
+ [Symbol.dispose](): void;
77
+ detach(): void;
78
+ succeeded(): boolean;
79
+ failed(): boolean;
80
+ getRightmostFailurePosition(): number;
81
+ getRightmostFailures(): any;
82
+ toString(): string;
83
+ getExpectedText(): string;
84
+ getInterval(): void;
85
+ use<T>(cb: (r: MatchResult) => T): T;
86
+ }
87
+ //# sourceMappingURL=miniohm.d.ts.map