1const syntaxError = (char) => {
2 throw new SyntaxError('Unexpected token "' + char + '"');
3};
4
5export const parse = (quasis, expressions) => {
6 let quasiIndex = 0;
7 let stackIndex = 0;
8
9 const sequenceStack = [];
10 const rootSequence = [];
11
12 let currentGroup = null;
13 let lastMatch;
14 let currentSequence = rootSequence;
15 let capture;
16
17 for (
18 let quasiIndex = 0, stackIndex = 0;
19 stackIndex < quasis.length + expressions.length;
20 stackIndex++
21 ) {
22 if (stackIndex % 2 !== 0) {
23 const expression = expressions[stackIndex++ >> 1];
24 currentSequence.push({ expression, capture });
25 capture = undefined;
26 }
27
28 const quasi = quasis[stackIndex >> 1];
29 for (quasiIndex = 0; quasiIndex < quasi.length; ) {
30 const char = quasi[quasiIndex++];
31 if (char === ' ' || char === '\t' || char === '\r' || char === '\n') {
32 } else if (char === '|' && currentSequence.length) {
33 currentSequence = currentSequence.alternation = [];
34 } else if (char === ')' && currentSequence.length) {
35 currentGroup = null;
36 currentSequence = sequenceStack.pop();
37 if (!currentSequence) syntaxError(char);
38 } else if (char === '(') {
39 sequenceStack.push(currentSequence);
40 currentSequence.push((currentGroup = { sequence: [], capture }));
41 currentSequence = currentGroup.sequence;
42 capture = undefined;
43 } else if (char === ':' || char === '=' || char === '!') {
44 capture = char;
45 const nextChar = quasi[quasiIndex];
46 if (quasi[quasiIndex] && quasi[quasiIndex] !== '(') syntaxError(char);
47 } else if (char === '?' && !currentSequence.length && currentGroup) {
48 capture = quasi[quasiIndex++];
49 if (capture === ':' || capture === '=' || capture === '!') {
50 currentGroup.capture = capture;
51 capture = undefined;
52 } else {
53 syntaxError(char);
54 }
55 } else if (
56 (char === '?' || char === '+' || char === '*') &&
57 (lastMatch = currentSequence[currentSequence.length - 1])
58 ) {
59 lastMatch.quantifier = char;
60 } else {
61 syntaxError(char);
62 }
63 }
64 }
65
66 return rootSequence;
67};