Skip to content

Commit

Permalink
feat: add connectable base in/out signals
Browse files Browse the repository at this point in the history
  • Loading branch information
glencoe committed Feb 18, 2023
1 parent 510c1c7 commit 7ad67f9
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 0 deletions.
52 changes: 52 additions & 0 deletions elasticai/creator/tests/unit/vhdl/test_signal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import unittest

from elasticai.creator.vhdl.signal import BaseInSignal, Identifiable


class MyOutSignal(Identifiable):
def id(self) -> str:
return "my_out_signal"


class AlwaysMatchingSignal(BaseInSignal):
def __init__(self):
super().__init__("always_matching_signal")

def definition(self) -> str:
return "empty def"

def matches(self, other: Identifiable) -> bool:
return True


class NeverMatchingSignal(BaseInSignal):
def definition(self) -> str:
return "empty_definition"

def __init__(self):
super().__init__("in_signal")

def matches(self, other: Identifiable) -> bool:
return False


class SignalTestCase(unittest.TestCase):
def test_never_matching_signal_is_missing_inputs_after_connect(self):
in_signal = NeverMatchingSignal()
in_signal.connect(MyOutSignal())
self.assertTrue(in_signal.is_missing_inputs())

def test_always_matching_signal_is_not_missing_inputs_after_connect(self):
in_signal = AlwaysMatchingSignal()
in_signal.connect(MyOutSignal())
self.assertFalse(in_signal.is_missing_inputs())

def test_code_produces_correct_vhdl_line_after_connecting(self):
in_signal = AlwaysMatchingSignal()
out_signal = MyOutSignal()
in_signal.connect(out_signal)
self.assertEqual([f"{in_signal.id()} <= {out_signal.id()}"], in_signal.code())


if __name__ == "__main__":
unittest.main()
16 changes: 16 additions & 0 deletions elasticai/creator/vhdl/connectable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from abc import abstractmethod
from typing import Any, Protocol, TypeVar

T_Connectable_contra = TypeVar(
"T_Connectable_contra", bound="Connectable", contravariant=True
)


class Connectable(Protocol):
@abstractmethod
def connect(self: T_Connectable_contra, other: Any):
...

@abstractmethod
def is_missing_inputs(self) -> bool:
...
27 changes: 27 additions & 0 deletions elasticai/creator/vhdl/graph/typing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from abc import abstractmethod
from typing import Iterable, Protocol, Reversible, TypeVar

T_Node_co = TypeVar("T_Node_co", bound="Node", covariant=True)


class Graph(Protocol[T_Node_co]):
@property
@abstractmethod
def nodes(self) -> Reversible[T_Node_co]:
...


T_Node = TypeVar("T_Node", bound="Node")
T_co = TypeVar("T_co", covariant=True)


class Node(Protocol[T_co]):
@property
@abstractmethod
def children(self: "Node[T_co]") -> Iterable["Node[T_co]"]:
...

@property
@abstractmethod
def parents(self: "Node[T_co]") -> Iterable["Node[T_co]"]:
...
81 changes: 81 additions & 0 deletions elasticai/creator/vhdl/signal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from abc import ABC, abstractmethod
from typing import (
Any,
ClassVar,
Collection,
Optional,
Protocol,
TypeVar,
runtime_checkable,
)

from elasticai.creator.vhdl.connectable import Connectable


class SignalProvider(Protocol):
def in_signals(self) -> Collection["InSignal"]:
...

def out_signals(self) -> Collection["OutSignal"]:
...


T_Signal_contra = TypeVar("T_Signal_contra", bound="Signal", contravariant=True)


class Identifiable(Protocol):
@abstractmethod
def id(self) -> str:
...


class Signal(Protocol):
@abstractmethod
def definition(self) -> str:
...


@runtime_checkable
class InSignal(Signal, Connectable, Protocol):
@abstractmethod
def code(self) -> list[str]:
...


class NullIdentifiable(Identifiable):
def id(self) -> str:
return ""


class BaseInSignal(InSignal, ABC):
_NULL_SIGNAL: ClassVar[Identifiable] = NullIdentifiable()

def __init__(self, id: str):
self._out_signal: Identifiable = self._NULL_SIGNAL
self._id = id

def code(self) -> list[str]:
return [f"{self.id()} <= {self._out_signal.id()}"]

@abstractmethod
def definition(self) -> str:
return ""

def id(self) -> str:
return self._id

def is_missing_inputs(self) -> bool:
return self._out_signal == self._NULL_SIGNAL

@abstractmethod
def matches(self, other: Any) -> bool:
...

def connect(self, other: Identifiable) -> None:
if self.matches(other):
self._out_signal = other


@runtime_checkable
class OutSignal(Signal, Protocol):
...

0 comments on commit 7ad67f9

Please sign in to comment.