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 const input = state.quasis[state.x];
14 if (input && state.y < input.length) {
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 const input = state.quasis[state.x];
30 if (input && state.y < input.length) {
31 pattern.lastIndex = state.y;
32
33 let match;
34 if (isStickySupported) {
35 if (pattern.test(input))
36 match = input.slice(state.y, pattern.lastIndex);
37 } else {
38 const x = pattern.exec(input);
39 if (x[1] == null) match = x[0];
40 }
41
42 state.y = pattern.lastIndex;
43 return match;
44 }
45 };
46};
47
48export const __pattern = (input) => {
49 if (typeof input === 'function') {
50 return execLambda(input);
51 } else if (typeof input === 'string') {
52 return execString(input);
53 } else {
54 return execRegex(input);
55 }
56};
57
58export const interpolation = (predicate) => (state) => {
59 let match;
60
61 if (
62 state.y >= state.quasis[state.x].length &&
63 state.x < state.expressions.length
64 ) {
65 state.y = 0;
66 match = state.expressions[state.x++];
67 if (predicate && match) match = predicate(match);
68 }
69
70 return match;
71};
72
73export const parse = (matcher) => (quasis, ...expressions) => {
74 if (typeof quasis === 'string') quasis = [quasis];
75 const state = { quasis, expressions, x: 0, y: 0 };
76 return matcher(state);
77};
78
79export const match = (name, transform) => (quasis, ...expressions) => {
80 const ast = parseDSL(
81 quasis,
82 expressions.map((_, i) => ({ id: `_${i}` }))
83 );
84 return new Function(
85 '_n,_t,' + expressions.map((_expression, i) => `_${i}`).join(','),
86 'return ' + astRoot(ast, '_n', transform ? '_t' : null)
87 )(name, transform, ...expressions.map(__pattern));
88};