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
16 for (
17 let quasiIndex = 0, stackIndex = 0;
18 stackIndex < quasis.length + expressions.length;
19 stackIndex++
20 ) {
21 if (stackIndex % 2 !== 0) {
22 currentSequence.push({
23 expression: expressions[stackIndex++ >> 1],
24 });
25 }
26
27 const quasi = quasis[stackIndex >> 1];
28 for (quasiIndex = 0; quasiIndex < quasi.length; ) {
29 const char = quasi[quasiIndex++];
30 if (char === ' ' || char === '\t' || char === '\r' || char === '\n') {
31 } else if (char === '|' && currentSequence.length) {
32 currentSequence = currentSequence.alternation = [];
33 } else if (char === ')' && currentSequence.length) {
34 currentGroup = null;
35 currentSequence = sequenceStack.pop();
36 if (!currentSequence) syntaxError(char);
37 } else if (char === '(') {
38 sequenceStack.push(currentSequence);
39 currentSequence.push((currentGroup = { sequence: [] }));
40 currentSequence = currentGroup.sequence;
41 } else if (char === '?' && !currentSequence.length && currentGroup) {
42 const nextChar = quasi[quasiIndex++];
43 if (nextChar === ':' || nextChar === '=' || nextChar === '!') {
44 currentGroup.capture = nextChar;
45 } else {
46 syntaxError(char);
47 }
48 } else if (
49 (char === '?' || char === '+' || char === '*') &&
50 (lastMatch = currentSequence[currentSequence.length - 1])
51 ) {
52 lastMatch.quantifier = char;
53 } else {
54 syntaxError(char);
55 }
56 }
57 }
58
59 return rootSequence;
60};