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