Mirror: The magical sticky regex-based parser generator 馃
1import { astRoot } from './codegen'; 2import { parse as parseDSL } from './parser'; 3 4const isStickySupported = typeof /./g.sticky === 'boolean'; 5 6export const _pattern = (input) => { 7 if (typeof input === 'function') return input; 8 const source = typeof input !== 'string' ? input.source : input; 9 return isStickySupported 10 ? new RegExp(source, 'y') 11 : new RegExp(`^(?:${source})`, 'g'); 12}; 13 14export const _exec = (state, pattern) => { 15 let match; 16 17 if (typeof pattern === 'function') { 18 if (!pattern.length) pattern = pattern(); 19 return pattern(state); 20 } else if (isStickySupported) { 21 pattern.lastIndex = state.index; 22 if (pattern.test(state.input)) { 23 match = state.input.slice(state.index, pattern.lastIndex); 24 state.index = pattern.lastIndex; 25 } 26 } else { 27 pattern.lastIndex = 0; 28 if (pattern.test(state.input.slice(state.index))) { 29 const lastIndex = state.index + pattern.lastIndex; 30 match = state.input.slice(state.index, lastIndex); 31 state.index = lastIndex; 32 } 33 } 34 35 return match; 36}; 37 38export const parse = (pattern) => (input) => { 39 const state = { input, index: 0 }; 40 return pattern(state); 41}; 42 43export const match = (name, transform) => (quasis, ...expressions) => { 44 const ast = parseDSL( 45 quasis, 46 expressions.map((expression, i) => 47 typeof expression === 'function' && expression.length 48 ? `_${i}(state)` 49 : `_e(state, _${i})` 50 ) 51 ); 52 53 const makeMatcher = new Function( 54 '_e,_n,_t,' + expressions.map((_expression, i) => `_${i}`).join(','), 55 'return ' + astRoot(ast, '_n', transform ? '_t' : null) 56 ); 57 58 return makeMatcher(_exec, name, transform, ...expressions.map(_pattern)); 59};