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};