···
4
-
export function initGenerator(_ids, _t) {
9
-
/** var id = state.index; */
10
-
class AssignIndexNode {
16
-
const member = t.memberExpression(ids.state, t.identifier('index'));
17
-
return t.variableDeclaration('var', [
18
-
t.variableDeclarator(this.id, member),
23
-
/** state.index = id; */
24
-
class RestoreIndexNode {
30
-
const expression = t.assignmentExpression(
32
-
t.memberExpression(ids.state, t.identifier('index')),
36
-
return t.expressionStatement(expression);
40
-
/** var id = node.length; */
41
-
class AssignLengthNode {
47
-
return t.variableDeclaration('var', [
48
-
t.variableDeclarator(
50
-
t.memberExpression(ids.node, t.identifier('length'))
56
-
/** node.length = id; */
57
-
class RestoreLengthNode {
63
-
const expression = t.assignmentExpression(
65
-
t.memberExpression(ids.node, t.identifier('length')),
69
-
return t.expressionStatement(expression);
73
-
/** return; break id; */
76
-
this.id = id || null;
80
-
const statement = this.id ? t.breakStatement(this.id) : t.returnStatement();
85
-
/** if (condition) { return; break id; } */
86
-
class AbortConditionNode {
87
-
constructor(condition, opts) {
88
-
this.condition = condition || null;
90
-
this.abort = opts.abort;
91
-
this.abortCondition = opts.abortCondition || null;
92
-
this.restoreIndex = opts.restoreIndex;
96
-
return t.ifStatement(
99
-
[this.restoreIndex.statement(), this.abort.statement()].filter(Boolean)
101
-
this.abortCondition ? this.abortCondition.statement() : null
106
-
/** Generates a full matcher for an expression */
107
-
class ExpressionNode {
108
-
constructor(ast, depth, opts) {
110
-
this.depth = depth || 0;
111
-
this.capturing = !!opts.capturing;
112
-
this.restoreIndex = opts.restoreIndex;
113
-
this.restoreLength = opts.restoreLength || null;
114
-
this.abortCondition = opts.abortCondition || null;
115
-
this.abort = opts.abort || null;
119
-
const execMatch = this.ast.expression;
120
-
const assignMatch = t.assignmentExpression('=', ids.match, execMatch);
122
-
const successNodes = t.blockStatement([
123
-
t.expressionStatement(
124
-
t.callExpression(t.memberExpression(ids.node, t.identifier('push')), [
130
-
const abortNodes = t.blockStatement(
132
-
this.abortCondition && this.abortCondition.statement(),
133
-
this.abort && this.restoreLength && this.restoreLength.statement(),
134
-
this.restoreIndex && this.restoreIndex.statement(),
135
-
this.abort && this.abort.statement(),
141
-
? t.ifStatement(t.unaryExpression('!', execMatch), abortNodes)
142
-
: t.ifStatement(assignMatch, successNodes, abortNodes),
147
-
/** Generates a full matcher for a group */
149
-
constructor(ast, depth, opts) {
151
-
this.depth = depth || 0;
152
-
if (ast.sequence.length === 1) {
153
-
return new ExpressionNode(ast.sequence[0], depth, opts);
156
-
const lengthId = t.identifier(`length_${depth}`);
157
-
const childOpts = {
159
-
capturing: !!opts.capturing && !!ast.capturing,
162
-
this.assignLength = null;
163
-
if (!childOpts.restoreLength && childOpts.capturing) {
164
-
this.assignLength = new AssignLengthNode(lengthId);
165
-
childOpts.restoreLength = new RestoreLengthNode(lengthId);
168
-
this.alternation = new AlternationNode(ast.sequence, depth + 1, childOpts);
173
-
this.assignLength && this.assignLength.statement(),
174
-
...this.alternation.statements(),
179
-
/** Generates looping logic around another group or expression matcher */
180
-
class QuantifierNode {
181
-
constructor(ast, depth, opts) {
182
-
const { quantifier } = ast;
184
-
this.depth = depth || 0;
186
-
const invertId = t.identifier(`invert_${this.depth}`);
187
-
const loopId = t.identifier(`loop_${this.depth}`);
188
-
const iterId = t.identifier(`iter_${this.depth}`);
189
-
const indexId = t.identifier(`index_${this.depth}`);
190
-
const ChildNode = ast.type === 'group' ? GroupNode : ExpressionNode;
191
-
const childOpts = { ...opts };
193
-
this.assignIndex = null;
194
-
this.restoreIndex = null;
195
-
this.blockId = null;
198
-
if (ast.type === 'group' && !!ast.lookahead) {
199
-
this.restoreIndex = new RestoreIndexNode(indexId);
200
-
this.assignIndex = new AssignIndexNode(indexId);
203
-
if (ast.type === 'group' && ast.lookahead === 'negative') {
204
-
childOpts.abort = new AbortNode(invertId);
205
-
childOpts.restoreIndex = this.restoreIndex;
206
-
this.restoreIndex = opts.restoreIndex;
207
-
this.blockId = invertId;
208
-
this.abort = opts.abort;
211
-
if (quantifier && !quantifier.singular && quantifier.required) {
212
-
childOpts.abortCondition = new AbortConditionNode(iterId, {
214
-
restoreIndex: new RestoreIndexNode(indexId),
215
-
abort: new AbortNode(loopId),
217
-
} else if (quantifier && !quantifier.singular) {
218
-
childOpts.restoreLength = null;
219
-
childOpts.restoreIndex = new RestoreIndexNode(indexId);
220
-
childOpts.abort = new AbortNode(loopId);
221
-
childOpts.abortCondition = null;
222
-
} else if (quantifier && !quantifier.required) {
223
-
childOpts.restoreIndex = new RestoreIndexNode(indexId);
224
-
childOpts.abortCondition = null;
225
-
childOpts.abort = null;
228
-
this.childNode = new ChildNode(ast, depth, childOpts);
232
-
const { quantifier } = this.ast;
233
-
const loopId = t.identifier(`loop_${this.depth}`);
234
-
const iterId = t.identifier(`iter_${this.depth}`);
235
-
const indexId = t.identifier(`index_${this.depth}`);
236
-
const assignIndex = new AssignIndexNode(indexId);
239
-
if (quantifier && !quantifier.singular && quantifier.required) {
241
-
t.labeledStatement(
244
-
t.variableDeclaration('var', [
245
-
t.variableDeclarator(iterId, t.numericLiteral(0)),
247
-
t.booleanLiteral(true),
248
-
t.updateExpression('++', iterId),
250
-
assignIndex.statement(),
251
-
...this.childNode.statements(),
256
-
} else if (quantifier && !quantifier.singular) {
258
-
t.labeledStatement(
261
-
t.booleanLiteral(true),
263
-
assignIndex.statement(),
264
-
...this.childNode.statements(),
269
-
} else if (quantifier && !quantifier.required) {
270
-
statements = [assignIndex.statement(), ...this.childNode.statements()];
272
-
statements = this.childNode.statements();
275
-
if (this.blockId && this.assignIndex && this.restoreIndex) {
277
-
t.labeledStatement(
281
-
this.assignIndex.statement(),
283
-
this.restoreIndex.statement(),
284
-
this.abort.statement(),
289
-
} else if (this.assignIndex && this.restoreIndex) {
290
-
statements.unshift(this.assignIndex.statement());
291
-
statements.push(this.restoreIndex.statement());
298
-
/** Generates a matcher of a sequence of sub-matchers for a single sequence */
299
-
class SequenceNode {
300
-
constructor(ast, depth, opts) {
302
-
this.depth = depth || 0;
304
-
const indexId = t.identifier(`index_${depth}`);
305
-
const blockId = t.identifier(`block_${this.depth}`);
307
-
this.returnStatement = opts.returnStatement;
308
-
this.assignIndex = ast.alternation ? new AssignIndexNode(indexId) : null;
310
-
this.quantifiers = ast.sequence.map((childAst) => {
311
-
return new QuantifierNode(childAst, depth, {
313
-
restoreIndex: ast.alternation
314
-
? new RestoreIndexNode(indexId)
315
-
: opts.restoreIndex,
316
-
abortCondition: ast.alternation ? null : opts.abortCondition,
317
-
abort: ast.alternation ? new AbortNode(blockId) : opts.abort,
323
-
const blockId = t.identifier(`block_${this.depth}`);
324
-
const alternationId = t.identifier(`alternation_${this.depth}`);
325
-
const statements = this.quantifiers.reduce((block, node) => {
326
-
block.push(...node.statements());
330
-
if (!this.ast.alternation) {
335
-
this.depth === 0 ? this.returnStatement : t.breakStatement(alternationId);
338
-
t.labeledStatement(
341
-
this.assignIndex && this.assignIndex.statement(),
350
-
/** Generates matchers for sequences with (or without) alternations */
351
-
class AlternationNode {
352
-
constructor(ast, depth, opts) {
354
-
this.depth = depth || 0;
355
-
this.sequences = [];
356
-
for (let current = ast; current; current = current.alternation) {
357
-
this.sequences.push(new SequenceNode(current, depth, opts));
362
-
if (this.sequences.length === 1) {
363
-
return this.sequences[0].statements();
366
-
const statements = [];
367
-
for (let i = 0; i < this.sequences.length; i++) {
368
-
statements.push(...this.sequences[i].statements());
371
-
if (this.depth === 0) {
375
-
const alternationId = t.identifier(`alternation_${this.depth}`);
376
-
return [t.labeledStatement(alternationId, t.blockStatement(statements))];
380
-
export class RootNode {
381
-
constructor(ast, nameNode, transformNode) {
382
-
const indexId = t.identifier('last_index');
383
-
const node = t.callExpression(ids.tag, [ids.node, nameNode]);
385
-
this.returnStatement = t.returnStatement(
386
-
transformNode ? t.callExpression(transformNode, [node]) : node
389
-
this.assignIndex = new AssignIndexNode(indexId);
390
-
this.node = new AlternationNode(ast, 0, {
391
-
returnStatement: this.returnStatement,
392
-
restoreIndex: new RestoreIndexNode(indexId, true),
393
-
restoreLength: null,
394
-
abortCondition: null,
395
-
abort: new AbortNode(),
402
-
this.assignIndex.statement(),
403
-
t.variableDeclaration('var', [
404
-
t.variableDeclarator(ids.match),
405
-
t.variableDeclarator(ids.node, t.arrayExpression()),
407
-
...this.node.statements(),
408
-
this.returnStatement,