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