Mirror: The magical sticky regex-based parser generator 🧙

Remove special logic for "+" quantifier

Instead it'll generate code for `${x} ${x}*` on the fly.

Changed files
+38 -49
src
babel
__snapshots__
+33 -29
src/babel/__snapshots__/plugin.test.js.snap
···
break alt_3;
}
-
loop_3: for (var j3 = 0; 1; j3++) {
var y3 = state.y,
x3 = state.x;
if ((x = _node_expression3(state)) != null) {} else {
-
if (j3) {
-
state.y = y3;
-
state.x = x3;
-
break loop_3;
-
} else {}
-
-
state.y = y1;
-
state.x = x1;
-
node.length = ln2;
-
return;
}
}
}
···
var y2 = state.y,
x2 = state.x;
-
loop_2: for (var j2 = 0; 1; j2++) {
var y2 = state.y,
x2 = state.x;
if ((x = _node_expression(state)) != null) {
node.push(x);
} else {
-
if (j2) {
-
state.y = y2;
-
state.x = x2;
-
break loop_2;
-
} else {}
-
state.y = y2;
state.x = x2;
-
break block_2;
}
}
break alt_2;
}
-
loop_2: for (var j2 = 0; 1; j2++) {
var y2 = state.y,
x2 = state.x;
if ((x = _node_expression2(state)) != null) {
node.push(x);
} else {
-
if (j2) {
-
state.y = y2;
-
state.x = x2;
-
break loop_2;
-
} else {}
-
-
state.y = y1;
-
state.x = x1;
-
return;
}
}
···
break alt_3;
}
+
if ((x = _node_expression3(state)) != null) {} else {
+
state.y = y1;
+
state.x = x1;
+
node.length = ln2;
+
return;
+
}
+
+
loop_3: for (;;) {
var y3 = state.y,
x3 = state.x;
if ((x = _node_expression3(state)) != null) {} else {
+
state.y = y3;
+
state.x = x3;
+
break loop_3;
}
}
}
···
var y2 = state.y,
x2 = state.x;
+
if ((x = _node_expression(state)) != null) {
+
node.push(x);
+
} else {
+
state.y = y2;
+
state.x = x2;
+
break block_2;
+
}
+
+
loop_2: for (;;) {
var y2 = state.y,
x2 = state.x;
if ((x = _node_expression(state)) != null) {
node.push(x);
} else {
state.y = y2;
state.x = x2;
+
break loop_2;
}
}
break alt_2;
}
+
if ((x = _node_expression2(state)) != null) {
+
node.push(x);
+
} else {
+
state.y = y1;
+
state.x = x1;
+
return;
+
}
+
+
loop_2: for (;;) {
var y2 = state.y,
x2 = state.x;
if ((x = _node_expression2(state)) != null) {
node.push(x);
} else {
+
state.y = y2;
+
state.x = x2;
+
break loop_2;
}
}
+5 -20
src/codegen.js
···
if ((${_match} = ${ast.expression.id}(${_state})) != null) {
${capture ? js`${_node}.push(${_match})` : ''}
} else {
-
${opts.onAbort}
${restoreIndex(opts.index)}
${restoreLength}
${opts.abort}
···
ast.expression ? astExpression(ast, depth, opts) : astGroup(ast, depth, opts);
const astQuantifier = (ast, depth, opts) => {
-
const { index, abort, onAbort } = opts;
const invert = `inv_${depth}`;
const loop = `loop_${depth}`;
-
const count = `j${depth}`;
opts = copy(opts);
if (ast.capture === '!') {
···
let child;
if (ast.quantifier === '+') {
-
opts.onAbort = js`
-
if (${count}) {
-
${restoreIndex(depth)}
-
break ${loop};
-
} else {
-
${onAbort}
-
}
-
`;
-
child = js`
-
${loop}: for (var ${count} = 0; 1; ${count}++) {
-
${assignIndex(depth)}
-
${astChild(ast, depth, opts)}
-
}
`;
} else if (ast.quantifier === '*') {
opts.length = 0;
opts.index = depth;
opts.abort = js`break ${loop};`;
-
opts.onAbort = '';
child = js`
${loop}: for (;;) {
···
} else if (ast.quantifier === '?') {
opts.index = depth;
opts.abort = '';
-
opts.onAbort = '';
child = js`
${assignIndex(depth)}
···
childOpts = copy(opts);
childOpts.index = depth;
childOpts.abort = js`break ${block};`;
-
childOpts.onAbort = '';
}
let sequence = '';
···
${astSequence(ast, 2, {
index: 1,
length: 0,
-
onAbort: '',
abort: js`return;`,
capture: true,
})}
···
if ((${_match} = ${ast.expression.id}(${_state})) != null) {
${capture ? js`${_node}.push(${_match})` : ''}
} else {
${restoreIndex(opts.index)}
${restoreLength}
${opts.abort}
···
ast.expression ? astExpression(ast, depth, opts) : astGroup(ast, depth, opts);
const astQuantifier = (ast, depth, opts) => {
+
const { index, abort } = opts;
const invert = `inv_${depth}`;
const loop = `loop_${depth}`;
opts = copy(opts);
if (ast.capture === '!') {
···
let child;
if (ast.quantifier === '+') {
+
const starAst = copy(ast);
+
starAst.quantifier = '*';
child = js`
+
${astChild(ast, depth, opts)}
+
${astQuantifier(starAst, depth, opts)}
`;
} else if (ast.quantifier === '*') {
opts.length = 0;
opts.index = depth;
opts.abort = js`break ${loop};`;
child = js`
${loop}: for (;;) {
···
} else if (ast.quantifier === '?') {
opts.index = depth;
opts.abort = '';
child = js`
${assignIndex(depth)}
···
childOpts = copy(opts);
childOpts.index = depth;
childOpts.abort = js`break ${block};`;
}
let sequence = '';
···
${astSequence(ast, 2, {
index: 1,
length: 0,
abort: js`return;`,
capture: true,
})}