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