22Representation of a recursive automaton
33"""
44
5- from typing import AbstractSet , Union
5+ from typing import Dict , Set , AbstractSet , Optional , Hashable , Any
66
7- from pyformlang .finite_automaton import DeterministicFiniteAutomaton
8- from pyformlang .finite_automaton .symbol import Symbol
7+ from pyformlang .finite_automaton import Symbol
98from pyformlang .finite_automaton .utils import to_symbol
109from pyformlang .regular_expression import Regex
1110from pyformlang .cfg import Epsilon
1211
13- from pyformlang . rsa .box import Box
12+ from .box import Box
1413
1514
1615class RecursiveAutomaton :
@@ -29,15 +28,15 @@ class RecursiveAutomaton:
2928
3029 def __init__ (self ,
3130 start_box : Box ,
32- boxes : AbstractSet [Box ]):
33- self ._nonterminal_to_box = {}
31+ boxes : AbstractSet [Box ]) -> None :
32+ self ._nonterminal_to_box : Dict [Symbol , Box ] = {}
33+ self ._start_nonterminal = start_box .nonterminal
3434 if start_box not in boxes :
35- self ._nonterminal_to_box [to_symbol (start_box .nonterminal )] = start_box
36- self ._start_nonterminal = to_symbol (start_box .nonterminal )
35+ self ._nonterminal_to_box [start_box .nonterminal ] = start_box
3736 for box in boxes :
38- self ._nonterminal_to_box [to_symbol ( box .nonterminal ) ] = box
37+ self ._nonterminal_to_box [box .nonterminal ] = box
3938
40- def get_box_by_nonterminal (self , nonterminal : Union [ Symbol , str ]) :
39+ def get_box_by_nonterminal (self , nonterminal : Hashable ) -> Optional [ Box ] :
4140 """
4241 Box by nonterminal
4342
@@ -53,50 +52,35 @@ def get_box_by_nonterminal(self, nonterminal: Union[Symbol, str]):
5352 """
5453
5554 nonterminal = to_symbol (nonterminal )
56- if nonterminal in self ._nonterminal_to_box :
57- return self ._nonterminal_to_box [nonterminal ]
55+ return self ._nonterminal_to_box .get (nonterminal , None )
5856
59- return None
60-
61- def get_number_boxes (self ):
57+ def get_number_boxes (self ) -> int :
6258 """ Size of set of boxes """
63-
6459 return len (self ._nonterminal_to_box )
6560
66- def to_dot (self ):
67- """ Create dot representation of recursive automaton """
68- dot_string = 'digraph "" {'
69- for box in self ._nonterminal_to_box .values ():
70- dot_string += f'\n { box .to_subgraph_dot ()} '
71- dot_string += "\n }"
72- return dot_string
73-
7461 @property
75- def nonterminals (self ) -> set :
62+ def nonterminals (self ) -> Set [ Symbol ] :
7663 """ The set of nonterminals """
77-
7864 return set (self ._nonterminal_to_box .keys ())
7965
8066 @property
81- def boxes (self ) -> dict :
67+ def boxes (self ) -> Set [ Box ] :
8268 """ The set of boxes """
83-
84- return self ._nonterminal_to_box
69+ return set (self ._nonterminal_to_box .values ())
8570
8671 @property
8772 def start_nonterminal (self ) -> Symbol :
8873 """ The start nonterminal """
89-
9074 return self ._start_nonterminal
9175
9276 @property
93- def start_box (self ):
77+ def start_box (self ) -> Box :
9478 """ The start box """
95-
96- return self .boxes [self .start_nonterminal ]
79+ return self ._nonterminal_to_box [self .start_nonterminal ]
9780
9881 @classmethod
99- def from_regex (cls , regex : Regex , start_nonterminal : Union [Symbol , str ]):
82+ def from_regex (cls , regex : Regex , start_nonterminal : Hashable ) \
83+ -> "RecursiveAutomaton" :
10084 """ Create a recursive automaton from regular expression
10185
10286 Parameters
@@ -116,14 +100,17 @@ def from_regex(cls, regex: Regex, start_nonterminal: Union[Symbol, str]):
116100 return RecursiveAutomaton (box , {box })
117101
118102 @classmethod
119- def from_ebnf (cls , text , start_nonterminal : Union [Symbol , str ] = Symbol ("S" )):
120- """ Create a recursive automaton from ebnf (ebnf = Extended Backus-Naur Form)
103+ def from_ebnf (cls , text : str , start_nonterminal : Hashable = Symbol ("S" )) \
104+ -> "RecursiveAutomaton" :
105+ """ Create a recursive automaton from ebnf \
106+ (ebnf = Extended Backus-Naur Form)
121107
122108 Parameters
123109 -----------
124110 text : str
125111 The text of transform
126- start_nonterminal : :class:`~pyformlang.finite_automaton.Symbol` | str, optional
112+ start_nonterminal : \
113+ :class:`~pyformlang.finite_automaton.Symbol` | str, optional
127114 The start nonterminal, S by default
128115
129116 Returns
@@ -132,7 +119,7 @@ def from_ebnf(cls, text, start_nonterminal: Union[Symbol, str] = Symbol("S")):
132119 The new recursive automaton built from context-free grammar
133120 """
134121 start_nonterminal = to_symbol (start_nonterminal )
135- productions = {}
122+ productions : Dict [ Hashable , str ] = {}
136123 boxes = set ()
137124 nonterminals = set ()
138125 for production in text .splitlines ():
@@ -160,7 +147,7 @@ def from_ebnf(cls, text, start_nonterminal: Union[Symbol, str] = Symbol("S")):
160147 start_box = Box (start_box_dfa , start_nonterminal )
161148 return RecursiveAutomaton (start_box , boxes )
162149
163- def is_equals_to (self , other ) :
150+ def is_equal_to (self , other : "RecursiveAutomaton" ) -> bool :
164151 """
165152 Check whether two recursive automata are equals by boxes.
166153 Not equivalency in terms of formal languages theory, just mapping boxes
@@ -175,9 +162,17 @@ def is_equals_to(self, other):
175162 are_equivalent : bool
176163 Whether the two recursive automata are equals or not
177164 """
165+ return self .boxes == other .boxes
166+
167+ def __eq__ (self , other : Any ) -> bool :
178168 if not isinstance (other , RecursiveAutomaton ):
179169 return False
180- return self .boxes == other . boxes
170+ return self .is_equal_to ( other )
181171
182- def __eq__ (self , other ):
183- return self .is_equals_to (other )
172+ def to_dot (self ) -> str :
173+ """ Create dot representation of recursive automaton """
174+ dot_string = 'digraph "" {'
175+ for box in self ._nonterminal_to_box .values ():
176+ dot_string += f'\n { box .to_subgraph_dot ()} '
177+ dot_string += "\n }"
178+ return dot_string
0 commit comments