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