Mirror: The magical sticky regex-based parser generator 馃
1import { astRoot, _private as privateId } from './codegen'; 2import { parse as parseDSL } from './parser'; 3 4const isStickySupported = typeof /./g.sticky === 'boolean'; 5 6export const __private = { 7 pattern(input) { 8 if (typeof input === 'function') return input; 9 const source = typeof input !== 'string' ? input.source : input; 10 return isStickySupported 11 ? new RegExp(source, 'y') 12 : new RegExp(source + '|()', 'g'); 13 }, 14 15 exec(state, pattern) { 16 let match; 17 18 if (typeof pattern === 'function') { 19 if (!pattern.length) pattern = pattern(); 20 return pattern(state); 21 } 22 23 const input = state.quasis[state.x]; 24 if (input && (pattern.lastIndex = state.y) < input.length) { 25 if (isStickySupported) { 26 if (pattern.test(input)) 27 match = input.slice(state.y, pattern.lastIndex); 28 } else { 29 match = pattern.exec(input)[0] || match; 30 } 31 32 state.y = pattern.lastIndex; 33 } 34 35 return match; 36 }, 37}; 38 39export const interpolation = (predicate) => (state) => { 40 let match; 41 42 if ( 43 state.y >= state.quasis[state.x].length && 44 state.x < state.expressions.length 45 ) { 46 state.y = 0; 47 match = state.expressions[state.x++]; 48 if (predicate && match) match = predicate(match); 49 } 50 51 return match; 52}; 53 54export const parse = (matcher) => (quasis, ...expressions) => { 55 if (typeof quasis === 'string') quasis = [quasis]; 56 const state = { quasis, expressions, x: 0, y: 0 }; 57 return matcher(state); 58}; 59 60export const match = (name, transform) => (quasis, ...expressions) => { 61 const ast = parseDSL( 62 quasis, 63 expressions.map((expression, i) => ({ 64 fn: typeof expression === 'function' && expression.length, 65 id: `_${i}`, 66 })) 67 ); 68 69 const makeMatcher = new Function( 70 privateId + 71 ',_n,_t,' + 72 expressions.map((_expression, i) => `_${i}`).join(','), 73 'return ' + astRoot(ast, '_n', transform ? '_t' : null) 74 ); 75 76 return makeMatcher( 77 __private, 78 name, 79 transform, 80 ...expressions.map(__private.pattern) 81 ); 82};