Mirror: The magical sticky regex-based parser generator 🧙
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Refactor AST to return arrays for sequences

+45 -86
+2 -5
src/codegen.js
··· 65 65 }; 66 66 67 67 const astGroup = (ast, depth, opts) => { 68 - if (ast.sequence.length === 1) 69 - return astExpression(ast.sequence[0], depth, opts); 70 - 71 68 const capture = !!opts.capture && !ast.capture; 72 69 73 70 let group = ''; ··· 208 205 } 209 206 210 207 let sequence = ''; 211 - for (let i = 0; i < ast.sequence.length; i++) 212 - sequence += astQuantifier(ast.sequence[i], depth, childOpts); 208 + for (let i = 0; i < ast.length; i++) 209 + sequence += astQuantifier(ast[i], depth, childOpts); 213 210 214 211 if (!ast.alternation) { 215 212 body += sequence;
+9 -21
src/parser.js
··· 3 3 let stackIndex = 0; 4 4 5 5 const sequenceStack = []; 6 - const rootSequence = { 7 - sequence: [], 8 - }; 6 + const rootSequence = []; 9 7 10 8 let currentGroup = null; 11 9 let lastMatch; ··· 13 11 14 12 while (stackIndex < quasis.length + expressions.length) { 15 13 if (stackIndex % 2 !== 0) { 16 - currentSequence.sequence.push({ 14 + currentSequence.push({ 17 15 expression: expressions[stackIndex++ >> 1], 18 16 }); 19 17 } ··· 24 22 25 23 if (char === ' ' || char === '\t' || char === '\r' || char === '\n') { 26 24 continue; 27 - } else if (char === '|' && currentSequence.sequence.length > 0) { 28 - currentSequence = currentSequence.alternation = { 29 - sequence: [], 30 - }; 31 - 25 + } else if (char === '|' && currentSequence.length) { 26 + currentSequence = currentSequence.alternation = []; 32 27 continue; 33 - } else if (char === ')' && currentSequence.sequence.length > 0) { 28 + } else if (char === ')' && currentSequence.length) { 34 29 currentGroup = null; 35 30 currentSequence = sequenceStack.pop(); 36 31 if (currentSequence) continue; 37 32 } else if (char === '(') { 38 33 currentGroup = { 39 - sequence: { 40 - sequence: [], 41 - }, 34 + sequence: [], 42 35 }; 43 36 44 37 sequenceStack.push(currentSequence); 45 - currentSequence.sequence.push(currentGroup); 38 + currentSequence.push(currentGroup); 46 39 currentSequence = currentGroup.sequence; 47 40 continue; 48 - } else if ( 49 - char === '?' && 50 - currentSequence.sequence.length === 0 && 51 - currentGroup 52 - ) { 41 + } else if (char === '?' && !currentSequence.length && currentGroup) { 53 42 const nextChar = quasi[quasiIndex++]; 54 43 if (nextChar === ':') { 55 44 currentGroup.capture = nextChar; ··· 63 52 } 64 53 } else if ( 65 54 (char === '?' || char === '+' || char === '*') && 66 - (lastMatch = 67 - currentSequence.sequence[currentSequence.sequence.length - 1]) 55 + (lastMatch = currentSequence[currentSequence.length - 1]) 68 56 ) { 69 57 lastMatch.quantifier = char; 70 58 continue;
+34 -60
src/parser.test.js
··· 2 2 3 3 const parseTag = (quasis, ...expressions) => parse(quasis, expressions); 4 4 5 - it('supports parsing expressions', () => { 6 - expect(parseTag`${1}`).toEqual({ 7 - sequence: [ 8 - { 9 - expression: 1, 10 - quantifier: undefined, 11 - }, 12 - ], 13 - alternation: undefined, 14 - }); 15 - }); 16 - 17 5 it('supports parsing expressions with quantifiers', () => { 18 6 let ast; 19 7 20 8 ast = parseTag`${1}?`; 21 - expect(ast).toHaveProperty('sequence.0.quantifier', '?'); 9 + expect(ast).toHaveProperty('0.quantifier', '?'); 22 10 23 11 ast = parseTag`${1}+`; 24 - expect(ast).toHaveProperty('sequence.0.quantifier', '+'); 12 + expect(ast).toHaveProperty('0.quantifier', '+'); 25 13 26 14 ast = parseTag`${1}*`; 27 - expect(ast).toHaveProperty('sequence.0.quantifier', '*'); 15 + expect(ast).toHaveProperty('0.quantifier', '*'); 28 16 }); 29 17 30 18 it('supports top-level alternations', () => { 31 19 let ast; 32 20 33 21 ast = parseTag`${1} | ${2}`; 34 - expect(ast).toHaveProperty('sequence.length', 1); 35 - expect(ast).toHaveProperty('sequence.0.expression', 1); 36 - expect(ast).toHaveProperty('alternation.sequence.0.expression', 2); 22 + expect(ast).toHaveProperty('length', 1); 23 + expect(ast).toHaveProperty('0.expression', 1); 24 + expect(ast).toHaveProperty('alternation.0.expression', 2); 37 25 38 26 ast = parseTag`${1}? | ${2}?`; 39 - expect(ast).toHaveProperty('sequence.0.quantifier', '?'); 27 + expect(ast).toHaveProperty('0.quantifier', '?'); 40 28 }); 41 29 42 30 it('supports groups with quantifiers', () => { 43 31 let ast; 44 32 45 33 ast = parseTag`(${1} ${2})`; 46 - expect(ast).toHaveProperty('sequence.length', 1); 47 - expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 2); 48 - expect(ast).toHaveProperty('sequence.0.sequence.sequence.0.expression', 1); 49 - expect(ast).toHaveProperty('sequence.0.sequence.sequence.1.expression', 2); 34 + expect(ast).toHaveProperty('length', 1); 35 + expect(ast).toHaveProperty('0.sequence.length', 2); 36 + expect(ast).toHaveProperty('0.sequence.0.expression', 1); 37 + expect(ast).toHaveProperty('0.sequence.1.expression', 2); 50 38 51 39 ast = parseTag`(${1} ${2}?)?`; 52 - expect(ast).toHaveProperty('sequence.length', 1); 53 - expect(ast).toHaveProperty('sequence.0.quantifier', '?'); 54 - expect(ast).toHaveProperty( 55 - 'sequence.0.sequence.sequence.0.quantifier', 56 - undefined 57 - ); 40 + expect(ast).toHaveProperty('length', 1); 41 + expect(ast).toHaveProperty('0.quantifier', '?'); 42 + expect(ast).toHaveProperty('0.sequence.0.quantifier', undefined); 58 43 }); 59 44 60 45 it('supports non-capturing groups', () => { 61 46 const ast = parseTag`(?: ${1})`; 62 - expect(ast).toHaveProperty('sequence.length', 1); 63 - expect(ast).toHaveProperty('sequence.0.capture', ':'); 64 - expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 1); 47 + expect(ast).toHaveProperty('length', 1); 48 + expect(ast).toHaveProperty('0.capture', ':'); 49 + expect(ast).toHaveProperty('0.sequence.length', 1); 65 50 }); 66 51 67 52 it('supports positive lookahead groups', () => { 68 53 const ast = parseTag`(?= ${1})`; 69 - expect(ast).toHaveProperty('sequence.length', 1); 70 - expect(ast).toHaveProperty('sequence.0.capture', '='); 71 - expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 1); 54 + expect(ast).toHaveProperty('length', 1); 55 + expect(ast).toHaveProperty('0.capture', '='); 56 + expect(ast).toHaveProperty('0.sequence.length', 1); 72 57 }); 73 58 74 59 it('supports negative lookahead groups', () => { 75 60 const ast = parseTag`(?! ${1})`; 76 - expect(ast).toHaveProperty('sequence.length', 1); 77 - expect(ast).toHaveProperty('sequence.0.capture', '!'); 78 - expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 1); 61 + expect(ast).toHaveProperty('length', 1); 62 + expect(ast).toHaveProperty('0.capture', '!'); 63 + expect(ast).toHaveProperty('0.sequence.length', 1); 79 64 }); 80 65 81 66 it('supports groups with alternates', () => { 82 67 expect(parseTag`(${1} | ${2}) ${3}`).toMatchInlineSnapshot(` 83 - Object { 84 - "sequence": Array [ 85 - Object { 86 - "sequence": Object { 87 - "alternation": Object { 88 - "sequence": Array [ 89 - Object { 90 - "expression": 2, 91 - }, 92 - ], 93 - }, 94 - "sequence": Array [ 95 - Object { 96 - "expression": 1, 97 - }, 98 - ], 68 + Array [ 69 + Object { 70 + "sequence": Array [ 71 + Object { 72 + "expression": 1, 99 73 }, 100 - }, 101 - Object { 102 - "expression": 3, 103 - }, 104 - ], 105 - } 74 + ], 75 + }, 76 + Object { 77 + "expression": 3, 78 + }, 79 + ] 106 80 `); 107 81 });