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' || typeof input === 'string') { 9 return input; 10 } 11 12 const source = typeof input !== 'string' ? input.source : input; 13 return isStickySupported 14 ? new RegExp(source, 'y') 15 : new RegExp(source + '|()', 'g'); 16 }, 17 18 exec(state, pattern) { 19 let match; 20 21 if (typeof pattern === 'function') { 22 if (!pattern.length) pattern = pattern(); 23 return pattern(state); 24 } 25 26 const input = state.quasis[state.x]; 27 if (input && state.y < input.length) { 28 if (typeof pattern === 'string') { 29 const end = state.y + pattern.length; 30 const sub = input.slice(state.y, end); 31 if (sub === pattern) { 32 state.y = end; 33 match = sub; 34 } 35 } else { 36 pattern.lastIndex = state.y; 37 if (isStickySupported) { 38 if (pattern.test(input)) 39 match = input.slice(state.y, pattern.lastIndex); 40 } else { 41 const x = pattern.exec(input); 42 match = x[1] == null ? x[0] : match; 43 } 44 45 state.y = pattern.lastIndex; 46 } 47 } 48 49 return match; 50 }, 51}; 52 53export const interpolation = (predicate) => (state) => { 54 let match; 55 56 if ( 57 state.y >= state.quasis[state.x].length && 58 state.x < state.expressions.length 59 ) { 60 state.y = 0; 61 match = state.expressions[state.x++]; 62 if (predicate && match) match = predicate(match); 63 } 64 65 return match; 66}; 67 68export const parse = (matcher) => (quasis, ...expressions) => { 69 if (typeof quasis === 'string') quasis = [quasis]; 70 const state = { quasis, expressions, x: 0, y: 0 }; 71 return matcher(state); 72}; 73 74export const match = (name, transform) => (quasis, ...expressions) => { 75 const ast = parseDSL( 76 quasis, 77 expressions.map((expression, i) => ({ 78 fn: typeof expression === 'function' && expression.length, 79 id: `_${i}`, 80 })) 81 ); 82 83 const makeMatcher = new Function( 84 privateId + 85 ',_n,_t,' + 86 expressions.map((_expression, i) => `_${i}`).join(','), 87 'return ' + astRoot(ast, '_n', transform ? '_t' : null) 88 ); 89 90 return makeMatcher( 91 __private, 92 name, 93 transform, 94 ...expressions.map(__private.pattern) 95 ); 96};