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