Skip to content

Commit

Permalink
unify terminal representations
Browse files Browse the repository at this point in the history
  • Loading branch information
bygu4 committed Dec 29, 2024
1 parent 5b5007d commit 510e04b
Show file tree
Hide file tree
Showing 15 changed files with 70 additions and 102 deletions.
55 changes: 28 additions & 27 deletions pyformlang/cfg/cfg_variable_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,56 @@

from typing import Dict, List, AbstractSet, Tuple, Optional, Hashable

from ..objects.cfg_objects import Variable, CFGObjectConvertible
from ..objects.formal_object import FormalObject
from ..objects.cfg_objects import Variable


class CFGVariableConverter:
"""A CFG Variable Converter"""

def __init__(self,
states: AbstractSet[CFGObjectConvertible],
stack_symbols: AbstractSet[CFGObjectConvertible]) -> None:
states: AbstractSet[FormalObject],
stack_symbols: AbstractSet[FormalObject]) -> None:
self._counter = 0
self._inverse_states_d: Dict[CFGObjectConvertible, int] = {}
self._inverse_states_d: Dict[FormalObject, int] = {}
self._counter_state = 0
for self._counter_state, state in enumerate(states):
self._inverse_states_d[state] = self._counter_state
state.index_cfg_converter = self._counter_state
state.index = self._counter_state
self._counter_state += 1
self._inverse_stack_symbol_d: Dict[CFGObjectConvertible, int] = {}
self._inverse_stack_symbol_d: Dict[FormalObject, int] = {}
self._counter_symbol = 0
for self._counter_symbol, symbol in enumerate(stack_symbols):
self._inverse_stack_symbol_d[symbol] = self._counter_symbol
symbol.index_cfg_converter = self._counter_symbol
symbol.index = self._counter_symbol
self._counter_symbol += 1
self._conversions: List[List[List[Tuple[bool, Optional[Variable]]]]] \
= [[[(False, None) for _ in range(len(states))]
for _ in range(len(stack_symbols))] for _ in
range(len(states))]

def _get_state_index(self, state: CFGObjectConvertible) -> int:
def _get_state_index(self, state: FormalObject) -> int:
"""Get the state index"""
if state.index_cfg_converter is None:
if state.index is None:
if state not in self._inverse_states_d:
self._inverse_states_d[state] = self._counter_state
self._counter_state += 1
state.index_cfg_converter = self._inverse_states_d[state]
return state.index_cfg_converter
state.index = self._inverse_states_d[state]
return state.index

def _get_symbol_index(self, symbol: CFGObjectConvertible) -> int:
def _get_symbol_index(self, symbol: FormalObject) -> int:
"""Get the symbol index"""
if symbol.index_cfg_converter is None:
if symbol.index is None:
if symbol not in self._inverse_stack_symbol_d:
self._inverse_stack_symbol_d[symbol] = self._counter_symbol
self._counter_symbol += 1
symbol.index_cfg_converter = self._inverse_stack_symbol_d[symbol]
return symbol.index_cfg_converter
symbol.index = self._inverse_stack_symbol_d[symbol]
return symbol.index

def to_cfg_combined_variable(self,
state0: CFGObjectConvertible,
stack_symbol: CFGObjectConvertible,
state1: CFGObjectConvertible) -> Variable:
state0: FormalObject,
stack_symbol: FormalObject,
state1: FormalObject) -> Variable:
""" Conversion used in the to_pda method """
i_stack_symbol, i_state0, i_state1 = self._get_indexes(
stack_symbol, state0, state1)
Expand All @@ -74,19 +75,19 @@ def _create_new_variable(self,
return temp

def set_valid(self,
state0: CFGObjectConvertible,
stack_symbol: CFGObjectConvertible,
state1: CFGObjectConvertible) -> None:
state0: FormalObject,
stack_symbol: FormalObject,
state1: FormalObject) -> None:
"""Set valid"""
i_stack_symbol, i_state0, i_state1 = self._get_indexes(
stack_symbol, state0, state1)
prev = self._conversions[i_state0][i_stack_symbol][i_state1]
self._conversions[i_state0][i_stack_symbol][i_state1] = (True, prev[1])

def is_valid_and_get(self,
state0: CFGObjectConvertible,
stack_symbol: CFGObjectConvertible,
state1: CFGObjectConvertible) -> Optional[Variable]:
state0: FormalObject,
stack_symbol: FormalObject,
state1: FormalObject) -> Optional[Variable]:
"""Check if valid and get"""
i_state0 = self._get_state_index(state0)
i_stack_symbol = self._get_symbol_index(stack_symbol)
Expand All @@ -102,9 +103,9 @@ def is_valid_and_get(self,
return current[1]

def _get_indexes(self,
stack_symbol: CFGObjectConvertible,
state0: CFGObjectConvertible,
state1: CFGObjectConvertible) \
stack_symbol: FormalObject,
state0: FormalObject,
state1: FormalObject) \
-> Tuple[int, int, int]:
i_state0 = self._get_state_index(state0)
i_stack_symbol = self._get_symbol_index(stack_symbol)
Expand Down
2 changes: 1 addition & 1 deletion pyformlang/cfg/tests/test_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ def test_eq(self):
assert "A" == Terminal("A")
assert Variable(1) == 1
assert Epsilon() == FAEpsilon()
assert Terminal("ABC") != Symbol("ABC")
assert Terminal("ABC") == Symbol("ABC")
assert State("S") != Variable("S")
3 changes: 2 additions & 1 deletion pyformlang/objects/base_epsilon.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
from typing import Any

from .formal_object import FormalObject
from .base_terminal import BaseTerminal

EPSILON_SYMBOLS = ["epsilon", "ɛ"]


class BaseEpsilon(FormalObject):
class BaseEpsilon(BaseTerminal):
""" An epsilon transition
Examples
Expand Down
24 changes: 24 additions & 0 deletions pyformlang/objects/base_terminal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
""" General terminal representation """

from typing import Any
from abc import abstractmethod

from .formal_object import FormalObject


class BaseTerminal(FormalObject):
""" General terminal representation """

def __eq__(self, other: Any) -> bool:
if isinstance(other, BaseTerminal):
return self.value == other.value
if isinstance(other, FormalObject):
return False
return self.value == other

def __hash__(self) -> int:
return super().__hash__()

@abstractmethod
def __repr__(self):
raise NotImplementedError
4 changes: 1 addition & 3 deletions pyformlang/objects/cfg_objects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@
from .terminal import Terminal
from .epsilon import Epsilon
from .production import Production
from .cfg_object_convertible import CFGObjectConvertible


__all__ = ["CFGObject",
"Variable",
"Terminal",
"Epsilon",
"Production",
"CFGObjectConvertible"]
"Production"]
4 changes: 2 additions & 2 deletions pyformlang/objects/cfg_objects/cfg_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

from abc import abstractmethod

from .cfg_object_convertible import CFGObjectConvertible
from ..formal_object import FormalObject


class CFGObject(CFGObjectConvertible):
class CFGObject(FormalObject):
""" An object in a CFG
Parameters
Expand Down
18 changes: 0 additions & 18 deletions pyformlang/objects/cfg_objects/cfg_object_convertible.py

This file was deleted.

16 changes: 2 additions & 14 deletions pyformlang/objects/cfg_objects/terminal.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
""" A terminal in a CFG """

from typing import Any

from .cfg_object import CFGObject
from ..formal_object import FormalObject
from ..base_terminal import BaseTerminal


class Terminal(CFGObject):
class Terminal(BaseTerminal, CFGObject):
""" A terminal in a CFG """

def __eq__(self, other: Any) -> bool:
if isinstance(other, Terminal):
return self.value == other.value
if isinstance(other, FormalObject):
return False
return self.value == other

def __hash__(self) -> int:
return super().__hash__()

def __repr__(self) -> str:
return f"Terminal({self})"

Expand Down
3 changes: 1 addition & 2 deletions pyformlang/objects/finite_automaton_objects/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
from typing import Any

from .finite_automaton_object import FiniteAutomatonObject
from ..cfg_objects import CFGObjectConvertible
from ..formal_object import FormalObject


class State(CFGObjectConvertible, FiniteAutomatonObject):
class State(FiniteAutomatonObject):
""" A state in a finite automaton
Parameters
Expand Down
16 changes: 2 additions & 14 deletions pyformlang/objects/finite_automaton_objects/symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
This module describe a symbol in a finite automaton.
"""

from typing import Any

from .finite_automaton_object import FiniteAutomatonObject
from ..formal_object import FormalObject
from ..base_terminal import BaseTerminal


class Symbol(FiniteAutomatonObject):
class Symbol(BaseTerminal, FiniteAutomatonObject):
""" A symbol in a finite automaton
Parameters
Expand All @@ -23,15 +21,5 @@ class Symbol(FiniteAutomatonObject):
A
"""

def __eq__(self, other: Any) -> bool:
if isinstance(other, Symbol):
return self.value == other.value
if isinstance(other, FormalObject):
return False
return self.value == other

def __hash__(self) -> int:
return super().__hash__()

def __repr__(self) -> str:
return f"Symbol({self})"
3 changes: 2 additions & 1 deletion pyformlang/objects/formal_object.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
""" General object representation """

from typing import Hashable, Any
from typing import Hashable, Optional, Any
from abc import abstractmethod


Expand All @@ -10,6 +10,7 @@ class FormalObject:
def __init__(self, value: Hashable) -> None:
self._value = value
self._hash = None
self.index: Optional[int] = None

@property
def value(self) -> Hashable:
Expand Down
3 changes: 1 addition & 2 deletions pyformlang/objects/pda_objects/stack_symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
from typing import Any

from .symbol import Symbol
from ..cfg_objects import CFGObjectConvertible
from ..formal_object import FormalObject


class StackSymbol(CFGObjectConvertible, Symbol):
class StackSymbol(Symbol):
""" A StackSymbol in a pushdown automaton
Parameters
Expand Down
3 changes: 1 addition & 2 deletions pyformlang/objects/pda_objects/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
from typing import Any

from .pda_object import PDAObject
from ..cfg_objects import CFGObjectConvertible
from ..formal_object import FormalObject


class State(CFGObjectConvertible, PDAObject):
class State(PDAObject):
""" A State in a pushdown automaton
Parameters
Expand Down
16 changes: 2 additions & 14 deletions pyformlang/objects/pda_objects/symbol.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
""" A Symbol in a pushdown automaton """

from typing import Any

from .pda_object import PDAObject
from ..formal_object import FormalObject
from ..base_terminal import BaseTerminal


class Symbol(PDAObject):
class Symbol(BaseTerminal, PDAObject):
""" A Symbol in a pushdown automaton
Parameters
Expand All @@ -16,15 +14,5 @@ class Symbol(PDAObject):
"""

def __eq__(self, other: Any) -> bool:
if isinstance(other, Symbol):
return self.value == other.value
if isinstance(other, FormalObject):
return False
return self.value == other

def __hash__(self) -> int:
return super().__hash__()

def __repr__(self) -> str:
return f"Symbol({self})"
2 changes: 1 addition & 1 deletion pyformlang/pda/tests/test_pda.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ def test_object_eq(self):
assert Symbol("A") != StackSymbol("A")
assert StackSymbol("ABC") != Symbol("ABC")
assert State("ABC") != FAState("ABC")
assert Symbol("s") != Terminal("s")
assert Symbol("s") == Terminal("s")

def test_contains(self, pda_example: PDA):
""" Tests the transition containment checks """
Expand Down

0 comments on commit 510e04b

Please sign in to comment.