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 while (typeof pattern === 'function') pattern = pattern(state); 19 return pattern; 20 } else if (typeof pattern === 'string') { 21 const end = state.index + pattern.length; 22 const sub = state.input.slice(state.index, end); 23 if (sub === pattern) { 24 state.index = end; 25 match = sub; 26 } 27 } else if (isStickySupported) { 28 pattern.lastIndex = state.index; 29 if (pattern.test(state.input)) { 30 match = state.input.slice(state.index, pattern.lastIndex); 31 state.index = pattern.lastIndex; 32 } 33 } else { 34 pattern.lastIndex = 0; 35 if (pattern.test(state.input.slice(state.index))) { 36 const lastIndex = state.index + pattern.lastIndex; 37 match = state.input.slice(state.index, lastIndex); 38 state.index = lastIndex; 39 } 40 } 41 42 return match; 43}; 44 45export const parse = (pattern) => (input) => { 46 const state = { input, index: 0 }; 47 return pattern(state); 48}; 49 50export const match = (name, transform) => (quasis, ...expressions) => { 51 const ast = parseDSL( 52 quasis, 53 expressions.map((expression, i) => `_e(state, _${i})`) 54 ); 55 56 const makeMatcher = new Function( 57 '_e,_n,_t,' + expressions.map((_expression, i) => `_${i}`).join(','), 58 'return ' + astRoot(ast, '_n', transform ? '_t' : null) 59 ); 60 61 return makeMatcher(_exec, name, transform, ...expressions.map(_pattern)); 62};