@@ -2,6 +2,7 @@ import * as CharSet from "./char-set"
22import * as RE from "./regex"
33import { assert } from "./utils"
44import * as Table from './table'
5+ import * as Graph from './graph'
56
67export type DFA = Readonly < {
78 allStates : Map < number , RE . ExtRegex >
@@ -44,7 +45,7 @@ function regexToDFA(regex: RE.ExtRegex): DFA {
4445 worklist . push ( targetState )
4546 // console.debug('state count: ', allStates.size)
4647 } else {
47- Table . setWith (
48+ Table . set (
4849 sourceState . hash ,
4950 knownState . hash ,
5051 charSet ,
@@ -70,81 +71,54 @@ function regexToDFA(regex: RE.ExtRegex): DFA {
7071 }
7172}
7273
73- type RipStateResult = {
74- predecessors : [ number , RE . StdRegex ] [ ]
75- selfLoop : RE . StdRegex
76- successors : [ number , RE . StdRegex ] [ ]
77- }
78-
79- function ripState ( state : number , transitions : Table . Table < RE . StdRegex > ) : RipStateResult {
80- const selfLoop = Table . get ( state , state , transitions ) ?? RE . epsilon
81-
82- const successorsMap = transitions . get ( state ) ?? new Map < number , RE . StdRegex > ( )
83- // handle self loops separately:
84- successorsMap . delete ( state )
85- const successors = [ ...successorsMap . entries ( ) ]
86- transitions . delete ( state )
87-
88- const predecessors : [ number , RE . StdRegex ] [ ] = [ ]
89- for ( const [ source , transitionsFromSource ] of transitions ) {
90- // handle self loops separately:
91- if ( source !== state ) {
92- const label = transitionsFromSource . get ( state )
93- if ( label !== undefined ) {
94- predecessors . push ( [ source , label ] )
95- transitionsFromSource . delete ( state )
96- }
97- }
98- }
99-
100- return { selfLoop, successors, predecessors }
101- }
102-
10374export function dfaToRegex ( dfa : DFA ) : RE . StdRegex {
104- const transitionsWithRegexLabels = Table . map ( dfa . transitions , RE . literal )
75+ const graph = Graph . create < RE . StdRegex > ( )
76+ for ( const [ source , target , charSet ] of Table . entries ( dfa . transitions ) ) {
77+ Graph . setEdge ( source , target , RE . literal ( charSet ) , graph )
78+ }
10579
10680 const newStartState = - 1
107- Table . set (
81+ Graph . setEdge (
10882 newStartState ,
10983 dfa . startState ,
11084 RE . epsilon ,
111- transitionsWithRegexLabels ,
85+ graph
11286 )
11387
11488 const newFinalState = - 2
11589 for ( const oldFinalState of dfa . finalStates ) {
116- Table . set (
90+ Graph . setEdge (
11791 oldFinalState ,
11892 newFinalState ,
11993 RE . epsilon ,
120- transitionsWithRegexLabels ,
94+ graph
12195 )
12296 }
12397
12498 for ( const state of dfa . allStates . keys ( ) ) {
125- const result = ripState ( state , transitionsWithRegexLabels )
99+ const result = Graph . ripNode ( state , graph )
126100
127101 for ( const [ pred , predLabel ] of result . predecessors ) {
128102 for ( const [ succ , succLabel ] of result . successors ) {
129103 const transitiveLabel = RE . seq ( [
130104 predLabel ,
131- RE . star ( result . selfLoop ) ,
105+ RE . star ( result . selfLoop ?? RE . epsilon ) ,
132106 succLabel ,
133107 ] )
134108
135- Table . setWith (
136- pred ,
109+ Graph . setEdge (
110+ pred ,
137111 succ ,
138112 transitiveLabel ,
139- transitionsWithRegexLabels ,
113+ graph ,
140114 RE . union ,
141115 )
142116 }
143117 }
144118 }
145119
146- assert ( transitionsWithRegexLabels . size === 1 )
147- const transitionsFromNewStart = transitionsWithRegexLabels . get ( newStartState )
120+ assert ( graph . successors . size === 1 )
121+ const transitionsFromNewStart = graph . successors . get ( newStartState )
148122 assert ( transitionsFromNewStart !== undefined )
149123
150124 if ( transitionsFromNewStart . size === 0 ) {
0 commit comments