diff options
author | elioat <elioat@tilde.institute> | 2024-10-13 19:24:58 -0400 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2024-10-13 19:24:58 -0400 |
commit | 63bc8963e6f031ed059bcf218cbc6277d33485b8 (patch) | |
tree | d5ab47fb75b1e85ae1f77b5d1bd83b2c44f6e2d4 /js | |
parent | 302274bb999c7172b74096f2c5199eac9e294ad0 (diff) | |
download | tour-63bc8963e6f031ed059bcf218cbc6277d33485b8.tar.gz |
*
Diffstat (limited to 'js')
-rw-r--r-- | js/regex.js | 41 |
1 files changed, 27 insertions, 14 deletions
diff --git a/js/regex.js b/js/regex.js index 14199af..86acf21 100644 --- a/js/regex.js +++ b/js/regex.js @@ -7,7 +7,8 @@ const tokenize = (pattern) => { if (char === '.' || char === '*' || char === '(' || char === ')' || char === '|') { tokens.push({ - type: char + type: char, + value: char }); } else if (char === '\\') { // Handle escaped characters i++; @@ -40,10 +41,11 @@ const tokenize = (pattern) => { + const parse = (tokens) => { let i = 0; - const parseExpression = () => { + const parseSequenceExpression = () => { const node = { type: 'sequence', elements: [] @@ -74,7 +76,7 @@ const parse = (tokens) => { }); } else if (token.type === '|') { i++; - const right = parseExpression(); + const right = parseSequenceExpression(); return { type: 'alternation', left: node, @@ -82,9 +84,9 @@ const parse = (tokens) => { }; } else if (token.type === '(') { i++; - node.elements.push(parseExpression()); + node.elements.push(parseSequenceExpression()); } else if (token.type === ')') { - break; // End of grouping + break; // End of a grouping } i++; @@ -93,12 +95,12 @@ const parse = (tokens) => { return node; }; - return parseExpression(); + return parseSequenceExpression(); }; -const match = (node, input) => { +const evaluateMatch = (node) => (input) => { if (node.type === 'literal') { return input[0] === node.value ? input.slice(1) : null; } @@ -108,7 +110,7 @@ const match = (node, input) => { if (node.type === 'star') { let remainder = input; while (remainder !== null) { - const next = match(node.element, remainder); + const next = evaluateMatch(node.element)(remainder); if (next === null) { break; } @@ -120,14 +122,14 @@ const match = (node, input) => { return node.value.includes(input[0]) ? input.slice(1) : null; } if (node.type === 'alternation') { - const remainderLeft = match(node.left, input); - const remainderRight = match(node.right, input); + const remainderLeft = evaluateMatch(node.left)(input); + const remainderRight = evaluateMatch(node.right)(input); return remainderLeft !== null ? remainderLeft : remainderRight; } if (node.type === 'sequence') { let remainder = input; for (const element of node.elements) { - remainder = match(element, remainder); + remainder = evaluateMatch(element)(remainder); if (remainder === null) { return null; } @@ -138,6 +140,17 @@ const match = (node, input) => { + +const assertEqual = (expected, actual, message) => { + if (expected !== actual) { + console.error(`FAIL: ${message}`); + } else { + console.log(`PASS: ${message}`); + } +}; + + + const runTests = () => { const tests = [{ pattern: "a.b*c", @@ -212,11 +225,11 @@ const runTests = () => { } ]; - tests.forEach(({pattern,input,expected}, index) => { + tests.forEach(({ pattern, input, expected }, index) => { const tokens = tokenize(pattern); const ast = parse(tokens); - const result = match(ast, input) !== null; - console.log(`Test ${index + 1}: ${result === expected ? 'PASS' : 'FAIL'}`); + const result = evaluateMatch(ast)(input) !== null; + assertEqual(expected, result, `Test ${index + 1}`); }); }; |