@teasel/parser 0.0.0 → 0.0.2

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/README.md CHANGED
@@ -1,3 +1,139 @@
1
- # teasel
1
+ <picture>
2
+ <source media="(prefers-color-scheme: dark)" srcset="banner-dark.svg">
3
+ <img src="banner.svg" width="100%" alt="">
4
+ </picture>
2
5
 
3
- Placeholder release. The parser lives at https://github.com/Nic-Polumeyv/teasel.
6
+ <h1 align="center">teasel</h1>
7
+ <p align="center">A JavaScript and TypeScript parser in Rust. It answers in ESTree.</p>
8
+
9
+ <br>
10
+
11
+ ```js
12
+ import { Source } from '@teasel/parser';
13
+
14
+ const source = new Source(text, { typescript: true, scopes: true });
15
+ const { node } = source.parse();
16
+ ```
17
+
18
+ Every parse is `source.parse(entry, offset, { end, stopAt })`. Every answer is `{ node, end }` and what the options add. A source is disposable: `using source = new Source(text)` releases what the engine holds for it at the end of the block, and the collector does otherwise.
19
+
20
+ ```
21
+ source.parse() Program
22
+ source.parse('expression', 7) the expression that starts at 7
23
+ source.parse('pattern', 7) an assignment target: a name or a destructuring
24
+ source.parse('params', 7) the patterns of a (a, b = 1)
25
+ source.parse('statement', 7) one statement
26
+ source.parse('typeParameters', 7) a <T extends U>
27
+ source.parse('program', 12, { end: 40 }) the program inside 12..40, positions of the whole
28
+ ```
29
+
30
+ ## Inside a larger syntax
31
+
32
+ A host that embeds JavaScript in its own reads one piece at a time, from an offset, and gets back where its own syntax resumes.
33
+
34
+ ```
35
+ {{ items as item, index }}
36
+ ▲ ▲
37
+ 3 8
38
+ ```
39
+
40
+ ```js
41
+ const { node, end } = source.parse('expression', 3, { stopAt: ['as', ','] });
42
+ // node Identifier items
43
+ // end 8
44
+ ```
45
+
46
+ `stopAt` lists the host's own tokens. One read outside every bracket the parse opened, where the expression could end, ends the parse: `,` does not start a sequence, `/>` is not a division. A `then` after `.` is a property name. A TypeScript `as` is the host's unless another `as` follows the assertion, so `xs as T[] as item` ends after the type.
47
+
48
+ ## What the options add
49
+
50
+ | option | on the tree | on the answer |
51
+ | --- | --- | --- |
52
+ | `locations` | `loc` with line and column on every node | |
53
+ | `comments` | `leadingComments`, `trailingComments`, `innerComments` | `comments`, every comment read |
54
+ | `scopes` | | `scopes`, `bindings`, `references`, and the four questions below |
55
+ | `parenthesized` | `parenthesized: true` on a node the source wraps in parens | |
56
+ | `errorRecovery` | an `Identifier` named `''` of no width where something is missing | `errors`, instead of a throw |
57
+ | `typescript` | TypeScript nodes | |
58
+ | `decorators: 'legacy'` or `'proposal'` | restricts decorator syntax; unset reads both | |
59
+ | `typescript: 'erase'` | JavaScript, the types gone | `typescript`, what could not be erased: enums, namespaces with values, parameter properties, `export =`, `import =`, decorators, accessor fields |
60
+ | `sourceType: 'module'` | strict code, `import`, `export`, top-level `await` | |
61
+
62
+ A key is on the answer exactly when its option is on. `allowReturnOutsideFunction`, `allowAwaitOutsideFunction`, `allowSuperOutsideMethod` and `allowUndeclaredExports` loosen the early errors as their names say.
63
+
64
+ ## Scopes
65
+
66
+ The tree stays plain ESTree. The facts hang beside it, reached from a node.
67
+
68
+ ```js
69
+ import { Source, scopeOf, bindingOf, referenceOf, parentOf } from '@teasel/parser';
70
+
71
+ const { node } = new Source('let x = 1; function f(y) { x = y; }', { scopes: true }).parse();
72
+ const [declaration, fn] = node.body;
73
+ const assignment = fn.body.body[0].expression;
74
+
75
+ bindingOf(declaration.declarations[0].id) // { name: 'x', kind: 'let', scope, node, declaration }
76
+ referenceOf(assignment.left) // { scope, binding, write: true, read: false, mutate: false, node, writeExpr }
77
+ scopeOf(fn) // { kind: 'function', parent, node, topLevelAwait: false }
78
+ parentOf(assignment.left) // the assignment
79
+ ```
80
+
81
+ ```
82
+ Program ──────────────────── scope: module
83
+ ├─ let x = 1 x binding let
84
+ └─ function f(y) { scope: function
85
+ │ y binding param
86
+ └─ x = y x reference write y reference read
87
+ ```
88
+
89
+ A reference to a name no scope declares has `binding: null`. A copy of a node carries no facts.
90
+
91
+ ## Errors
92
+
93
+ ```js
94
+ try {
95
+ new Source('x = ;').parse();
96
+ } catch (e) {
97
+ e.code; // 'unexpected_token'
98
+ e.pos; // 4
99
+ e.end; // 5
100
+ e.loc; // { line: 1, column: 4 }
101
+ e.message; // 'Unexpected token'
102
+ }
103
+ ```
104
+
105
+ With `errorRecovery`, the parse comes back and the errors come with it.
106
+
107
+ ```
108
+ { f(a, }
109
+
110
+ errors [{ code: 'unexpected_token', pos: 7, end: 7, loc }]
111
+ node Identifier '' at 7..7
112
+ end 7
113
+ ```
114
+
115
+ ## Rust and the command line
116
+
117
+ ```rust
118
+ let (ast, roots, end) = teasel::parse_at(source, 0, None, Entry::Program, options, "")?;
119
+ ```
120
+
121
+ ```
122
+ teasel --typescript --scopes file.ts
123
+ ```
124
+
125
+ ## Build
126
+
127
+ ```
128
+ cargo build --release
129
+ cd package
130
+ bun run build # the Node addon
131
+ bun run build:wasm # the WebAssembly module
132
+ bun test.js
133
+ ```
134
+
135
+ Node resolves `@teasel/parser` to the addon and everything else to the WebAssembly module, with the same API.
136
+
137
+ <br>
138
+
139
+ <p align="center"><sub>Named after the plant whose dried heads were used to tease apart wool fibres and raise the nap on cloth.</sub></p>
package/api.js ADDED
@@ -0,0 +1,185 @@
1
+ import { decode, facts } from './decode.js';
2
+ import { isIdentifierStart, isIdentifierChar } from './identifier.js';
3
+
4
+ // acorn's option names, which `Request::set` of json.rs takes as they are
5
+ const OPTIONS = new Set(['sourceType', 'typescript', 'decorators', 'comments', 'scopes', 'locations', 'parenthesized', 'allowReturnOutsideFunction', 'allowAwaitOutsideFunction', 'allowSuperOutsideMethod', 'allowUndeclaredExports', 'errorRecovery']);
6
+
7
+ // the engine takes the options that are on as their names
8
+ export function names(options) {
9
+ if (options === undefined) return '';
10
+ const on = [];
11
+ for (const key in options) {
12
+ const value = options[key];
13
+ if (key === 'host') {
14
+ if (value !== undefined && typeof value !== 'string') throw new TypeError('host must be the grammar as a string');
15
+ continue;
16
+ }
17
+ if (!OPTIONS.has(key)) throw new TypeError(`${key} is not an option`);
18
+ if (value === undefined || value === false) continue;
19
+ if (key === 'decorators') {
20
+ if (value !== 'legacy' && value !== 'proposal') throw new TypeError(`decorators must be "legacy" or "proposal", not ${JSON.stringify(value)}`);
21
+ on.push(`${value}Decorators`);
22
+ } else if (key === 'sourceType') {
23
+ if (value !== 'script' && value !== 'module') throw new TypeError(`sourceType must be "script" or "module", not ${JSON.stringify(value)}`);
24
+ if (value === 'module') on.push('module');
25
+ } else if (value === true) on.push(key);
26
+ else if (key === 'typescript' && value === 'erase') on.push('typescript', 'erase');
27
+ else throw new TypeError(`${key} must be a boolean, not ${JSON.stringify(value)}`);
28
+ }
29
+ return on.join(' ');
30
+ }
31
+
32
+ // `Entry` of parser/mod.rs by index
33
+ export const ENTRY = { program: 0, expression: 1, pattern: 2, params: 3, statement: 4, typeParameters: 5 };
34
+
35
+ // the engine takes the stop tokens as one string
36
+ function stops(list) {
37
+ if (list === undefined) return '';
38
+ if (!Array.isArray(list) || !list.every((stop) => typeof stop === 'string' && stop !== '' && !/\s/.test(stop))) {
39
+ throw new TypeError('stopAt must be a list of words and punctuators');
40
+ }
41
+ return list.join(' ');
42
+ }
43
+
44
+ /**
45
+ * @typedef {ArrayBuffer | Uint32Array | string} Answer
46
+ * @typedef {object} Engine
47
+ * @property {(source: string, names: string, host: string) => any} create
48
+ * @property {(held: any, entry: number, offset: number, end: number | undefined, stop: string) => Answer} parse
49
+ * @property {(held: any) => void} [free]
50
+ * @property {() => string[]} constants
51
+ * @property {() => ArrayLike<number>} shapes
52
+ */
53
+
54
+ // words the engine has to judge: keywords, the strict-mode reserved words and the contextual ones
55
+ const KEYWORD = new Set('await break case catch class const continue debugger default delete do else enum export extends false finally for function if implements import in instanceof interface let new null package private protected public return static super switch this throw true try typeof var void while with yield'.split(' '));
56
+
57
+ /**
58
+ * The offset after an identifier the host's syntax follows directly, so the answer needs no
59
+ * engine: a name, then optional space, then an unmatched closer, the cut, or one of `stopAt`.
60
+ * Anything the grammar could continue with, a dot or an operator or a TypeScript `as`, and any
61
+ * word the engine has to judge, is left to it.
62
+ * @param {string} source @param {number} at @param {number} end @param {string[] | undefined} stopAt
63
+ * @returns {[number, number] | null} the identifier's end and where the parse ends
64
+ */
65
+ function bare(source, at, end, stopAt, typescript) {
66
+ let i = at;
67
+ const first = source.codePointAt(i);
68
+ if (first === undefined || !isIdentifierStart(first) || first === 0x5c) return null;
69
+ i += first > 0xffff ? 2 : 1;
70
+ while (i < end) {
71
+ const code = /** @type {number} */ (source.codePointAt(i));
72
+ if (code === 0x5c) return null;
73
+ if (!isIdentifierChar(code)) break;
74
+ i += code > 0xffff ? 2 : 1;
75
+ }
76
+ const name_end = i;
77
+ if (KEYWORD.has(source.slice(at, name_end))) return null;
78
+ while (i < end && /\s/.test(source[i])) i++;
79
+ if (i === end) return [name_end, name_end];
80
+ const c = source[i];
81
+ if (c === '}' || c === ')' || c === ']') return [name_end, name_end];
82
+ if (stopAt !== undefined) {
83
+ for (const stop of stopAt) {
84
+ if (!source.startsWith(stop, i)) continue;
85
+ const after = source.codePointAt(i + stop.length);
86
+ if (isIdentifierStart(/** @type {number} */ (stop.codePointAt(0))) && after !== undefined && isIdentifierChar(after)) continue;
87
+ // a stop TypeScript reads as its own is the engine's to judge
88
+ if (typescript && (stop === 'as' || stop === 'satisfies')) return null;
89
+ return [name_end, name_end];
90
+ }
91
+ }
92
+ return null;
93
+ }
94
+
95
+ /** @param {Engine} engine */
96
+ export function bind(engine) {
97
+ const registry = engine.free && typeof FinalizationRegistry !== 'undefined' ? new FinalizationRegistry(engine.free) : null;
98
+
99
+ function result(answer, source) {
100
+ if (typeof answer !== 'string') return decode(answer, source, engine);
101
+ const { message, ...error } = JSON.parse(answer).error;
102
+ throw Object.assign(new SyntaxError(message), error);
103
+ }
104
+
105
+ return class Source {
106
+ #held;
107
+ #source;
108
+ #options;
109
+ /** @type {number[] | undefined} */
110
+ #lines;
111
+
112
+ constructor(source, options) {
113
+ this.#held = engine.create(source, names(options), options?.host ?? '');
114
+ this.#source = source;
115
+ this.#options = options ?? {};
116
+ registry?.register(this, this.#held, this);
117
+ }
118
+
119
+ /**
120
+ * @param {keyof typeof ENTRY} [entry] what to read
121
+ * @param {number} [offset] where it starts
122
+ * @param {{ end?: number, stopAt?: string[] }} [at] where the source is cut, and the host's tokens that end the parse
123
+ */
124
+ parse(entry = 'program', offset = 0, { end, stopAt } = {}) {
125
+ if (this.#held === undefined) throw new TypeError('the source is freed');
126
+ const index = ENTRY[entry];
127
+ if (index === undefined) throw new TypeError(`${JSON.stringify(entry)} is not an entry`);
128
+ const stop = stops(stopAt);
129
+ if (this.#options.host !== undefined && index === ENTRY.program) return result(engine.parse(this.#held, index, 0, undefined, ''), this.#source);
130
+ if ((index === ENTRY.expression || index === ENTRY.pattern) && Number.isInteger(offset) && offset >= 0) {
131
+ const cut = end === undefined ? this.#source.length : end;
132
+ const found = Number.isInteger(cut) && cut <= this.#source.length && offset <= cut ? bare(this.#source, offset, cut, index === ENTRY.pattern ? [',', '(', ':', '='] : stopAt, !!this.#options.typescript) : null;
133
+ if (found !== null && (index === ENTRY.expression || !this.#source.startsWith(':', found[0]))) return this.#identifier(offset, found[0], index === ENTRY.pattern);
134
+ }
135
+ return result(engine.parse(this.#held, index, offset, end, stop), this.#source);
136
+ }
137
+
138
+ /** The answer the engine would give for a bare identifier, built here. */
139
+ #identifier(start, end, pattern) {
140
+ const o = this.#options;
141
+ /** @type {any} */
142
+ const node = { type: 'Identifier', start, end, name: this.#source.slice(start, end) };
143
+ if (o.locations) node.loc = { start: this.#position(start), end: this.#position(end) };
144
+ /** @type {any} */
145
+ const answer = { node, end };
146
+ if (o.comments) answer.comments = [];
147
+ if (o.errorRecovery) answer.errors = [];
148
+ if (o.typescript === 'erase') answer.typescript = [];
149
+ if (o.scopes) {
150
+ const scope = { kind: 'fragment', parent: null, topLevelAwait: false, node };
151
+ const binding = pattern ? { name: node.name, kind: 'pattern', scope, node, declaration: null } : null;
152
+ const reference = pattern ? null : { scope, binding: null, write: false, read: true, mutate: false, node, writeExpr: null };
153
+ answer.scopes = [scope];
154
+ answer.bindings = binding === null ? [] : [binding];
155
+ answer.references = reference === null ? [] : [reference];
156
+ facts(node, scope, binding, reference);
157
+ } else {
158
+ facts(node, undefined, undefined, undefined);
159
+ }
160
+ return answer;
161
+ }
162
+
163
+ /** Line and column of an offset, from a line table built on first use. */
164
+ #position(offset) {
165
+ if (this.#lines === undefined) {
166
+ this.#lines = [0];
167
+ for (let i = this.#source.indexOf('\n'); i !== -1; i = this.#source.indexOf('\n', i + 1)) this.#lines.push(i + 1);
168
+ }
169
+ let lo = 0, hi = this.#lines.length - 1;
170
+ while (lo < hi) {
171
+ const mid = (lo + hi + 1) >> 1;
172
+ if (this.#lines[mid] <= offset) lo = mid;
173
+ else hi = mid - 1;
174
+ }
175
+ return { line: lo + 1, column: offset - this.#lines[lo] };
176
+ }
177
+
178
+ [Symbol.dispose]() {
179
+ if (this.#held === undefined) return;
180
+ registry?.unregister(this);
181
+ engine.free?.(this.#held);
182
+ this.#held = undefined;
183
+ }
184
+ };
185
+ }
package/decode.js ADDED
@@ -0,0 +1,282 @@
1
+ // Turns the addon's shape-coded stream into ESTree objects: what `JSON.parse` did, without the
2
+ // text. The layout is `teasel::estree::Binary`, the kinds `teasel::estree::kind`.
3
+ const HEADER = 7;
4
+ // in a node's place
5
+ const NULL = 0;
6
+ const END = 1;
7
+
8
+ const little = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
9
+ // a leading U+FEFF is text, not a mark
10
+ const utf8 = new TextDecoder('utf-8', { ignoreBOM: true });
11
+
12
+ // symbol keys: ten times cheaper than a WeakMap entry, and skipped by JSON, Object.keys and for-in
13
+ const SCOPE = Symbol('scope');
14
+ const BINDING = Symbol('binding');
15
+ const REFERENCE = Symbol('reference');
16
+ const PARENT = Symbol('parent');
17
+
18
+
19
+ /** @param {import('estree').Node} node @returns {import('./index.js').Scope | undefined} the scope the node opens */
20
+ export const scopeOf = (node) => (node == null ? undefined : node[SCOPE]);
21
+ /** @param {import('estree').Node} node @returns {import('./index.js').Binding | null | undefined} what the identifier declares or refers to; null for a global, undefined when it names no value */
22
+ export const bindingOf = (node) => (node == null ? undefined : node[BINDING]);
23
+ /** @param {import('estree').Node} node @returns {import('./index.js').Reference | undefined} the reference an identifier makes, a global's included */
24
+ export const referenceOf = (node) => (node == null ? undefined : node[REFERENCE]);
25
+ /** @param {import('estree').Node} node @returns {import('estree').Node | undefined} the node it is a child of; undefined for the root of an answer */
26
+ export const parentOf = (node) => (node == null ? undefined : node[PARENT]);
27
+
28
+ const FACTS = new Set(['scope', 'declares', 'reference', 'defines', 'writes', 'root']);
29
+
30
+ /** Files a node built outside the stream as the decoder would: no parent, and its facts when it has them. */
31
+ export function facts(node, scope, binding, reference) {
32
+ node[PARENT] = undefined;
33
+ if (scope !== undefined) node[SCOPE] = scope;
34
+ if (node.type === 'Identifier' || binding !== undefined) node[BINDING] = binding === null ? null : binding;
35
+ if (node.type === 'Identifier' || reference !== undefined) node[REFERENCE] = reference === null ? undefined : reference;
36
+ }
37
+
38
+ /**
39
+ * One decode at a time; the builders are generated once and read through this.
40
+ * @type {{ w: Uint32Array, at: number, strings: string[], floats: Float64Array | null, source: string, constants: string[], scopes: any[], bindings: any[], build: (() => any)[] }}
41
+ */
42
+ const EMPTY = [];
43
+
44
+ function node(S) {
45
+ const id = S.w[S.at++];
46
+ return id === NULL ? null : S.build[id](S);
47
+ }
48
+
49
+ function nodes(S) {
50
+ const list = [];
51
+ for (;;) {
52
+ const id = S.w[S.at++];
53
+ if (id === END) return list;
54
+ list.push(id === NULL ? null : S.build[id](S));
55
+ }
56
+ }
57
+
58
+ function ints(S) {
59
+ const n = S.w[S.at++];
60
+ const list = new Array(n);
61
+ for (let i = 0; i < n; i++) list[i] = S.w[S.at++];
62
+ return list;
63
+ }
64
+
65
+ function strs(S) {
66
+ const n = S.w[S.at++];
67
+ const list = new Array(n);
68
+ for (let i = 0; i < n; i++) list[i] = S.strings[S.w[S.at++]];
69
+ return list;
70
+ }
71
+
72
+ /** @typedef {{ type: string | null, keys: string[], kinds: number[] }} Shape */
73
+
74
+ // one reader per kind, as source for the generated builders and as a function for the interpreter
75
+ const READ = ['node(S)', 'S.w[S.at++]', 'S.floats[S.w[S.at++]]', 'S.w[S.at++] === 1', 'S.constants[S.w[S.at++]]', 'S.strings[S.w[S.at++]]', 'S.source.slice(S.w[S.at++], S.w[S.at++])', '{ start: { line: S.w[S.at++], column: S.w[S.at++] }, end: { line: S.w[S.at++], column: S.w[S.at++] } }', 'nodes(S)', 'ints(S)', 'strs(S)'];
76
+ const READERS = [node, (S) => S.w[S.at++], (S) => /** @type {Float64Array} */ (S.floats)[S.w[S.at++]], (S) => S.w[S.at++] === 1, (S) => S.constants[S.w[S.at++]], (S) => S.strings[S.w[S.at++]], (S) => S.source.slice(S.w[S.at++], S.w[S.at++]), (S) => ({ start: { line: S.w[S.at++], column: S.w[S.at++] }, end: { line: S.w[S.at++], column: S.w[S.at++] } }), nodes, ints, strs];
77
+
78
+ /**
79
+ * One object literal per shape, its facts and its parent link as symbol slots of the literal:
80
+ * V8 allocates it in one hidden class with nothing added later. Facts, and everything the stream
81
+ * puts before the last of them, are read into locals first.
82
+ * @param {Shape} shape @param {boolean} link
83
+ */
84
+ function generate({ type, keys, kinds }, link) {
85
+ let last = -1;
86
+ if (link && type !== null) for (let i = 0; i < keys.length; i++) if (FACTS.has(keys[i]) || kinds[i] === 0 || kinds[i] === 8) last = i;
87
+ const lead = [];
88
+ const props = type === null ? [] : [`type: ${JSON.stringify(type)}`];
89
+ // what the node points at, set once it exists
90
+ const after = [];
91
+ let scope = null, binding = null, reference = null;
92
+ for (let i = 0; i < keys.length; i++) {
93
+ const key = keys[i];
94
+ if (i > last) props.push(`${JSON.stringify(key)}: ${READ[kinds[i]]}`);
95
+ else {
96
+ lead.push(`const v${i} = ${READ[kinds[i]]};`);
97
+ if (key === 'scope') { scope = `S.scopes[v${i}]`; lead.push(`const s = ${scope};`); after.push('s.node = n;'); }
98
+ else if (key === 'declares') { binding = 'd'; lead.push(`const d = S.bindings[v${i}];`); after.push('if (d.node === null) d.node = n;'); }
99
+ else if (key === 'reference') { reference = 'r'; binding = 'r.binding'; lead.push(`const r = S.references[v${i}];`); after.push('r.node = n;'); }
100
+ else if (key === 'defines') after.push(`for (let i = 0; i < v${i}.length; i++) S.bindings[v${i}[i]].declaration = n;`);
101
+ else if (key === 'writes') after.push(`for (let i = 0; i < v${i}.length; i++) S.references[v${i}[i]].writeExpr = n;`);
102
+ else if (key === 'root') after.push(`S.roots[v${i}].node = n;`);
103
+ else {
104
+ props.push(`${JSON.stringify(key)}: v${i}`);
105
+ // a child with a type is a node; a literal's regex or a template element's value is not
106
+ if (link && kinds[i] === 0) after.push(`if (v${i} !== null && v${i}.type !== undefined) v${i}[PARENT] = n;`);
107
+ else if (link && kinds[i] === 8) after.push(`for (let i = 0; i < v${i}.length; i++) if (v${i}[i] !== null) v${i}[i][PARENT] = n;`);
108
+ }
109
+ }
110
+ }
111
+ if (link && type !== null) {
112
+ props.push('[PARENT]: undefined');
113
+ if (scope !== null) props.push('[SCOPE]: s');
114
+ // every identifier has the two slots, so those with facts and those without share a class
115
+ if (type === 'Identifier' || binding !== null) props.push(`[BINDING]: ${binding ?? 'undefined'}`);
116
+ if (type === 'Identifier' || reference !== null) props.push(`[REFERENCE]: ${reference ?? 'undefined'}`);
117
+ }
118
+ const body = `${lead.join(' ')} const n = { ${props.join(', ')} }; ${after.join(' ')} return n;`;
119
+ return new Function('node', 'nodes', 'ints', 'strs', 'PARENT', 'SCOPE', 'BINDING', 'REFERENCE', `return (S) => { ${body} };`)(node, nodes, ints, strs, PARENT, SCOPE, BINDING, REFERENCE);
120
+ }
121
+
122
+ /** The same without code generation, for a host whose policy forbids it. @param {Shape} shape @param {boolean} link */
123
+ function interpret({ type, keys, kinds }, link) {
124
+ const linked = link && type !== null;
125
+ return (S) => {
126
+ const n = type === null ? {} : linked ? { type, [PARENT]: undefined, [SCOPE]: undefined, [BINDING]: undefined, [REFERENCE]: undefined } : { type };
127
+ for (let i = 0; i < keys.length; i++) {
128
+ const key = keys[i];
129
+ const value = READERS[kinds[i]](S);
130
+ if (linked && kinds[i] === 0 && value !== null && value.type !== undefined) value[PARENT] = n;
131
+ else if (linked && kinds[i] === 8) for (const child of value) if (child !== null) child[PARENT] = n;
132
+ if (!linked || !FACTS.has(key)) n[key] = value;
133
+ else if (key === 'scope') { const s = S.scopes[value]; n[SCOPE] = s; s.node = n; }
134
+ else if (key === 'declares') { const d = S.bindings[value]; n[BINDING] = d; if (d.node === null) d.node = n; }
135
+ else if (key === 'reference') { const r = S.references[value]; n[REFERENCE] = r; n[BINDING] = r.binding; r.node = n; }
136
+ else if (key === 'defines') for (const b of value) S.bindings[b].declaration = n;
137
+ else if (key === 'root') S.roots[value].node = n;
138
+ else for (const w of value) S.references[w].writeExpr = n;
139
+ }
140
+ return n;
141
+ };
142
+ }
143
+
144
+ const compile = (() => {
145
+ try {
146
+ new Function('');
147
+ return generate;
148
+ } catch {
149
+ return interpret;
150
+ }
151
+ })();
152
+
153
+ /**
154
+ * @typedef {{ constants: () => string[], shapes: () => ArrayLike<number> }} Tables the engine's numbering
155
+ * @type {WeakMap<Tables, { constants: string[], shapes: (Shape | null)[], linked: (() => any)[], plain: (() => any)[] }>}
156
+ */
157
+ const tables = new WeakMap();
158
+
159
+ /** @param {Tables} engine @param {number} known constants @param {number} known_shapes */
160
+ function table_of(engine, known, known_shapes) {
161
+ let table = tables.get(engine);
162
+ if (table === undefined) tables.set(engine, (table = { constants: [], shapes: [null, null], linked: [], plain: [] }));
163
+ if (known > table.constants.length) table.constants = engine.constants();
164
+ if (known_shapes > table.shapes.length) {
165
+ const { constants, shapes } = table;
166
+ const flat = engine.shapes();
167
+ let at = 0;
168
+ for (let id = 2; at < flat.length; id++) {
169
+ const n = flat[at++];
170
+ if (id === shapes.length) {
171
+ const keys = [], kinds = [];
172
+ for (let i = 1; i < n; i++) {
173
+ keys.push(constants[flat[at + i] >>> 4]);
174
+ kinds.push(flat[at + i] & 15);
175
+ }
176
+ shapes.push({ type: flat[at] === 0 ? null : constants[flat[at] - 1], keys, kinds });
177
+ }
178
+ at += n;
179
+ }
180
+ }
181
+ return table;
182
+ }
183
+
184
+ /** @param {ReturnType<typeof table_of>} table @param {boolean} link */
185
+ function builders(table, link) {
186
+ const list = link ? table.linked : table.plain;
187
+ if (list.length === 0) list.push(null, null);
188
+ while (list.length < table.shapes.length) list.push(compile(/** @type {Shape} */ (table.shapes[list.length]), link));
189
+ return list;
190
+ }
191
+
192
+ function unaligned_floats(buffer, start, count) {
193
+ const view = new DataView(buffer, start, count * 8);
194
+ const floats = new Float64Array(count);
195
+ for (let i = 0; i < count; i++) floats[i] = view.getFloat64(i * 8, little);
196
+ return floats;
197
+ }
198
+
199
+ /** @param {any[]} scopes @param {any[]} bindings @param {any[]} references */
200
+ function link_tables(scopes, bindings, references) {
201
+ for (const scope of scopes) {
202
+ scope.parent = scope.parent === null ? null : scopes[scope.parent];
203
+ scope.node = null;
204
+ }
205
+ for (const binding of bindings) {
206
+ binding.scope = scopes[binding.scope];
207
+ binding.node = null;
208
+ binding.declaration = null;
209
+ }
210
+ for (const reference of references) {
211
+ reference.scope = scopes[reference.scope];
212
+ reference.binding = reference.binding === null ? null : bindings[reference.binding];
213
+ reference.node = null;
214
+ reference.writeExpr = null;
215
+ }
216
+ }
217
+
218
+ /** @param {any[]} roots @param {any[]} scopes @param {any[]} bindings @param {any[]} references */
219
+ function link_roots(roots, scopes, bindings, references) {
220
+ for (const root of roots) {
221
+ root.node = null;
222
+ root.scope = scopes[root.scope];
223
+ root.scopes = scopes.slice(root.scopes[0], root.scopes[1]);
224
+ root.bindings = bindings.slice(root.bindings[0], root.bindings[1]);
225
+ root.references = references.slice(root.references[0], root.references[1]);
226
+ }
227
+ }
228
+
229
+ /**
230
+ * @param {ArrayBuffer | Uint32Array} answer the words, or a view of them inside a larger buffer
231
+ * @param {string} source
232
+ * @param {Tables} engine
233
+ * @param {boolean} [link] replace the scope and binding numbers with the objects they index
234
+ */
235
+ export function decode(answer, source, engine, link = true) {
236
+ const words = answer instanceof Uint32Array ? answer : new Uint32Array(answer);
237
+ const { buffer, byteOffset } = words;
238
+ // read by index: destructuring a typed array goes through its iterator, a tenth of a small decode
239
+ const tree = words[0], ends_count = words[1], floats_count = words[2], bytes = words[3], known = words[4], known_shapes = words[5], tables_at = words[6];
240
+ const table = table_of(engine, known, known_shapes);
241
+ const text_at = HEADER + tree + ends_count;
242
+ const text = bytes ? utf8.decode(new Uint8Array(buffer, byteOffset + text_at * 4, bytes)) : '';
243
+ let floats_at = text_at + ((bytes + 3) >> 2);
244
+ if (floats_at % 2 === 1) floats_at++;
245
+ const floats_start = byteOffset + floats_at * 4;
246
+ const floats = !floats_count ? null : floats_start % 8 === 0 ? new Float64Array(buffer, floats_start, floats_count) : unaligned_floats(buffer, floats_start, floats_count);
247
+ const strings = new Array(ends_count);
248
+ let from = 0;
249
+ for (let i = 0; i < ends_count; i++) {
250
+ const end = words[HEADER + tree + i];
251
+ strings[i] = text.slice(from, end);
252
+ from = end;
253
+ }
254
+ // one state object per decode, young like everything it points at: no write barriers
255
+ const S = { w: words, at: HEADER, strings, floats, source, constants: table.constants, scopes: EMPTY, bindings: EMPTY, references: EMPTY, roots: EMPTY, build: builders(table, link) };
256
+ let scopes = null, bindings = null, references = null, roots = null;
257
+ if (tables_at !== 0) {
258
+ // the writer's `all_scopes` order; the roots table is there when a host document has pieces of JavaScript
259
+ S.at = HEADER + tables_at;
260
+ scopes = nodes(S);
261
+ bindings = nodes(S);
262
+ references = nodes(S);
263
+ if (S.at < HEADER + tree) roots = nodes(S);
264
+ if (link) {
265
+ link_tables(scopes, bindings, references);
266
+ if (roots !== null) link_roots(roots, scopes, bindings, references);
267
+ }
268
+ S.scopes = scopes;
269
+ S.bindings = bindings;
270
+ S.references = references;
271
+ if (roots !== null) S.roots = roots;
272
+ S.at = HEADER;
273
+ }
274
+ const root = node(S);
275
+ if (scopes !== null) {
276
+ root.scopes = scopes;
277
+ root.bindings = bindings;
278
+ root.references = references;
279
+ if (roots !== null) root.roots = roots;
280
+ }
281
+ return root;
282
+ }
package/identifier.js ADDED
@@ -0,0 +1,218 @@
1
+ // Generated by scripts/unicode.js from Unicode 17.0.0. Do not edit.
2
+ // The parser's own identifier tables, so a host tokenizing around embedded JavaScript agrees with
3
+ // it whatever Unicode its engine has. Each table is a flat list of inclusive ranges.
4
+ const ID_START = [
5
+ 0xaa, 0xaa, 0xb5, 0xb5, 0xba, 0xba, 0xc0, 0xd6, 0xd8, 0xf6, 0xf8, 0x2c1, 0x2c6, 0x2d1, 0x2e0, 0x2e4,
6
+ 0x2ec, 0x2ec, 0x2ee, 0x2ee, 0x370, 0x374, 0x376, 0x377, 0x37a, 0x37d, 0x37f, 0x37f, 0x386, 0x386, 0x388, 0x38a,
7
+ 0x38c, 0x38c, 0x38e, 0x3a1, 0x3a3, 0x3f5, 0x3f7, 0x481, 0x48a, 0x52f, 0x531, 0x556, 0x559, 0x559, 0x560, 0x588,
8
+ 0x5d0, 0x5ea, 0x5ef, 0x5f2, 0x620, 0x64a, 0x66e, 0x66f, 0x671, 0x6d3, 0x6d5, 0x6d5, 0x6e5, 0x6e6, 0x6ee, 0x6ef,
9
+ 0x6fa, 0x6fc, 0x6ff, 0x6ff, 0x710, 0x710, 0x712, 0x72f, 0x74d, 0x7a5, 0x7b1, 0x7b1, 0x7ca, 0x7ea, 0x7f4, 0x7f5,
10
+ 0x7fa, 0x7fa, 0x800, 0x815, 0x81a, 0x81a, 0x824, 0x824, 0x828, 0x828, 0x840, 0x858, 0x860, 0x86a, 0x870, 0x887,
11
+ 0x889, 0x88f, 0x8a0, 0x8c9, 0x904, 0x939, 0x93d, 0x93d, 0x950, 0x950, 0x958, 0x961, 0x971, 0x980, 0x985, 0x98c,
12
+ 0x98f, 0x990, 0x993, 0x9a8, 0x9aa, 0x9b0, 0x9b2, 0x9b2, 0x9b6, 0x9b9, 0x9bd, 0x9bd, 0x9ce, 0x9ce, 0x9dc, 0x9dd,
13
+ 0x9df, 0x9e1, 0x9f0, 0x9f1, 0x9fc, 0x9fc, 0xa05, 0xa0a, 0xa0f, 0xa10, 0xa13, 0xa28, 0xa2a, 0xa30, 0xa32, 0xa33,
14
+ 0xa35, 0xa36, 0xa38, 0xa39, 0xa59, 0xa5c, 0xa5e, 0xa5e, 0xa72, 0xa74, 0xa85, 0xa8d, 0xa8f, 0xa91, 0xa93, 0xaa8,
15
+ 0xaaa, 0xab0, 0xab2, 0xab3, 0xab5, 0xab9, 0xabd, 0xabd, 0xad0, 0xad0, 0xae0, 0xae1, 0xaf9, 0xaf9, 0xb05, 0xb0c,
16
+ 0xb0f, 0xb10, 0xb13, 0xb28, 0xb2a, 0xb30, 0xb32, 0xb33, 0xb35, 0xb39, 0xb3d, 0xb3d, 0xb5c, 0xb5d, 0xb5f, 0xb61,
17
+ 0xb71, 0xb71, 0xb83, 0xb83, 0xb85, 0xb8a, 0xb8e, 0xb90, 0xb92, 0xb95, 0xb99, 0xb9a, 0xb9c, 0xb9c, 0xb9e, 0xb9f,
18
+ 0xba3, 0xba4, 0xba8, 0xbaa, 0xbae, 0xbb9, 0xbd0, 0xbd0, 0xc05, 0xc0c, 0xc0e, 0xc10, 0xc12, 0xc28, 0xc2a, 0xc39,
19
+ 0xc3d, 0xc3d, 0xc58, 0xc5a, 0xc5c, 0xc5d, 0xc60, 0xc61, 0xc80, 0xc80, 0xc85, 0xc8c, 0xc8e, 0xc90, 0xc92, 0xca8,
20
+ 0xcaa, 0xcb3, 0xcb5, 0xcb9, 0xcbd, 0xcbd, 0xcdc, 0xcde, 0xce0, 0xce1, 0xcf1, 0xcf2, 0xd04, 0xd0c, 0xd0e, 0xd10,
21
+ 0xd12, 0xd3a, 0xd3d, 0xd3d, 0xd4e, 0xd4e, 0xd54, 0xd56, 0xd5f, 0xd61, 0xd7a, 0xd7f, 0xd85, 0xd96, 0xd9a, 0xdb1,
22
+ 0xdb3, 0xdbb, 0xdbd, 0xdbd, 0xdc0, 0xdc6, 0xe01, 0xe30, 0xe32, 0xe33, 0xe40, 0xe46, 0xe81, 0xe82, 0xe84, 0xe84,
23
+ 0xe86, 0xe8a, 0xe8c, 0xea3, 0xea5, 0xea5, 0xea7, 0xeb0, 0xeb2, 0xeb3, 0xebd, 0xebd, 0xec0, 0xec4, 0xec6, 0xec6,
24
+ 0xedc, 0xedf, 0xf00, 0xf00, 0xf40, 0xf47, 0xf49, 0xf6c, 0xf88, 0xf8c, 0x1000, 0x102a, 0x103f, 0x103f, 0x1050, 0x1055,
25
+ 0x105a, 0x105d, 0x1061, 0x1061, 0x1065, 0x1066, 0x106e, 0x1070, 0x1075, 0x1081, 0x108e, 0x108e, 0x10a0, 0x10c5, 0x10c7, 0x10c7,
26
+ 0x10cd, 0x10cd, 0x10d0, 0x10fa, 0x10fc, 0x1248, 0x124a, 0x124d, 0x1250, 0x1256, 0x1258, 0x1258, 0x125a, 0x125d, 0x1260, 0x1288,
27
+ 0x128a, 0x128d, 0x1290, 0x12b0, 0x12b2, 0x12b5, 0x12b8, 0x12be, 0x12c0, 0x12c0, 0x12c2, 0x12c5, 0x12c8, 0x12d6, 0x12d8, 0x1310,
28
+ 0x1312, 0x1315, 0x1318, 0x135a, 0x1380, 0x138f, 0x13a0, 0x13f5, 0x13f8, 0x13fd, 0x1401, 0x166c, 0x166f, 0x167f, 0x1681, 0x169a,
29
+ 0x16a0, 0x16ea, 0x16ee, 0x16f8, 0x1700, 0x1711, 0x171f, 0x1731, 0x1740, 0x1751, 0x1760, 0x176c, 0x176e, 0x1770, 0x1780, 0x17b3,
30
+ 0x17d7, 0x17d7, 0x17dc, 0x17dc, 0x1820, 0x1878, 0x1880, 0x18a8, 0x18aa, 0x18aa, 0x18b0, 0x18f5, 0x1900, 0x191e, 0x1950, 0x196d,
31
+ 0x1970, 0x1974, 0x1980, 0x19ab, 0x19b0, 0x19c9, 0x1a00, 0x1a16, 0x1a20, 0x1a54, 0x1aa7, 0x1aa7, 0x1b05, 0x1b33, 0x1b45, 0x1b4c,
32
+ 0x1b83, 0x1ba0, 0x1bae, 0x1baf, 0x1bba, 0x1be5, 0x1c00, 0x1c23, 0x1c4d, 0x1c4f, 0x1c5a, 0x1c7d, 0x1c80, 0x1c8a, 0x1c90, 0x1cba,
33
+ 0x1cbd, 0x1cbf, 0x1ce9, 0x1cec, 0x1cee, 0x1cf3, 0x1cf5, 0x1cf6, 0x1cfa, 0x1cfa, 0x1d00, 0x1dbf, 0x1e00, 0x1f15, 0x1f18, 0x1f1d,
34
+ 0x1f20, 0x1f45, 0x1f48, 0x1f4d, 0x1f50, 0x1f57, 0x1f59, 0x1f59, 0x1f5b, 0x1f5b, 0x1f5d, 0x1f5d, 0x1f5f, 0x1f7d, 0x1f80, 0x1fb4,
35
+ 0x1fb6, 0x1fbc, 0x1fbe, 0x1fbe, 0x1fc2, 0x1fc4, 0x1fc6, 0x1fcc, 0x1fd0, 0x1fd3, 0x1fd6, 0x1fdb, 0x1fe0, 0x1fec, 0x1ff2, 0x1ff4,
36
+ 0x1ff6, 0x1ffc, 0x2071, 0x2071, 0x207f, 0x207f, 0x2090, 0x209c, 0x2102, 0x2102, 0x2107, 0x2107, 0x210a, 0x2113, 0x2115, 0x2115,
37
+ 0x2118, 0x211d, 0x2124, 0x2124, 0x2126, 0x2126, 0x2128, 0x2128, 0x212a, 0x2139, 0x213c, 0x213f, 0x2145, 0x2149, 0x214e, 0x214e,
38
+ 0x2160, 0x2188, 0x2c00, 0x2ce4, 0x2ceb, 0x2cee, 0x2cf2, 0x2cf3, 0x2d00, 0x2d25, 0x2d27, 0x2d27, 0x2d2d, 0x2d2d, 0x2d30, 0x2d67,
39
+ 0x2d6f, 0x2d6f, 0x2d80, 0x2d96, 0x2da0, 0x2da6, 0x2da8, 0x2dae, 0x2db0, 0x2db6, 0x2db8, 0x2dbe, 0x2dc0, 0x2dc6, 0x2dc8, 0x2dce,
40
+ 0x2dd0, 0x2dd6, 0x2dd8, 0x2dde, 0x3005, 0x3007, 0x3021, 0x3029, 0x3031, 0x3035, 0x3038, 0x303c, 0x3041, 0x3096, 0x309b, 0x309f,
41
+ 0x30a1, 0x30fa, 0x30fc, 0x30ff, 0x3105, 0x312f, 0x3131, 0x318e, 0x31a0, 0x31bf, 0x31f0, 0x31ff, 0x3400, 0x4dbf, 0x4e00, 0xa48c,
42
+ 0xa4d0, 0xa4fd, 0xa500, 0xa60c, 0xa610, 0xa61f, 0xa62a, 0xa62b, 0xa640, 0xa66e, 0xa67f, 0xa69d, 0xa6a0, 0xa6ef, 0xa717, 0xa71f,
43
+ 0xa722, 0xa788, 0xa78b, 0xa7dc, 0xa7f1, 0xa801, 0xa803, 0xa805, 0xa807, 0xa80a, 0xa80c, 0xa822, 0xa840, 0xa873, 0xa882, 0xa8b3,
44
+ 0xa8f2, 0xa8f7, 0xa8fb, 0xa8fb, 0xa8fd, 0xa8fe, 0xa90a, 0xa925, 0xa930, 0xa946, 0xa960, 0xa97c, 0xa984, 0xa9b2, 0xa9cf, 0xa9cf,
45
+ 0xa9e0, 0xa9e4, 0xa9e6, 0xa9ef, 0xa9fa, 0xa9fe, 0xaa00, 0xaa28, 0xaa40, 0xaa42, 0xaa44, 0xaa4b, 0xaa60, 0xaa76, 0xaa7a, 0xaa7a,
46
+ 0xaa7e, 0xaaaf, 0xaab1, 0xaab1, 0xaab5, 0xaab6, 0xaab9, 0xaabd, 0xaac0, 0xaac0, 0xaac2, 0xaac2, 0xaadb, 0xaadd, 0xaae0, 0xaaea,
47
+ 0xaaf2, 0xaaf4, 0xab01, 0xab06, 0xab09, 0xab0e, 0xab11, 0xab16, 0xab20, 0xab26, 0xab28, 0xab2e, 0xab30, 0xab5a, 0xab5c, 0xab69,
48
+ 0xab70, 0xabe2, 0xac00, 0xd7a3, 0xd7b0, 0xd7c6, 0xd7cb, 0xd7fb, 0xf900, 0xfa6d, 0xfa70, 0xfad9, 0xfb00, 0xfb06, 0xfb13, 0xfb17,
49
+ 0xfb1d, 0xfb1d, 0xfb1f, 0xfb28, 0xfb2a, 0xfb36, 0xfb38, 0xfb3c, 0xfb3e, 0xfb3e, 0xfb40, 0xfb41, 0xfb43, 0xfb44, 0xfb46, 0xfbb1,
50
+ 0xfbd3, 0xfd3d, 0xfd50, 0xfd8f, 0xfd92, 0xfdc7, 0xfdf0, 0xfdfb, 0xfe70, 0xfe74, 0xfe76, 0xfefc, 0xff21, 0xff3a, 0xff41, 0xff5a,
51
+ 0xff66, 0xffbe, 0xffc2, 0xffc7, 0xffca, 0xffcf, 0xffd2, 0xffd7, 0xffda, 0xffdc, 0x10000, 0x1000b, 0x1000d, 0x10026, 0x10028, 0x1003a,
52
+ 0x1003c, 0x1003d, 0x1003f, 0x1004d, 0x10050, 0x1005d, 0x10080, 0x100fa, 0x10140, 0x10174, 0x10280, 0x1029c, 0x102a0, 0x102d0, 0x10300, 0x1031f,
53
+ 0x1032d, 0x1034a, 0x10350, 0x10375, 0x10380, 0x1039d, 0x103a0, 0x103c3, 0x103c8, 0x103cf, 0x103d1, 0x103d5, 0x10400, 0x1049d, 0x104b0, 0x104d3,
54
+ 0x104d8, 0x104fb, 0x10500, 0x10527, 0x10530, 0x10563, 0x10570, 0x1057a, 0x1057c, 0x1058a, 0x1058c, 0x10592, 0x10594, 0x10595, 0x10597, 0x105a1,
55
+ 0x105a3, 0x105b1, 0x105b3, 0x105b9, 0x105bb, 0x105bc, 0x105c0, 0x105f3, 0x10600, 0x10736, 0x10740, 0x10755, 0x10760, 0x10767, 0x10780, 0x10785,
56
+ 0x10787, 0x107b0, 0x107b2, 0x107ba, 0x10800, 0x10805, 0x10808, 0x10808, 0x1080a, 0x10835, 0x10837, 0x10838, 0x1083c, 0x1083c, 0x1083f, 0x10855,
57
+ 0x10860, 0x10876, 0x10880, 0x1089e, 0x108e0, 0x108f2, 0x108f4, 0x108f5, 0x10900, 0x10915, 0x10920, 0x10939, 0x10940, 0x10959, 0x10980, 0x109b7,
58
+ 0x109be, 0x109bf, 0x10a00, 0x10a00, 0x10a10, 0x10a13, 0x10a15, 0x10a17, 0x10a19, 0x10a35, 0x10a60, 0x10a7c, 0x10a80, 0x10a9c, 0x10ac0, 0x10ac7,
59
+ 0x10ac9, 0x10ae4, 0x10b00, 0x10b35, 0x10b40, 0x10b55, 0x10b60, 0x10b72, 0x10b80, 0x10b91, 0x10c00, 0x10c48, 0x10c80, 0x10cb2, 0x10cc0, 0x10cf2,
60
+ 0x10d00, 0x10d23, 0x10d4a, 0x10d65, 0x10d6f, 0x10d85, 0x10e80, 0x10ea9, 0x10eb0, 0x10eb1, 0x10ec2, 0x10ec7, 0x10f00, 0x10f1c, 0x10f27, 0x10f27,
61
+ 0x10f30, 0x10f45, 0x10f70, 0x10f81, 0x10fb0, 0x10fc4, 0x10fe0, 0x10ff6, 0x11003, 0x11037, 0x11071, 0x11072, 0x11075, 0x11075, 0x11083, 0x110af,
62
+ 0x110d0, 0x110e8, 0x11103, 0x11126, 0x11144, 0x11144, 0x11147, 0x11147, 0x11150, 0x11172, 0x11176, 0x11176, 0x11183, 0x111b2, 0x111c1, 0x111c4,
63
+ 0x111da, 0x111da, 0x111dc, 0x111dc, 0x11200, 0x11211, 0x11213, 0x1122b, 0x1123f, 0x11240, 0x11280, 0x11286, 0x11288, 0x11288, 0x1128a, 0x1128d,
64
+ 0x1128f, 0x1129d, 0x1129f, 0x112a8, 0x112b0, 0x112de, 0x11305, 0x1130c, 0x1130f, 0x11310, 0x11313, 0x11328, 0x1132a, 0x11330, 0x11332, 0x11333,
65
+ 0x11335, 0x11339, 0x1133d, 0x1133d, 0x11350, 0x11350, 0x1135d, 0x11361, 0x11380, 0x11389, 0x1138b, 0x1138b, 0x1138e, 0x1138e, 0x11390, 0x113b5,
66
+ 0x113b7, 0x113b7, 0x113d1, 0x113d1, 0x113d3, 0x113d3, 0x11400, 0x11434, 0x11447, 0x1144a, 0x1145f, 0x11461, 0x11480, 0x114af, 0x114c4, 0x114c5,
67
+ 0x114c7, 0x114c7, 0x11580, 0x115ae, 0x115d8, 0x115db, 0x11600, 0x1162f, 0x11644, 0x11644, 0x11680, 0x116aa, 0x116b8, 0x116b8, 0x11700, 0x1171a,
68
+ 0x11740, 0x11746, 0x11800, 0x1182b, 0x118a0, 0x118df, 0x118ff, 0x11906, 0x11909, 0x11909, 0x1190c, 0x11913, 0x11915, 0x11916, 0x11918, 0x1192f,
69
+ 0x1193f, 0x1193f, 0x11941, 0x11941, 0x119a0, 0x119a7, 0x119aa, 0x119d0, 0x119e1, 0x119e1, 0x119e3, 0x119e3, 0x11a00, 0x11a00, 0x11a0b, 0x11a32,
70
+ 0x11a3a, 0x11a3a, 0x11a50, 0x11a50, 0x11a5c, 0x11a89, 0x11a9d, 0x11a9d, 0x11ab0, 0x11af8, 0x11bc0, 0x11be0, 0x11c00, 0x11c08, 0x11c0a, 0x11c2e,
71
+ 0x11c40, 0x11c40, 0x11c72, 0x11c8f, 0x11d00, 0x11d06, 0x11d08, 0x11d09, 0x11d0b, 0x11d30, 0x11d46, 0x11d46, 0x11d60, 0x11d65, 0x11d67, 0x11d68,
72
+ 0x11d6a, 0x11d89, 0x11d98, 0x11d98, 0x11db0, 0x11ddb, 0x11ee0, 0x11ef2, 0x11f02, 0x11f02, 0x11f04, 0x11f10, 0x11f12, 0x11f33, 0x11fb0, 0x11fb0,
73
+ 0x12000, 0x12399, 0x12400, 0x1246e, 0x12480, 0x12543, 0x12f90, 0x12ff0, 0x13000, 0x1342f, 0x13441, 0x13446, 0x13460, 0x143fa, 0x14400, 0x14646,
74
+ 0x16100, 0x1611d, 0x16800, 0x16a38, 0x16a40, 0x16a5e, 0x16a70, 0x16abe, 0x16ad0, 0x16aed, 0x16b00, 0x16b2f, 0x16b40, 0x16b43, 0x16b63, 0x16b77,
75
+ 0x16b7d, 0x16b8f, 0x16d40, 0x16d6c, 0x16e40, 0x16e7f, 0x16ea0, 0x16eb8, 0x16ebb, 0x16ed3, 0x16f00, 0x16f4a, 0x16f50, 0x16f50, 0x16f93, 0x16f9f,
76
+ 0x16fe0, 0x16fe1, 0x16fe3, 0x16fe3, 0x16ff2, 0x16ff6, 0x17000, 0x18cd5, 0x18cff, 0x18d1e, 0x18d80, 0x18df2, 0x1aff0, 0x1aff3, 0x1aff5, 0x1affb,
77
+ 0x1affd, 0x1affe, 0x1b000, 0x1b122, 0x1b132, 0x1b132, 0x1b150, 0x1b152, 0x1b155, 0x1b155, 0x1b164, 0x1b167, 0x1b170, 0x1b2fb, 0x1bc00, 0x1bc6a,
78
+ 0x1bc70, 0x1bc7c, 0x1bc80, 0x1bc88, 0x1bc90, 0x1bc99, 0x1d400, 0x1d454, 0x1d456, 0x1d49c, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a2, 0x1d4a5, 0x1d4a6,
79
+ 0x1d4a9, 0x1d4ac, 0x1d4ae, 0x1d4b9, 0x1d4bb, 0x1d4bb, 0x1d4bd, 0x1d4c3, 0x1d4c5, 0x1d505, 0x1d507, 0x1d50a, 0x1d50d, 0x1d514, 0x1d516, 0x1d51c,
80
+ 0x1d51e, 0x1d539, 0x1d53b, 0x1d53e, 0x1d540, 0x1d544, 0x1d546, 0x1d546, 0x1d54a, 0x1d550, 0x1d552, 0x1d6a5, 0x1d6a8, 0x1d6c0, 0x1d6c2, 0x1d6da,
81
+ 0x1d6dc, 0x1d6fa, 0x1d6fc, 0x1d714, 0x1d716, 0x1d734, 0x1d736, 0x1d74e, 0x1d750, 0x1d76e, 0x1d770, 0x1d788, 0x1d78a, 0x1d7a8, 0x1d7aa, 0x1d7c2,
82
+ 0x1d7c4, 0x1d7cb, 0x1df00, 0x1df1e, 0x1df25, 0x1df2a, 0x1e030, 0x1e06d, 0x1e100, 0x1e12c, 0x1e137, 0x1e13d, 0x1e14e, 0x1e14e, 0x1e290, 0x1e2ad,
83
+ 0x1e2c0, 0x1e2eb, 0x1e4d0, 0x1e4eb, 0x1e5d0, 0x1e5ed, 0x1e5f0, 0x1e5f0, 0x1e6c0, 0x1e6de, 0x1e6e0, 0x1e6e2, 0x1e6e4, 0x1e6e5, 0x1e6e7, 0x1e6ed,
84
+ 0x1e6f0, 0x1e6f4, 0x1e6fe, 0x1e6ff, 0x1e7e0, 0x1e7e6, 0x1e7e8, 0x1e7eb, 0x1e7ed, 0x1e7ee, 0x1e7f0, 0x1e7fe, 0x1e800, 0x1e8c4, 0x1e900, 0x1e943,
85
+ 0x1e94b, 0x1e94b, 0x1ee00, 0x1ee03, 0x1ee05, 0x1ee1f, 0x1ee21, 0x1ee22, 0x1ee24, 0x1ee24, 0x1ee27, 0x1ee27, 0x1ee29, 0x1ee32, 0x1ee34, 0x1ee37,
86
+ 0x1ee39, 0x1ee39, 0x1ee3b, 0x1ee3b, 0x1ee42, 0x1ee42, 0x1ee47, 0x1ee47, 0x1ee49, 0x1ee49, 0x1ee4b, 0x1ee4b, 0x1ee4d, 0x1ee4f, 0x1ee51, 0x1ee52,
87
+ 0x1ee54, 0x1ee54, 0x1ee57, 0x1ee57, 0x1ee59, 0x1ee59, 0x1ee5b, 0x1ee5b, 0x1ee5d, 0x1ee5d, 0x1ee5f, 0x1ee5f, 0x1ee61, 0x1ee62, 0x1ee64, 0x1ee64,
88
+ 0x1ee67, 0x1ee6a, 0x1ee6c, 0x1ee72, 0x1ee74, 0x1ee77, 0x1ee79, 0x1ee7c, 0x1ee7e, 0x1ee7e, 0x1ee80, 0x1ee89, 0x1ee8b, 0x1ee9b, 0x1eea1, 0x1eea3,
89
+ 0x1eea5, 0x1eea9, 0x1eeab, 0x1eebb, 0x20000, 0x2a6df, 0x2a700, 0x2b81d, 0x2b820, 0x2cead, 0x2ceb0, 0x2ebe0, 0x2ebf0, 0x2ee5d, 0x2f800, 0x2fa1d,
90
+ 0x30000, 0x3134a, 0x31350, 0x33479,
91
+ ];
92
+ const ID_CONTINUE = [
93
+ 0xaa, 0xaa, 0xb5, 0xb5, 0xb7, 0xb7, 0xba, 0xba, 0xc0, 0xd6, 0xd8, 0xf6, 0xf8, 0x2c1, 0x2c6, 0x2d1,
94
+ 0x2e0, 0x2e4, 0x2ec, 0x2ec, 0x2ee, 0x2ee, 0x300, 0x374, 0x376, 0x377, 0x37a, 0x37d, 0x37f, 0x37f, 0x386, 0x38a,
95
+ 0x38c, 0x38c, 0x38e, 0x3a1, 0x3a3, 0x3f5, 0x3f7, 0x481, 0x483, 0x487, 0x48a, 0x52f, 0x531, 0x556, 0x559, 0x559,
96
+ 0x560, 0x588, 0x591, 0x5bd, 0x5bf, 0x5bf, 0x5c1, 0x5c2, 0x5c4, 0x5c5, 0x5c7, 0x5c7, 0x5d0, 0x5ea, 0x5ef, 0x5f2,
97
+ 0x610, 0x61a, 0x620, 0x669, 0x66e, 0x6d3, 0x6d5, 0x6dc, 0x6df, 0x6e8, 0x6ea, 0x6fc, 0x6ff, 0x6ff, 0x710, 0x74a,
98
+ 0x74d, 0x7b1, 0x7c0, 0x7f5, 0x7fa, 0x7fa, 0x7fd, 0x7fd, 0x800, 0x82d, 0x840, 0x85b, 0x860, 0x86a, 0x870, 0x887,
99
+ 0x889, 0x88f, 0x897, 0x8e1, 0x8e3, 0x963, 0x966, 0x96f, 0x971, 0x983, 0x985, 0x98c, 0x98f, 0x990, 0x993, 0x9a8,
100
+ 0x9aa, 0x9b0, 0x9b2, 0x9b2, 0x9b6, 0x9b9, 0x9bc, 0x9c4, 0x9c7, 0x9c8, 0x9cb, 0x9ce, 0x9d7, 0x9d7, 0x9dc, 0x9dd,
101
+ 0x9df, 0x9e3, 0x9e6, 0x9f1, 0x9fc, 0x9fc, 0x9fe, 0x9fe, 0xa01, 0xa03, 0xa05, 0xa0a, 0xa0f, 0xa10, 0xa13, 0xa28,
102
+ 0xa2a, 0xa30, 0xa32, 0xa33, 0xa35, 0xa36, 0xa38, 0xa39, 0xa3c, 0xa3c, 0xa3e, 0xa42, 0xa47, 0xa48, 0xa4b, 0xa4d,
103
+ 0xa51, 0xa51, 0xa59, 0xa5c, 0xa5e, 0xa5e, 0xa66, 0xa75, 0xa81, 0xa83, 0xa85, 0xa8d, 0xa8f, 0xa91, 0xa93, 0xaa8,
104
+ 0xaaa, 0xab0, 0xab2, 0xab3, 0xab5, 0xab9, 0xabc, 0xac5, 0xac7, 0xac9, 0xacb, 0xacd, 0xad0, 0xad0, 0xae0, 0xae3,
105
+ 0xae6, 0xaef, 0xaf9, 0xaff, 0xb01, 0xb03, 0xb05, 0xb0c, 0xb0f, 0xb10, 0xb13, 0xb28, 0xb2a, 0xb30, 0xb32, 0xb33,
106
+ 0xb35, 0xb39, 0xb3c, 0xb44, 0xb47, 0xb48, 0xb4b, 0xb4d, 0xb55, 0xb57, 0xb5c, 0xb5d, 0xb5f, 0xb63, 0xb66, 0xb6f,
107
+ 0xb71, 0xb71, 0xb82, 0xb83, 0xb85, 0xb8a, 0xb8e, 0xb90, 0xb92, 0xb95, 0xb99, 0xb9a, 0xb9c, 0xb9c, 0xb9e, 0xb9f,
108
+ 0xba3, 0xba4, 0xba8, 0xbaa, 0xbae, 0xbb9, 0xbbe, 0xbc2, 0xbc6, 0xbc8, 0xbca, 0xbcd, 0xbd0, 0xbd0, 0xbd7, 0xbd7,
109
+ 0xbe6, 0xbef, 0xc00, 0xc0c, 0xc0e, 0xc10, 0xc12, 0xc28, 0xc2a, 0xc39, 0xc3c, 0xc44, 0xc46, 0xc48, 0xc4a, 0xc4d,
110
+ 0xc55, 0xc56, 0xc58, 0xc5a, 0xc5c, 0xc5d, 0xc60, 0xc63, 0xc66, 0xc6f, 0xc80, 0xc83, 0xc85, 0xc8c, 0xc8e, 0xc90,
111
+ 0xc92, 0xca8, 0xcaa, 0xcb3, 0xcb5, 0xcb9, 0xcbc, 0xcc4, 0xcc6, 0xcc8, 0xcca, 0xccd, 0xcd5, 0xcd6, 0xcdc, 0xcde,
112
+ 0xce0, 0xce3, 0xce6, 0xcef, 0xcf1, 0xcf3, 0xd00, 0xd0c, 0xd0e, 0xd10, 0xd12, 0xd44, 0xd46, 0xd48, 0xd4a, 0xd4e,
113
+ 0xd54, 0xd57, 0xd5f, 0xd63, 0xd66, 0xd6f, 0xd7a, 0xd7f, 0xd81, 0xd83, 0xd85, 0xd96, 0xd9a, 0xdb1, 0xdb3, 0xdbb,
114
+ 0xdbd, 0xdbd, 0xdc0, 0xdc6, 0xdca, 0xdca, 0xdcf, 0xdd4, 0xdd6, 0xdd6, 0xdd8, 0xddf, 0xde6, 0xdef, 0xdf2, 0xdf3,
115
+ 0xe01, 0xe3a, 0xe40, 0xe4e, 0xe50, 0xe59, 0xe81, 0xe82, 0xe84, 0xe84, 0xe86, 0xe8a, 0xe8c, 0xea3, 0xea5, 0xea5,
116
+ 0xea7, 0xebd, 0xec0, 0xec4, 0xec6, 0xec6, 0xec8, 0xece, 0xed0, 0xed9, 0xedc, 0xedf, 0xf00, 0xf00, 0xf18, 0xf19,
117
+ 0xf20, 0xf29, 0xf35, 0xf35, 0xf37, 0xf37, 0xf39, 0xf39, 0xf3e, 0xf47, 0xf49, 0xf6c, 0xf71, 0xf84, 0xf86, 0xf97,
118
+ 0xf99, 0xfbc, 0xfc6, 0xfc6, 0x1000, 0x1049, 0x1050, 0x109d, 0x10a0, 0x10c5, 0x10c7, 0x10c7, 0x10cd, 0x10cd, 0x10d0, 0x10fa,
119
+ 0x10fc, 0x1248, 0x124a, 0x124d, 0x1250, 0x1256, 0x1258, 0x1258, 0x125a, 0x125d, 0x1260, 0x1288, 0x128a, 0x128d, 0x1290, 0x12b0,
120
+ 0x12b2, 0x12b5, 0x12b8, 0x12be, 0x12c0, 0x12c0, 0x12c2, 0x12c5, 0x12c8, 0x12d6, 0x12d8, 0x1310, 0x1312, 0x1315, 0x1318, 0x135a,
121
+ 0x135d, 0x135f, 0x1369, 0x1371, 0x1380, 0x138f, 0x13a0, 0x13f5, 0x13f8, 0x13fd, 0x1401, 0x166c, 0x166f, 0x167f, 0x1681, 0x169a,
122
+ 0x16a0, 0x16ea, 0x16ee, 0x16f8, 0x1700, 0x1715, 0x171f, 0x1734, 0x1740, 0x1753, 0x1760, 0x176c, 0x176e, 0x1770, 0x1772, 0x1773,
123
+ 0x1780, 0x17d3, 0x17d7, 0x17d7, 0x17dc, 0x17dd, 0x17e0, 0x17e9, 0x180b, 0x180d, 0x180f, 0x1819, 0x1820, 0x1878, 0x1880, 0x18aa,
124
+ 0x18b0, 0x18f5, 0x1900, 0x191e, 0x1920, 0x192b, 0x1930, 0x193b, 0x1946, 0x196d, 0x1970, 0x1974, 0x1980, 0x19ab, 0x19b0, 0x19c9,
125
+ 0x19d0, 0x19da, 0x1a00, 0x1a1b, 0x1a20, 0x1a5e, 0x1a60, 0x1a7c, 0x1a7f, 0x1a89, 0x1a90, 0x1a99, 0x1aa7, 0x1aa7, 0x1ab0, 0x1abd,
126
+ 0x1abf, 0x1add, 0x1ae0, 0x1aeb, 0x1b00, 0x1b4c, 0x1b50, 0x1b59, 0x1b6b, 0x1b73, 0x1b80, 0x1bf3, 0x1c00, 0x1c37, 0x1c40, 0x1c49,
127
+ 0x1c4d, 0x1c7d, 0x1c80, 0x1c8a, 0x1c90, 0x1cba, 0x1cbd, 0x1cbf, 0x1cd0, 0x1cd2, 0x1cd4, 0x1cfa, 0x1d00, 0x1f15, 0x1f18, 0x1f1d,
128
+ 0x1f20, 0x1f45, 0x1f48, 0x1f4d, 0x1f50, 0x1f57, 0x1f59, 0x1f59, 0x1f5b, 0x1f5b, 0x1f5d, 0x1f5d, 0x1f5f, 0x1f7d, 0x1f80, 0x1fb4,
129
+ 0x1fb6, 0x1fbc, 0x1fbe, 0x1fbe, 0x1fc2, 0x1fc4, 0x1fc6, 0x1fcc, 0x1fd0, 0x1fd3, 0x1fd6, 0x1fdb, 0x1fe0, 0x1fec, 0x1ff2, 0x1ff4,
130
+ 0x1ff6, 0x1ffc, 0x200c, 0x200d, 0x203f, 0x2040, 0x2054, 0x2054, 0x2071, 0x2071, 0x207f, 0x207f, 0x2090, 0x209c, 0x20d0, 0x20dc,
131
+ 0x20e1, 0x20e1, 0x20e5, 0x20f0, 0x2102, 0x2102, 0x2107, 0x2107, 0x210a, 0x2113, 0x2115, 0x2115, 0x2118, 0x211d, 0x2124, 0x2124,
132
+ 0x2126, 0x2126, 0x2128, 0x2128, 0x212a, 0x2139, 0x213c, 0x213f, 0x2145, 0x2149, 0x214e, 0x214e, 0x2160, 0x2188, 0x2c00, 0x2ce4,
133
+ 0x2ceb, 0x2cf3, 0x2d00, 0x2d25, 0x2d27, 0x2d27, 0x2d2d, 0x2d2d, 0x2d30, 0x2d67, 0x2d6f, 0x2d6f, 0x2d7f, 0x2d96, 0x2da0, 0x2da6,
134
+ 0x2da8, 0x2dae, 0x2db0, 0x2db6, 0x2db8, 0x2dbe, 0x2dc0, 0x2dc6, 0x2dc8, 0x2dce, 0x2dd0, 0x2dd6, 0x2dd8, 0x2dde, 0x2de0, 0x2dff,
135
+ 0x3005, 0x3007, 0x3021, 0x302f, 0x3031, 0x3035, 0x3038, 0x303c, 0x3041, 0x3096, 0x3099, 0x309f, 0x30a1, 0x30ff, 0x3105, 0x312f,
136
+ 0x3131, 0x318e, 0x31a0, 0x31bf, 0x31f0, 0x31ff, 0x3400, 0x4dbf, 0x4e00, 0xa48c, 0xa4d0, 0xa4fd, 0xa500, 0xa60c, 0xa610, 0xa62b,
137
+ 0xa640, 0xa66f, 0xa674, 0xa67d, 0xa67f, 0xa6f1, 0xa717, 0xa71f, 0xa722, 0xa788, 0xa78b, 0xa7dc, 0xa7f1, 0xa827, 0xa82c, 0xa82c,
138
+ 0xa840, 0xa873, 0xa880, 0xa8c5, 0xa8d0, 0xa8d9, 0xa8e0, 0xa8f7, 0xa8fb, 0xa8fb, 0xa8fd, 0xa92d, 0xa930, 0xa953, 0xa960, 0xa97c,
139
+ 0xa980, 0xa9c0, 0xa9cf, 0xa9d9, 0xa9e0, 0xa9fe, 0xaa00, 0xaa36, 0xaa40, 0xaa4d, 0xaa50, 0xaa59, 0xaa60, 0xaa76, 0xaa7a, 0xaac2,
140
+ 0xaadb, 0xaadd, 0xaae0, 0xaaef, 0xaaf2, 0xaaf6, 0xab01, 0xab06, 0xab09, 0xab0e, 0xab11, 0xab16, 0xab20, 0xab26, 0xab28, 0xab2e,
141
+ 0xab30, 0xab5a, 0xab5c, 0xab69, 0xab70, 0xabea, 0xabec, 0xabed, 0xabf0, 0xabf9, 0xac00, 0xd7a3, 0xd7b0, 0xd7c6, 0xd7cb, 0xd7fb,
142
+ 0xf900, 0xfa6d, 0xfa70, 0xfad9, 0xfb00, 0xfb06, 0xfb13, 0xfb17, 0xfb1d, 0xfb28, 0xfb2a, 0xfb36, 0xfb38, 0xfb3c, 0xfb3e, 0xfb3e,
143
+ 0xfb40, 0xfb41, 0xfb43, 0xfb44, 0xfb46, 0xfbb1, 0xfbd3, 0xfd3d, 0xfd50, 0xfd8f, 0xfd92, 0xfdc7, 0xfdf0, 0xfdfb, 0xfe00, 0xfe0f,
144
+ 0xfe20, 0xfe2f, 0xfe33, 0xfe34, 0xfe4d, 0xfe4f, 0xfe70, 0xfe74, 0xfe76, 0xfefc, 0xff10, 0xff19, 0xff21, 0xff3a, 0xff3f, 0xff3f,
145
+ 0xff41, 0xff5a, 0xff65, 0xffbe, 0xffc2, 0xffc7, 0xffca, 0xffcf, 0xffd2, 0xffd7, 0xffda, 0xffdc, 0x10000, 0x1000b, 0x1000d, 0x10026,
146
+ 0x10028, 0x1003a, 0x1003c, 0x1003d, 0x1003f, 0x1004d, 0x10050, 0x1005d, 0x10080, 0x100fa, 0x10140, 0x10174, 0x101fd, 0x101fd, 0x10280, 0x1029c,
147
+ 0x102a0, 0x102d0, 0x102e0, 0x102e0, 0x10300, 0x1031f, 0x1032d, 0x1034a, 0x10350, 0x1037a, 0x10380, 0x1039d, 0x103a0, 0x103c3, 0x103c8, 0x103cf,
148
+ 0x103d1, 0x103d5, 0x10400, 0x1049d, 0x104a0, 0x104a9, 0x104b0, 0x104d3, 0x104d8, 0x104fb, 0x10500, 0x10527, 0x10530, 0x10563, 0x10570, 0x1057a,
149
+ 0x1057c, 0x1058a, 0x1058c, 0x10592, 0x10594, 0x10595, 0x10597, 0x105a1, 0x105a3, 0x105b1, 0x105b3, 0x105b9, 0x105bb, 0x105bc, 0x105c0, 0x105f3,
150
+ 0x10600, 0x10736, 0x10740, 0x10755, 0x10760, 0x10767, 0x10780, 0x10785, 0x10787, 0x107b0, 0x107b2, 0x107ba, 0x10800, 0x10805, 0x10808, 0x10808,
151
+ 0x1080a, 0x10835, 0x10837, 0x10838, 0x1083c, 0x1083c, 0x1083f, 0x10855, 0x10860, 0x10876, 0x10880, 0x1089e, 0x108e0, 0x108f2, 0x108f4, 0x108f5,
152
+ 0x10900, 0x10915, 0x10920, 0x10939, 0x10940, 0x10959, 0x10980, 0x109b7, 0x109be, 0x109bf, 0x10a00, 0x10a03, 0x10a05, 0x10a06, 0x10a0c, 0x10a13,
153
+ 0x10a15, 0x10a17, 0x10a19, 0x10a35, 0x10a38, 0x10a3a, 0x10a3f, 0x10a3f, 0x10a60, 0x10a7c, 0x10a80, 0x10a9c, 0x10ac0, 0x10ac7, 0x10ac9, 0x10ae6,
154
+ 0x10b00, 0x10b35, 0x10b40, 0x10b55, 0x10b60, 0x10b72, 0x10b80, 0x10b91, 0x10c00, 0x10c48, 0x10c80, 0x10cb2, 0x10cc0, 0x10cf2, 0x10d00, 0x10d27,
155
+ 0x10d30, 0x10d39, 0x10d40, 0x10d65, 0x10d69, 0x10d6d, 0x10d6f, 0x10d85, 0x10e80, 0x10ea9, 0x10eab, 0x10eac, 0x10eb0, 0x10eb1, 0x10ec2, 0x10ec7,
156
+ 0x10efa, 0x10f1c, 0x10f27, 0x10f27, 0x10f30, 0x10f50, 0x10f70, 0x10f85, 0x10fb0, 0x10fc4, 0x10fe0, 0x10ff6, 0x11000, 0x11046, 0x11066, 0x11075,
157
+ 0x1107f, 0x110ba, 0x110c2, 0x110c2, 0x110d0, 0x110e8, 0x110f0, 0x110f9, 0x11100, 0x11134, 0x11136, 0x1113f, 0x11144, 0x11147, 0x11150, 0x11173,
158
+ 0x11176, 0x11176, 0x11180, 0x111c4, 0x111c9, 0x111cc, 0x111ce, 0x111da, 0x111dc, 0x111dc, 0x11200, 0x11211, 0x11213, 0x11237, 0x1123e, 0x11241,
159
+ 0x11280, 0x11286, 0x11288, 0x11288, 0x1128a, 0x1128d, 0x1128f, 0x1129d, 0x1129f, 0x112a8, 0x112b0, 0x112ea, 0x112f0, 0x112f9, 0x11300, 0x11303,
160
+ 0x11305, 0x1130c, 0x1130f, 0x11310, 0x11313, 0x11328, 0x1132a, 0x11330, 0x11332, 0x11333, 0x11335, 0x11339, 0x1133b, 0x11344, 0x11347, 0x11348,
161
+ 0x1134b, 0x1134d, 0x11350, 0x11350, 0x11357, 0x11357, 0x1135d, 0x11363, 0x11366, 0x1136c, 0x11370, 0x11374, 0x11380, 0x11389, 0x1138b, 0x1138b,
162
+ 0x1138e, 0x1138e, 0x11390, 0x113b5, 0x113b7, 0x113c0, 0x113c2, 0x113c2, 0x113c5, 0x113c5, 0x113c7, 0x113ca, 0x113cc, 0x113d3, 0x113e1, 0x113e2,
163
+ 0x11400, 0x1144a, 0x11450, 0x11459, 0x1145e, 0x11461, 0x11480, 0x114c5, 0x114c7, 0x114c7, 0x114d0, 0x114d9, 0x11580, 0x115b5, 0x115b8, 0x115c0,
164
+ 0x115d8, 0x115dd, 0x11600, 0x11640, 0x11644, 0x11644, 0x11650, 0x11659, 0x11680, 0x116b8, 0x116c0, 0x116c9, 0x116d0, 0x116e3, 0x11700, 0x1171a,
165
+ 0x1171d, 0x1172b, 0x11730, 0x11739, 0x11740, 0x11746, 0x11800, 0x1183a, 0x118a0, 0x118e9, 0x118ff, 0x11906, 0x11909, 0x11909, 0x1190c, 0x11913,
166
+ 0x11915, 0x11916, 0x11918, 0x11935, 0x11937, 0x11938, 0x1193b, 0x11943, 0x11950, 0x11959, 0x119a0, 0x119a7, 0x119aa, 0x119d7, 0x119da, 0x119e1,
167
+ 0x119e3, 0x119e4, 0x11a00, 0x11a3e, 0x11a47, 0x11a47, 0x11a50, 0x11a99, 0x11a9d, 0x11a9d, 0x11ab0, 0x11af8, 0x11b60, 0x11b67, 0x11bc0, 0x11be0,
168
+ 0x11bf0, 0x11bf9, 0x11c00, 0x11c08, 0x11c0a, 0x11c36, 0x11c38, 0x11c40, 0x11c50, 0x11c59, 0x11c72, 0x11c8f, 0x11c92, 0x11ca7, 0x11ca9, 0x11cb6,
169
+ 0x11d00, 0x11d06, 0x11d08, 0x11d09, 0x11d0b, 0x11d36, 0x11d3a, 0x11d3a, 0x11d3c, 0x11d3d, 0x11d3f, 0x11d47, 0x11d50, 0x11d59, 0x11d60, 0x11d65,
170
+ 0x11d67, 0x11d68, 0x11d6a, 0x11d8e, 0x11d90, 0x11d91, 0x11d93, 0x11d98, 0x11da0, 0x11da9, 0x11db0, 0x11ddb, 0x11de0, 0x11de9, 0x11ee0, 0x11ef6,
171
+ 0x11f00, 0x11f10, 0x11f12, 0x11f3a, 0x11f3e, 0x11f42, 0x11f50, 0x11f5a, 0x11fb0, 0x11fb0, 0x12000, 0x12399, 0x12400, 0x1246e, 0x12480, 0x12543,
172
+ 0x12f90, 0x12ff0, 0x13000, 0x1342f, 0x13440, 0x13455, 0x13460, 0x143fa, 0x14400, 0x14646, 0x16100, 0x16139, 0x16800, 0x16a38, 0x16a40, 0x16a5e,
173
+ 0x16a60, 0x16a69, 0x16a70, 0x16abe, 0x16ac0, 0x16ac9, 0x16ad0, 0x16aed, 0x16af0, 0x16af4, 0x16b00, 0x16b36, 0x16b40, 0x16b43, 0x16b50, 0x16b59,
174
+ 0x16b63, 0x16b77, 0x16b7d, 0x16b8f, 0x16d40, 0x16d6c, 0x16d70, 0x16d79, 0x16e40, 0x16e7f, 0x16ea0, 0x16eb8, 0x16ebb, 0x16ed3, 0x16f00, 0x16f4a,
175
+ 0x16f4f, 0x16f87, 0x16f8f, 0x16f9f, 0x16fe0, 0x16fe1, 0x16fe3, 0x16fe4, 0x16ff0, 0x16ff6, 0x17000, 0x18cd5, 0x18cff, 0x18d1e, 0x18d80, 0x18df2,
176
+ 0x1aff0, 0x1aff3, 0x1aff5, 0x1affb, 0x1affd, 0x1affe, 0x1b000, 0x1b122, 0x1b132, 0x1b132, 0x1b150, 0x1b152, 0x1b155, 0x1b155, 0x1b164, 0x1b167,
177
+ 0x1b170, 0x1b2fb, 0x1bc00, 0x1bc6a, 0x1bc70, 0x1bc7c, 0x1bc80, 0x1bc88, 0x1bc90, 0x1bc99, 0x1bc9d, 0x1bc9e, 0x1ccf0, 0x1ccf9, 0x1cf00, 0x1cf2d,
178
+ 0x1cf30, 0x1cf46, 0x1d165, 0x1d169, 0x1d16d, 0x1d172, 0x1d17b, 0x1d182, 0x1d185, 0x1d18b, 0x1d1aa, 0x1d1ad, 0x1d242, 0x1d244, 0x1d400, 0x1d454,
179
+ 0x1d456, 0x1d49c, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a2, 0x1d4a5, 0x1d4a6, 0x1d4a9, 0x1d4ac, 0x1d4ae, 0x1d4b9, 0x1d4bb, 0x1d4bb, 0x1d4bd, 0x1d4c3,
180
+ 0x1d4c5, 0x1d505, 0x1d507, 0x1d50a, 0x1d50d, 0x1d514, 0x1d516, 0x1d51c, 0x1d51e, 0x1d539, 0x1d53b, 0x1d53e, 0x1d540, 0x1d544, 0x1d546, 0x1d546,
181
+ 0x1d54a, 0x1d550, 0x1d552, 0x1d6a5, 0x1d6a8, 0x1d6c0, 0x1d6c2, 0x1d6da, 0x1d6dc, 0x1d6fa, 0x1d6fc, 0x1d714, 0x1d716, 0x1d734, 0x1d736, 0x1d74e,
182
+ 0x1d750, 0x1d76e, 0x1d770, 0x1d788, 0x1d78a, 0x1d7a8, 0x1d7aa, 0x1d7c2, 0x1d7c4, 0x1d7cb, 0x1d7ce, 0x1d7ff, 0x1da00, 0x1da36, 0x1da3b, 0x1da6c,
183
+ 0x1da75, 0x1da75, 0x1da84, 0x1da84, 0x1da9b, 0x1da9f, 0x1daa1, 0x1daaf, 0x1df00, 0x1df1e, 0x1df25, 0x1df2a, 0x1e000, 0x1e006, 0x1e008, 0x1e018,
184
+ 0x1e01b, 0x1e021, 0x1e023, 0x1e024, 0x1e026, 0x1e02a, 0x1e030, 0x1e06d, 0x1e08f, 0x1e08f, 0x1e100, 0x1e12c, 0x1e130, 0x1e13d, 0x1e140, 0x1e149,
185
+ 0x1e14e, 0x1e14e, 0x1e290, 0x1e2ae, 0x1e2c0, 0x1e2f9, 0x1e4d0, 0x1e4f9, 0x1e5d0, 0x1e5fa, 0x1e6c0, 0x1e6de, 0x1e6e0, 0x1e6f5, 0x1e6fe, 0x1e6ff,
186
+ 0x1e7e0, 0x1e7e6, 0x1e7e8, 0x1e7eb, 0x1e7ed, 0x1e7ee, 0x1e7f0, 0x1e7fe, 0x1e800, 0x1e8c4, 0x1e8d0, 0x1e8d6, 0x1e900, 0x1e94b, 0x1e950, 0x1e959,
187
+ 0x1ee00, 0x1ee03, 0x1ee05, 0x1ee1f, 0x1ee21, 0x1ee22, 0x1ee24, 0x1ee24, 0x1ee27, 0x1ee27, 0x1ee29, 0x1ee32, 0x1ee34, 0x1ee37, 0x1ee39, 0x1ee39,
188
+ 0x1ee3b, 0x1ee3b, 0x1ee42, 0x1ee42, 0x1ee47, 0x1ee47, 0x1ee49, 0x1ee49, 0x1ee4b, 0x1ee4b, 0x1ee4d, 0x1ee4f, 0x1ee51, 0x1ee52, 0x1ee54, 0x1ee54,
189
+ 0x1ee57, 0x1ee57, 0x1ee59, 0x1ee59, 0x1ee5b, 0x1ee5b, 0x1ee5d, 0x1ee5d, 0x1ee5f, 0x1ee5f, 0x1ee61, 0x1ee62, 0x1ee64, 0x1ee64, 0x1ee67, 0x1ee6a,
190
+ 0x1ee6c, 0x1ee72, 0x1ee74, 0x1ee77, 0x1ee79, 0x1ee7c, 0x1ee7e, 0x1ee7e, 0x1ee80, 0x1ee89, 0x1ee8b, 0x1ee9b, 0x1eea1, 0x1eea3, 0x1eea5, 0x1eea9,
191
+ 0x1eeab, 0x1eebb, 0x1fbf0, 0x1fbf9, 0x20000, 0x2a6df, 0x2a700, 0x2b81d, 0x2b820, 0x2cead, 0x2ceb0, 0x2ebe0, 0x2ebf0, 0x2ee5d, 0x2f800, 0x2fa1d,
192
+ 0x30000, 0x3134a, 0x31350, 0x33479, 0xe0100, 0xe01ef,
193
+ ];
194
+
195
+ /** @param {number[]} table @param {number} code */
196
+ function lookup(table, code) {
197
+ let lo = 0;
198
+ let hi = table.length >> 1;
199
+ while (lo < hi) {
200
+ const mid = (lo + hi) >> 1;
201
+ if (code < table[mid * 2]) hi = mid;
202
+ else if (code > table[mid * 2 + 1]) lo = mid + 1;
203
+ else return true;
204
+ }
205
+ return false;
206
+ }
207
+
208
+ /** Whether a code point can start an identifier. @param {number} code */
209
+ export function isIdentifierStart(code) {
210
+ if (code < 128) return (code >= 65 && code <= 90) || (code >= 97 && code <= 122) || code === 36 || code === 95;
211
+ return lookup(ID_START, code);
212
+ }
213
+
214
+ /** Whether a code point can continue an identifier. @param {number} code */
215
+ export function isIdentifierChar(code) {
216
+ if (code < 128) return (code >= 65 && code <= 90) || (code >= 97 && code <= 122) || (code >= 48 && code <= 57) || code === 36 || code === 95;
217
+ return lookup(ID_CONTINUE, code);
218
+ }
package/index.d.ts ADDED
@@ -0,0 +1,256 @@
1
+ import type { Expression, Identifier, Node, Pattern, Program, SourceLocation, Statement } from 'estree';
2
+
3
+ declare global {
4
+ interface SymbolConstructor {
5
+ readonly dispose: unique symbol;
6
+ }
7
+ }
8
+
9
+ export interface Options {
10
+ /**
11
+ * The grammar of a host language the whole source is a document of: a template language
12
+ * with JavaScript inside it. The program entry then answers with the document's root, the
13
+ * host's own nodes around the JavaScript ones, in one tree; the other entries read
14
+ * JavaScript at an offset as before. TypeScript turns on by what the grammar says of a
15
+ * script tag.
16
+ */
17
+ host?: string;
18
+ /** `script` by default, as in acorn. */
19
+ sourceType?: 'script' | 'module';
20
+ /**
21
+ * Parse TypeScript. `'erase'` parses it and emits JavaScript: annotations, type-only
22
+ * declarations and imports go, assertions give way to their expression, and what erasure
23
+ * cannot express (enums, namespaces with values, parameter properties, `export =`, `import =`)
24
+ * stays in the tree and is listed as `typescript` on the answer, as are the proposals
25
+ * JavaScript itself has: decorators and accessor fields (`AccessorProperty`).
26
+ */
27
+ typescript?: boolean | 'erase';
28
+ /**
29
+ * Which decorators are read. 'legacy' refuses decorators on private elements, class
30
+ * expressions and their members; 'proposal' refuses parameter decorators and decorators
31
+ * on abstract or declared fields. Unset reads both syntaxes.
32
+ */
33
+ decorators?: 'legacy' | 'proposal';
34
+ /** Attach `leadingComments`, `trailingComments` and `innerComments` to nodes, and list every comment read as `comments` on the answer. */
35
+ comments?: boolean;
36
+ /**
37
+ * Scope analysis: the answer lists `scopes`, `bindings` and `references`, and `scopeOf`,
38
+ * `bindingOf` and `referenceOf` answer for a node. The tree itself carries nothing, and a copy
39
+ * of a node carries no facts. TypeScript type positions bind nothing.
40
+ */
41
+ scopes?: boolean;
42
+ /** Add `loc` with line and column to every node, as in acorn; off by default. */
43
+ locations?: boolean;
44
+ /** Mark a node the source wraps in parens with `parenthesized: true`, absent otherwise. */
45
+ parenthesized?: boolean;
46
+ allowReturnOutsideFunction?: boolean;
47
+ allowAwaitOutsideFunction?: boolean;
48
+ allowSuperOutsideMethod?: boolean;
49
+ allowUndeclaredExports?: boolean;
50
+ /**
51
+ * List syntax errors on the answer as `errors` instead of throwing the first: a missing
52
+ * operand, name or pattern is an `Identifier` named `''` of no width where it was expected,
53
+ * and a statement or entry that cannot be read is skipped to the next stop token or
54
+ * unmatched closing bracket, an empty identifier standing for it. Placeholders are neither
55
+ * bindings nor references.
56
+ */
57
+ errorRecovery?: boolean;
58
+ }
59
+
60
+ /**
61
+ * Thrown for a syntax error. `code` names what went wrong, for a host to branch on, and
62
+ * `message` says it in words, without a position. An error at the token being read spans it
63
+ * with `pos` and `end`; one reported elsewhere, at a declaration seen earlier say, has `end`
64
+ * equal to `pos`. `unexpected_eof` is the end of what was parsed: the `end` the parse was given,
65
+ * else the end of the source. A bad offset from the host is an `invalid_request` without a `loc`.
66
+ */
67
+ export interface ParseError extends SyntaxError {
68
+ code: string;
69
+ pos: number;
70
+ end: number;
71
+ loc?: { line: number; column: number };
72
+ }
73
+
74
+ /** A scope, as one of `scopes` on the answer. */
75
+ export interface Scope {
76
+ kind:
77
+ | 'module'
78
+ | 'script'
79
+ | 'function'
80
+ | 'function-name'
81
+ | 'class'
82
+ | 'block'
83
+ | 'catch'
84
+ | 'for'
85
+ | 'switch'
86
+ | 'static-block'
87
+ | 'with'
88
+ | 'namespace'
89
+ | 'enum'
90
+ | 'fragment';
91
+ /** The node that opens it; null for a function-name scope and for the scope around a parameter list parsed on its own. */
92
+ node: Node | null;
93
+ parent: Scope | null;
94
+ /** An `await` or `for await` runs directly in it, no function around; only a program or fragment scope can say so. */
95
+ topLevelAwait: boolean;
96
+ }
97
+
98
+ /** A binding, as one of `bindings` on the answer. */
99
+ export interface Binding {
100
+ name: string;
101
+ kind:
102
+ | 'var'
103
+ | 'let'
104
+ | 'const'
105
+ | 'using'
106
+ | 'await using'
107
+ | 'function'
108
+ | 'class'
109
+ | 'param'
110
+ | 'catch'
111
+ | 'import'
112
+ | 'function-name'
113
+ | 'class-name'
114
+ | 'arguments'
115
+ | 'enum'
116
+ | 'enum-member'
117
+ | 'namespace'
118
+ | 'pattern';
119
+ scope: Scope;
120
+ /** The identifier that declares it; null for `arguments`. */
121
+ node: Identifier | null;
122
+ /** What declares it: the declarator, function, class, import specifier, catch clause or enum, as eslint-scope's definition node; null for `arguments` and for a pattern or parameter list parsed on its own. */
123
+ declaration: Node | null;
124
+ }
125
+
126
+ /** A piece of JavaScript a host read on its own, as one of `roots` on a document's answer, with what the tables hold for it. */
127
+ export interface Root {
128
+ node: Node;
129
+ /** The scope the piece sits in. */
130
+ scope: Scope;
131
+ /** The scopes opened inside it, the bindings declared and the references made there. */
132
+ scopes: Scope[];
133
+ bindings: Binding[];
134
+ references: Reference[];
135
+ }
136
+ /** A reference, as one of `references` on the answer. */
137
+ export interface Reference {
138
+ node: Identifier;
139
+ /** The scope the reference is made from. */
140
+ scope: Scope;
141
+ /** Null for a global. */
142
+ binding: Binding | null;
143
+ /** The identifier is assigned to, updated or bound by a destructuring assignment. */
144
+ write: boolean;
145
+ /** A member of the identifier's value is assigned to, updated or deleted. */
146
+ mutate: boolean;
147
+ /** The identifier's value is read: every reference but a plain assignment's target or a destructuring one's; a compound assignment or an update reads and writes. */
148
+ read: boolean;
149
+ /** What a write assigns: the right side of the assignment or the iterated expression of a `for-in` or `for-of`, as eslint-scope's `writeExpr`; null for an update. */
150
+ writeExpr: Expression | null;
151
+ }
152
+
153
+ /** The node `node` is a child of; undefined for the root of an answer. A literal's `regex` and a template element's `value` are not nodes and have none. */
154
+ export function parentOf(node: Node): Node | undefined;
155
+ /** With `scopes`: the scope `node` opens, when it opens one. */
156
+ export function scopeOf(node: Node): Scope | undefined;
157
+ /** With `scopes`: what an identifier declares or refers to; null for a global, undefined when it names no value, a property key say. */
158
+ export function bindingOf(node: Node): Binding | null | undefined;
159
+ /** With `scopes`: the reference an identifier makes, with its `write` and `mutate`; a global's too, which no binding lists. */
160
+ export function referenceOf(node: Node): Reference | undefined;
161
+
162
+ /** A range of the source, with `loc` when `locations` is on. */
163
+ export interface Span {
164
+ start: number;
165
+ end: number;
166
+ loc?: { start: { line: number; column: number }; end: { line: number; column: number } };
167
+ }
168
+
169
+ export interface Comment extends Span {
170
+ type: 'Line' | 'Block';
171
+ value: string;
172
+ }
173
+
174
+ /** A node erasure left in place, by type. */
175
+ export interface Kept extends Span {
176
+ type: string;
177
+ }
178
+
179
+ /** A recovered error: what the thrown `SyntaxError` carries, as a plain object. */
180
+ export type Recovered = Pick<ParseError, 'code' | 'message' | 'pos' | 'end'> & { loc: { line: number; column: number } };
181
+
182
+ /** What a parse returns: the node, or the patterns of a parameter list, and what the options add; a key is there exactly when its option is on. */
183
+ export interface Parsed<T> {
184
+ node: T;
185
+ /** The offset after everything the parse consumed: the node, its closing parens and the comments after it; a program's is the end it was given. */
186
+ end: number;
187
+ /** Every comment read, in source order; with `comments`. */
188
+ comments?: Comment[];
189
+ /** What erasure left in place; with `typescript: 'erase'`. */
190
+ typescript?: Kept[];
191
+ /** The errors recovered from, in source order; with `errorRecovery`. */
192
+ errors?: Recovered[];
193
+ /** With `scopes`. */
194
+ scopes?: Scope[];
195
+ bindings?: Binding[];
196
+ references?: Reference[];
197
+ /** With `scopes`, for a document read by a host grammar: its pieces of JavaScript in source order. */
198
+ roots?: Root[];
199
+ }
200
+
201
+ /**
202
+ * What a parse reads: a program, or what a host embedding JavaScript in a larger syntax reads at
203
+ * a point of it. A type parameter list `<...>` is TypeScript only, `not_typescript` otherwise.
204
+ */
205
+ export type Entry = 'program' | 'expression' | 'pattern' | 'params' | 'statement' | 'typeParameters';
206
+
207
+ export interface At {
208
+ /** Where the source is cut, a UTF-16 offset; the end of the source by default. A program reads to it. */
209
+ end?: number;
210
+ /**
211
+ * The host's own tokens, words or punctuators, that follow what is parsed. One read outside
212
+ * every bracket the parse opened, where the expression could end, ends it: `,` ends an
213
+ * expression before a sequence would, and `/>` is never a division. A `then` after `.` is a
214
+ * property name. A TypeScript `as` is the host's unless another `as` follows the assertion,
215
+ * so `xs as T[] as item` ends after the type.
216
+ */
217
+ stopAt?: string[];
218
+ }
219
+
220
+ /**
221
+ * A node of a host language, as its grammar names the type and the fields; the JavaScript under
222
+ * it is ESTree.
223
+ */
224
+ export interface HostNode {
225
+ type: string;
226
+ start: number;
227
+ end: number;
228
+ loc?: SourceLocation;
229
+ [field: string]: unknown;
230
+ }
231
+
232
+ /**
233
+ * A source kept with its options: the parses out of it share the source copy and the position
234
+ * tables. Offsets are UTF-16, as in acorn; positions stay those of the whole source. `Root` is
235
+ * what the program entry answers with: the program, or the document's root with a `host`.
236
+ */
237
+ export class Source<Root = Program> {
238
+ constructor(source: string, options?: Options);
239
+ /** The program starting at `offset`, the whole source by default; the document with a `host`. */
240
+ parse(entry?: 'program', offset?: number, at?: At): Parsed<Root>;
241
+ parse(entry: 'expression', offset: number, at?: At): Parsed<Expression>;
242
+ /** An assignment target: an identifier or a destructuring pattern. */
243
+ parse(entry: 'pattern', offset: number, at?: At): Parsed<Pattern>;
244
+ /** A parenthesized parameter list, as an arrow function's is read. */
245
+ parse(entry: 'params', offset: number, at?: At): Parsed<Pattern[]>;
246
+ parse(entry: 'statement', offset: number, at?: At): Parsed<Statement>;
247
+ /** A `TSTypeParameterDeclaration`. */
248
+ parse(entry: 'typeParameters', offset: number, at?: At): Parsed<Node>;
249
+ /** Releases what the engine holds for the source, as `using` does at the end of its block; the collector does it otherwise. */
250
+ [Symbol.dispose](): void;
251
+ }
252
+
253
+ /** Whether a code point can start an identifier, as acorn decides it. */
254
+ export function isIdentifierStart(code: number): boolean;
255
+ /** Whether a code point can continue an identifier. */
256
+ export function isIdentifierChar(code: number): boolean;
package/index.js ADDED
@@ -0,0 +1,26 @@
1
+ // the source goes over as bytes: V8's encoder is 14x faster than the host reading a string out
2
+ import { bind } from './api.js';
3
+ import { load } from './native.js';
4
+
5
+ export { isIdentifierStart, isIdentifierChar } from './identifier.js';
6
+ export { scopeOf, bindingOf, referenceOf, parentOf } from './decode.js';
7
+
8
+ const native = load();
9
+ const encoder = new TextEncoder();
10
+ let scratch = new Uint8Array(1 << 16);
11
+
12
+ function bytes(text) {
13
+ const size = text.length * 3;
14
+ if (scratch.length < size && size <= 1 << 20) scratch = new Uint8Array(size);
15
+ const room = size <= scratch.length ? scratch : new Uint8Array(size);
16
+ const { written } = encoder.encodeInto(text, room);
17
+ return room.subarray(0, written);
18
+ }
19
+
20
+ export const Source = bind({
21
+ create: (source, names, host) => native.create(bytes(source), names, host),
22
+ parse: native.parse,
23
+ free: native.free,
24
+ constants: native.constants,
25
+ shapes: native.shapes,
26
+ });
package/native.js ADDED
@@ -0,0 +1,22 @@
1
+ import { createRequire } from 'node:module';
2
+
3
+ export const platforms = {
4
+ 'linux-x64-gnu': { target: 'x86_64-unknown-linux-gnu', os: 'linux', cpu: 'x64', libc: 'glibc' },
5
+ 'linux-arm64-gnu': { target: 'aarch64-unknown-linux-gnu', os: 'linux', cpu: 'arm64', libc: 'glibc' },
6
+ 'darwin-x64': { target: 'x86_64-apple-darwin', os: 'darwin', cpu: 'x64' },
7
+ 'darwin-arm64': { target: 'aarch64-apple-darwin', os: 'darwin', cpu: 'arm64' },
8
+ 'win32-x64-msvc': { target: 'x86_64-pc-windows-msvc', os: 'win32', cpu: 'x64' },
9
+ };
10
+
11
+ export const here = `${process.platform}-${process.arch}${{ linux: '-gnu', win32: '-msvc' }[process.platform] ?? ''}`;
12
+
13
+ export function load() {
14
+ const require = createRequire(import.meta.url);
15
+ const file = `teasel.${here}.node`;
16
+ try {
17
+ return require(`./${file}`);
18
+ } catch (e) {
19
+ if (e.code !== 'MODULE_NOT_FOUND') throw e;
20
+ return require(`@teasel/parser-${here}/${file}`);
21
+ }
22
+ }
package/package.json CHANGED
@@ -1,11 +1,62 @@
1
1
  {
2
2
  "name": "@teasel/parser",
3
- "version": "0.0.0",
4
- "description": "A JavaScript parser in Rust, built to sit under the Svelte compiler. Placeholder release.",
3
+ "version": "0.0.2",
4
+ "description": "A JavaScript and TypeScript parser in Rust. It answers in ESTree.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/Nic-Polumeyv/teasel.git"
9
9
  },
10
- "files": []
10
+ "type": "module",
11
+ "main": "index.js",
12
+ "types": "index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "node": {
16
+ "types": "./index.d.ts",
17
+ "default": "./index.js"
18
+ },
19
+ "default": {
20
+ "types": "./wasm.d.ts",
21
+ "default": "./wasm.js"
22
+ }
23
+ },
24
+ "./wasm": {
25
+ "types": "./wasm.d.ts",
26
+ "default": "./wasm.js"
27
+ },
28
+ "./teasel.wasm": "./teasel.wasm"
29
+ },
30
+ "files": [
31
+ "index.js",
32
+ "index.d.ts",
33
+ "wasm.js",
34
+ "wasm.d.ts",
35
+ "native.js",
36
+ "api.js",
37
+ "decode.js",
38
+ "identifier.js",
39
+ "teasel.wasm"
40
+ ],
41
+ "scripts": {
42
+ "build": "bun addon.js",
43
+ "build:wasm": "cargo build --release -p teasel-wasm --target wasm32-unknown-unknown && cp ../target/wasm32-unknown-unknown/release/teasel_wasm.wasm teasel.wasm",
44
+ "test": "bun test.js && bun test.js interpret",
45
+ "check": "node check.js",
46
+ "changeset:version": "changeset version && bun versions.js && git add --all"
47
+ },
48
+ "dependencies": {
49
+ "@types/estree": "^1.0.6"
50
+ },
51
+ "devDependencies": {
52
+ "@changesets/changelog-github": "^1.0.0",
53
+ "@changesets/cli": "^3.0.1"
54
+ },
55
+ "optionalDependencies": {
56
+ "@teasel/parser-linux-x64-gnu": "0.0.2",
57
+ "@teasel/parser-linux-arm64-gnu": "0.0.2",
58
+ "@teasel/parser-darwin-x64": "0.0.2",
59
+ "@teasel/parser-darwin-arm64": "0.0.2",
60
+ "@teasel/parser-win32-x64-msvc": "0.0.2"
61
+ }
11
62
  }
package/teasel.wasm ADDED
Binary file
package/wasm.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './index.js';
package/wasm.js ADDED
@@ -0,0 +1,62 @@
1
+ import { bind } from './api.js';
2
+
3
+ export { isIdentifierStart, isIdentifierChar } from './identifier.js';
4
+ export { scopeOf, bindingOf, referenceOf, parentOf } from './decode.js';
5
+
6
+ const encoder = new TextEncoder();
7
+ const utf8 = new TextDecoder();
8
+
9
+ // `teasel.wasm` next to this file, read where there is a file system and fetched elsewhere
10
+ const url = new URL('./teasel.wasm', import.meta.url);
11
+ const { instance } =
12
+ url.protocol === 'file:'
13
+ ? await WebAssembly.instantiate(await (await import('node:fs/promises')).readFile(url), {})
14
+ : await WebAssembly.instantiateStreaming(fetch(url), {});
15
+ /** @type {WebAssembly.Exports & Record<string, Function> & { memory: WebAssembly.Memory }} */
16
+ const wasm = /** @type {any} */ (instance.exports);
17
+ /** @type {string[]} */
18
+ let constants = [];
19
+ /** @type {number[]} */
20
+ let shapes = [];
21
+ let shapes_known = 0;
22
+
23
+ // the module takes the bytes over
24
+ function bytes(text) {
25
+ const capacity = text.length * 3;
26
+ const ptr = wasm.alloc(capacity);
27
+ const { written } = encoder.encodeInto(text, new Uint8Array(wasm.memory.buffer, ptr, capacity));
28
+ return [ptr, written, capacity];
29
+ }
30
+
31
+ function create(source, names, host) {
32
+ const handle = wasm.source_new(...bytes(source), ...bytes(names), ...bytes(host));
33
+ if (handle === 0) throw new Error(JSON.parse(text()).error.message);
34
+ return handle;
35
+ }
36
+
37
+ const text = () => utf8.decode(new Uint8Array(wasm.memory.buffer, wasm.text_ptr(), wasm.text_len()));
38
+ const words = () => new Uint32Array(wasm.memory.buffer, wasm.words_ptr(), wasm.words_len());
39
+
40
+ // the constants and shapes come first: writing them can grow the memory and detach a view taken before
41
+ function answer(status) {
42
+ if (status !== 0) return text();
43
+ if (words()[4] > constants.length) {
44
+ wasm.constants();
45
+ constants = JSON.parse(text());
46
+ }
47
+ if (words()[5] > shapes_known) {
48
+ shapes_known = words()[5];
49
+ wasm.shapes();
50
+ shapes = JSON.parse(text());
51
+ }
52
+ return words();
53
+ }
54
+
55
+ export const Source = bind({
56
+ create,
57
+ // the words outlive the source: they sit in the answer buffer until the next parse
58
+ parse: (held, entry, offset, end, stop) => answer(wasm.source_parse(held, entry, offset, end ?? 0, end === undefined ? 0 : 1, ...bytes(stop))),
59
+ free: (held) => wasm.source_free(held),
60
+ constants: () => constants,
61
+ shapes: () => shapes,
62
+ });