Mirror: The magical sticky regex-based parser generator 🧙

Fix edge case for optional groups not being atomic

+31 -22
+20 -16
src/babel/__snapshots__/plugin.test.js.snap
··· 192 192 return; 193 193 } 194 194 195 - loop_3: for (;;) { 195 + group_3: for (;;) { 196 196 var y3 = state.y, 197 197 x3 = state.x; 198 198 199 199 if ((x = _node_expression3(state)) == null) { 200 200 state.y = y3; 201 201 state.x = x3; 202 - break loop_3; 202 + break group_3; 203 203 } 204 204 } 205 205 } ··· 277 277 break block_2; 278 278 } 279 279 280 - loop_2: for (;;) { 280 + group_2: for (;;) { 281 281 var y2 = state.y, 282 282 x2 = state.x; 283 283 ··· 286 286 } else { 287 287 state.y = y2; 288 288 state.x = x2; 289 - break loop_2; 289 + break group_2; 290 290 } 291 291 } 292 292 ··· 301 301 return; 302 302 } 303 303 304 - loop_2: for (;;) { 304 + group_2: for (;;) { 305 305 var y2 = state.y, 306 306 x2 = state.x; 307 307 ··· 310 310 } else { 311 311 state.y = y2; 312 312 state.x = x2; 313 - break loop_2; 313 + break group_2; 314 314 } 315 315 } 316 316 317 - loop_2: for (;;) { 317 + group_2: for (;;) { 318 318 var y2 = state.y, 319 319 x2 = state.x; 320 320 var ln2 = node.length; ··· 325 325 state.y = y2; 326 326 state.x = x2; 327 327 node.length = ln2; 328 - break loop_2; 328 + break group_2; 329 329 } 330 330 331 - var y4 = state.y, 332 - x4 = state.x; 331 + group_4: { 332 + var y4 = state.y, 333 + x4 = state.x; 333 334 334 - if ((x = _node_expression4(state)) != null) { 335 - node.push(x); 336 - } else { 337 - state.y = y4; 338 - state.x = x4; 335 + if ((x = _node_expression4(state)) != null) { 336 + node.push(x); 337 + } else { 338 + state.y = y4; 339 + state.x = x4; 340 + node.length = ln2; 341 + break group_4; 342 + } 339 343 } 340 344 341 345 if ((x = _node_expression5(state)) != null) { ··· 344 348 state.y = y2; 345 349 state.x = x2; 346 350 node.length = ln2; 347 - break loop_2; 351 + break group_2; 348 352 } 349 353 } 350 354 }
+8 -6
src/codegen.js
··· 71 71 const astQuantifier = (ast, depth, opts) => { 72 72 const { index, abort } = opts; 73 73 const invert = `inv_${depth}`; 74 - const loop = `loop_${depth}`; 74 + const group = `group_${depth}`; 75 75 76 76 opts = copy(opts); 77 77 if (ast.capture === '!') { ··· 90 90 } else if (ast.quantifier === '*') { 91 91 opts.length = 0; 92 92 opts.index = depth; 93 - opts.abort = js`break ${loop};`; 93 + opts.abort = js`break ${group};`; 94 94 95 95 child = js` 96 - ${loop}: for (;;) { 96 + ${group}: for (;;) { 97 97 ${assignIndex(depth)} 98 98 ${astChild(ast, depth, opts)} 99 99 } 100 100 `; 101 101 } else if (ast.quantifier === '?') { 102 102 opts.index = depth; 103 - opts.abort = ''; 103 + opts.abort = js`break ${group}`; 104 104 105 105 child = js` 106 - ${assignIndex(depth)} 107 - ${astChild(ast, depth, opts)} 106 + ${group}: { 107 + ${assignIndex(depth)} 108 + ${astChild(ast, depth, opts)} 109 + } 108 110 `; 109 111 } else { 110 112 child = astChild(ast, depth, opts);
+3
src/core.test.js
··· 115 115 input | result 116 116 ${'123'} | ${['1', '2', '3']} 117 117 ${'3'} | ${['3']} 118 + ${'23'} | ${undefined} 118 119 ${'_'} | ${undefined} 119 120 `('should return $result when $input is passed', ({ input, result }) => { 120 121 expectToParse(node, input, result); ··· 128 129 ${'123'} | ${['1', '2', '3']} 129 130 ${'12123'} | ${['1', '2', '1', '2', '3']} 130 131 ${'3'} | ${['3']} 132 + ${'23'} | ${undefined} 131 133 ${'13'} | ${undefined} 132 134 ${'_'} | ${undefined} 133 135 `('should return $result when $input is passed', ({ input, result }) => { ··· 141 143 input | result 142 144 ${'123'} | ${['1', '2', '3']} 143 145 ${'12123'} | ${['1', '2', '1', '2', '3']} 146 + ${'23'} | ${undefined} 144 147 ${'3'} | ${undefined} 145 148 ${'13'} | ${undefined} 146 149 ${'_'} | ${undefined}