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