From 1fed11af6e608456fae79699bdb94e6eda8b44f9 Mon Sep 17 00:00:00 2001 From: Shigoto-dev19 Date: Mon, 11 Mar 2024 10:02:49 +0100 Subject: [PATCH] Adopt & Adapt regex to NFA tests --- src/regex.test.ts | 362 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 360 insertions(+), 2 deletions(-) diff --git a/src/regex.test.ts b/src/regex.test.ts index cfe07e0..b409bdf 100644 --- a/src/regex.test.ts +++ b/src/regex.test.ts @@ -1,8 +1,9 @@ /** - * Edited from https://github.com/CyberZHG/toolbox/blob/gh-pages/test/test_lexical_parse_regex.js + * Edited from #parseRegex - https://github.com/CyberZHG/toolbox/blob/gh-pages/test/test_lexical_parse_regex.js + * #regexToNfa - https://github.com/CyberZHG/toolbox/blob/gh-pages/test/test_lexical_regex_to_nfa.js */ -import { parseRegex } from './lexical'; +import { parseRegex, State, regexToNfa } from './lexical'; describe('Lexical', function () { describe('#parseRegex', function () { @@ -295,4 +296,361 @@ describe('Lexical', function () { }); }); + + describe('#regexToNfa', function () { + it('Empty', function () { + let actual = regexToNfa('ϵ'), + nodes: State[] = [ + { + 'id': 0, + 'type': 'start', + 'edges': [] + }, + { + 'id': 1, + 'type': 'accept', + 'edges': [] + } + ]; + nodes[0].edges.push(['ϵ', nodes[1]]); + expect(actual).toEqual(nodes[0]); + }); + + it('Text', function () { + let actual = regexToNfa('a'), + nodes: State[] = [ + { + 'id': 0, + 'type': 'start', + 'edges': [] + }, + { + 'id': 1, + 'type': 'accept', + 'edges': [] + } + ]; + nodes[0].edges.push(['a', nodes[1]]); + expect(actual).toEqual(nodes[0]); + }); + + it('Cat 2', function () { + let actual = regexToNfa('ab'), + nodes: State[] = [ + { + 'id': 0, + 'type': 'start', + 'edges': [] + }, + { + 'id': 1, + 'type': '', + 'edges': [] + }, + { + 'id': 2, + 'type': 'accept', + 'edges': [] + } + ]; + nodes[0].edges.push(['a', nodes[1]]); + nodes[1].edges.push(['b', nodes[2]]); + expect(actual).toEqual(nodes[0]); + }); + + it('Cat 3', function () { + let actual = regexToNfa('abc'), + nodes: State[] = [ + { + 'id': 0, + 'type': 'start', + 'edges': [] + }, + { + 'id': 1, + 'type': '', + 'edges': [] + }, + { + 'id': 2, + 'type': '', + 'edges': [] + }, + { + 'id': 3, + 'type': 'accept', + 'edges': [] + } + ]; + nodes[0].edges.push(['a', nodes[1]]); + nodes[1].edges.push(['b', nodes[2]]); + nodes[2].edges.push(['c', nodes[3]]); + expect(actual).toEqual(nodes[0]); + }); + + it('Or', function () { + let actual = regexToNfa('a|b'), + nodes: State[] = [ + { + 'id': 0, + 'type': 'start', + 'edges': [] + }, + { + 'id': 1, + 'type': '', + 'edges': [] + }, + { + 'id': 2, + 'type': '', + 'edges': [] + }, + { + 'id': 3, + 'type': '', + 'edges': [] + }, + { + 'id': 4, + 'type': '', + 'edges': [] + }, + { + 'id': 5, + 'type': 'accept', + 'edges': [] + } + ]; + nodes[0].edges.push(['ϵ', nodes[1]]); + nodes[0].edges.push(['ϵ', nodes[3]]); + nodes[1].edges.push(['a', nodes[2]]); + nodes[3].edges.push(['b', nodes[4]]); + nodes[2].edges.push(['ϵ', nodes[5]]); + nodes[4].edges.push(['ϵ', nodes[5]]); + expect(actual).toEqual(nodes[0]); + }); + + it('Star', function () { + let actual = regexToNfa('a*'), + nodes: State[] = [ + { + 'id': 0, + 'type': 'start', + 'edges': [] + }, + { + 'id': 1, + 'type': '', + 'edges': [] + }, + { + 'id': 2, + 'type': '', + 'edges': [] + }, + { + 'id': 3, + 'type': 'accept', + 'edges': [] + } + ]; + nodes[0].edges.push(['ϵ', nodes[1]]); + nodes[0].edges.push(['ϵ', nodes[3]]); + nodes[1].edges.push(['a', nodes[2]]); + nodes[2].edges.push(['ϵ', nodes[1]]); + nodes[2].edges.push(['ϵ', nodes[3]]); + expect(actual).toEqual(nodes[0]); + }); + + /*function toNodes(start) { + let ids = {}, + front, + node, + nodes: State[] = [], + queue = [start]; + for (front = 0; front < queue.length; front += 1) { + node = queue[front]; + if (!ids.hasOwnProperty(node.id)) { + ids[node.id] = node; + node.edges.forEach(function (edge) { + queue.push(edge[1]); + }); + } + } + Object.keys(ids).forEach(function (key) { + ids[key].edges = []; + nodes.push(ids[key]); + }); + console.log(nodes); + return nodes; + } + + function toEdges(start) { + let ids = {}, + front, + node, + nodes: State[] = [], + queue = [start]; + for (front = 0; front < queue.length; front += 1) { + node = queue[front]; + if (!ids.hasOwnProperty(node.id)) { + ids[node.id] = node; + node.edges.forEach(function (edge) { + queue.push(edge[1]); + }); + } + } + Object.keys(ids).forEach(function (key) { + ids[key].edges.forEach(function (edge) { + console.log('nodes[' + key + '].edges.push([\'' + edge[0] + '\', nodes[' + edge[1].id + ']]);'); + }); + }); + return nodes; + }*/ + + it('Example 3.7.3 (a)', function () { + let actual = regexToNfa('(a|b)*'), + nodes: State[] = [ + {type: 'start', edges: [], id: 0}, + {type: '', edges: [], id: 1}, + {type: '', edges: [], id: 2}, + {type: '', edges: [], id: 3}, + {type: '', edges: [], id: 4}, + {type: '', edges: [], id: 5}, + {type: '', edges: [], id: 6}, + {type: 'accept', edges: [], id: 7} + ]; + nodes[0].edges.push(['ϵ', nodes[1]]); + nodes[0].edges.push(['ϵ', nodes[7]]); + nodes[1].edges.push(['ϵ', nodes[2]]); + nodes[1].edges.push(['ϵ', nodes[4]]); + nodes[2].edges.push(['a', nodes[3]]); + nodes[3].edges.push(['ϵ', nodes[6]]); + nodes[4].edges.push(['b', nodes[5]]); + nodes[5].edges.push(['ϵ', nodes[6]]); + nodes[6].edges.push(['ϵ', nodes[1]]); + nodes[6].edges.push(['ϵ', nodes[7]]); + expect(actual).toEqual(nodes[0]); + }); + + it('Example 3.7.3 (b)', function () { + let actual = regexToNfa('(a*|b*)*'), + nodes: State[] = [ + {type: 'start', edges: [], id: 0}, + {type: '', edges: [], id: 1}, + {type: '', edges: [], id: 2}, + {type: '', edges: [], id: 3}, + {type: '', edges: [], id: 4}, + {type: '', edges: [], id: 5}, + {type: '', edges: [], id: 6}, + {type: '', edges: [], id: 7}, + {type: '', edges: [], id: 8}, + {type: '', edges: [], id: 9}, + {type: '', edges: [], id: 10}, + {type: 'accept', edges: [], id: 11} + ]; + nodes[0].edges.push(['ϵ', nodes[1]]); + nodes[0].edges.push(['ϵ', nodes[11]]); + nodes[1].edges.push(['ϵ', nodes[2]]); + nodes[1].edges.push(['ϵ', nodes[6]]); + nodes[2].edges.push(['ϵ', nodes[3]]); + nodes[2].edges.push(['ϵ', nodes[5]]); + nodes[3].edges.push(['a', nodes[4]]); + nodes[4].edges.push(['ϵ', nodes[3]]); + nodes[4].edges.push(['ϵ', nodes[5]]); + nodes[5].edges.push(['ϵ', nodes[10]]); + nodes[6].edges.push(['ϵ', nodes[7]]); + nodes[6].edges.push(['ϵ', nodes[9]]); + nodes[7].edges.push(['b', nodes[8]]); + nodes[8].edges.push(['ϵ', nodes[7]]); + nodes[8].edges.push(['ϵ', nodes[9]]); + nodes[9].edges.push(['ϵ', nodes[10]]); + nodes[10].edges.push(['ϵ', nodes[1]]); + nodes[10].edges.push(['ϵ', nodes[11]]); + expect(actual).toEqual(nodes[0]); + }); + + it('Example 3.7.3 (c)', function () { + let actual = regexToNfa('((ϵ|a)b*)*'), + nodes: State[] = [ + {type: 'start', edges: [], id: 0}, + {type: '', edges: [], id: 1}, + {type: '', edges: [], id: 2}, + {type: '', edges: [], id: 3}, + {type: '', edges: [], id: 4}, + {type: '', edges: [], id: 5}, + {type: '', edges: [], id: 6}, + {type: '', edges: [], id: 7}, + {type: '', edges: [], id: 8}, + {type: '', edges: [], id: 9}, + {type: 'accept', edges: [], id: 10} + ]; + nodes[0].edges.push(['ϵ', nodes[1]]); + nodes[0].edges.push(['ϵ', nodes[10]]); + nodes[1].edges.push(['ϵ', nodes[2]]); + nodes[1].edges.push(['ϵ', nodes[4]]); + nodes[2].edges.push(['ϵ', nodes[3]]); + nodes[3].edges.push(['ϵ', nodes[6]]); + nodes[4].edges.push(['a', nodes[5]]); + nodes[5].edges.push(['ϵ', nodes[6]]); + nodes[6].edges.push(['ϵ', nodes[7]]); + nodes[6].edges.push(['ϵ', nodes[9]]); + nodes[7].edges.push(['b', nodes[8]]); + nodes[8].edges.push(['ϵ', nodes[7]]); + nodes[8].edges.push(['ϵ', nodes[9]]); + nodes[9].edges.push(['ϵ', nodes[1]]); + nodes[9].edges.push(['ϵ', nodes[10]]); + expect(actual).toEqual(nodes[0]); + }); + + it('Example 3.7.3 (d)', function () { + let actual = regexToNfa('(a|b)*abb(a|b)*'), + nodes: State[] = [ + {type: 'start', edges: [], id: 0}, + {type: '', edges: [], id: 1}, + {type: '', edges: [], id: 2}, + {type: '', edges: [], id: 3}, + {type: '', edges: [], id: 4}, + {type: '', edges: [], id: 5}, + {type: '', edges: [], id: 6}, + {type: '', edges: [], id: 7}, + {type: '', edges: [], id: 8}, + {type: '', edges: [], id: 9}, + {type: '', edges: [], id: 10}, + {type: '', edges: [], id: 11}, + {type: '', edges: [], id: 12}, + {type: '', edges: [], id: 13}, + {type: '', edges: [], id: 14}, + {type: '', edges: [], id: 15}, + {type: '', edges: [], id: 16}, + {type: 'accept', edges: [], id: 17} + ]; + nodes[0].edges.push(['ϵ', nodes[1]]); + nodes[0].edges.push(['ϵ', nodes[7]]); + nodes[1].edges.push(['ϵ', nodes[2]]); + nodes[1].edges.push(['ϵ', nodes[4]]); + nodes[2].edges.push(['a', nodes[3]]); + nodes[3].edges.push(['ϵ', nodes[6]]); + nodes[4].edges.push(['b', nodes[5]]); + nodes[5].edges.push(['ϵ', nodes[6]]); + nodes[6].edges.push(['ϵ', nodes[1]]); + nodes[6].edges.push(['ϵ', nodes[7]]); + nodes[7].edges.push(['a', nodes[8]]); + nodes[8].edges.push(['b', nodes[9]]); + nodes[9].edges.push(['b', nodes[10]]); + nodes[10].edges.push(['ϵ', nodes[11]]); + nodes[10].edges.push(['ϵ', nodes[17]]); + nodes[11].edges.push(['ϵ', nodes[12]]); + nodes[11].edges.push(['ϵ', nodes[14]]); + nodes[12].edges.push(['a', nodes[13]]); + nodes[13].edges.push(['ϵ', nodes[16]]); + nodes[14].edges.push(['b', nodes[15]]); + nodes[15].edges.push(['ϵ', nodes[16]]); + nodes[16].edges.push(['ϵ', nodes[11]]); + nodes[16].edges.push(['ϵ', nodes[17]]); + expect(actual).toEqual(nodes[0]); + }); + + }); }); \ No newline at end of file