statechart.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. from enum import *
  2. from dataclasses import *
  3. from typing import *
  4. import itertools
  5. from sccd.statechart.static.tree import *
  6. from sccd.action_lang.static.scope import *
  7. class SemanticAspect:
  8. def __str__(self):
  9. # Override default: only print field, not the type (e.g. "TAKE_ONE" instead of "BigStepMaximality.TAKE_ONE")
  10. return self.name
  11. class BigStepMaximality(SemanticAspect, Enum):
  12. TAKE_ONE = auto()
  13. TAKE_MANY = auto()
  14. SYNTACTIC = auto()
  15. class ComboStepMaximality(SemanticAspect, Enum):
  16. COMBO_TAKE_ONE = auto()
  17. COMBO_TAKE_MANY = auto()
  18. class InternalEventLifeline(SemanticAspect, Enum):
  19. QUEUE = auto()
  20. NEXT_COMBO_STEP = auto()
  21. NEXT_SMALL_STEP = auto()
  22. REMAINDER = auto()
  23. SAME = auto()
  24. class InputEventLifeline(SemanticAspect, Enum):
  25. WHOLE = auto()
  26. FIRST_COMBO_STEP = auto()
  27. FIRST_SMALL_STEP = auto()
  28. class MemoryProtocol(SemanticAspect, Enum):
  29. BIG_STEP = auto()
  30. COMBO_STEP = auto()
  31. SMALL_STEP = auto()
  32. # NONE = auto()
  33. class Priority(SemanticAspect, Enum):
  34. SOURCE_PARENT = auto()
  35. SOURCE_CHILD = auto()
  36. ARENA_PARENT = auto()
  37. ARENA_CHILD = auto()
  38. class Concurrency(SemanticAspect, Enum):
  39. SINGLE = auto()
  40. MANY = auto()
  41. _T = TypeVar('_T', bound=SemanticAspect)
  42. SemanticChoice = Union[_T, List[_T]]
  43. @dataclass
  44. class SemanticConfiguration:
  45. # All semantic aspects and their default values.
  46. # Every field can be set to a list of multiple options, or just a value.
  47. # The following is the default configuration:
  48. big_step_maximality: SemanticChoice[BigStepMaximality] = BigStepMaximality.TAKE_MANY
  49. combo_step_maximality: SemanticChoice[ComboStepMaximality] = ComboStepMaximality.COMBO_TAKE_ONE
  50. internal_event_lifeline: SemanticChoice[InternalEventLifeline] = InternalEventLifeline.NEXT_COMBO_STEP
  51. input_event_lifeline: SemanticChoice[InputEventLifeline] = InputEventLifeline.FIRST_COMBO_STEP
  52. enabledness_memory_protocol: SemanticChoice[MemoryProtocol] = MemoryProtocol.COMBO_STEP
  53. assignment_memory_protocol: SemanticChoice[MemoryProtocol] = MemoryProtocol.COMBO_STEP
  54. priority: SemanticChoice[Priority] = Priority.SOURCE_PARENT
  55. concurrency: SemanticChoice[Concurrency] = Concurrency.SINGLE
  56. def __str__(self):
  57. s = ""
  58. for f in fields(self):
  59. s += "\n %s: %s" % (f.name, getattr(self, f.name))
  60. return s
  61. @classmethod
  62. def get_fields(cls) -> Iterator[Tuple[str, SemanticAspect]]:
  63. return ((f.name, type(f.default)) for f in fields(cls))
  64. # Whether multiple options are set for any aspect.
  65. def has_multiple_variants(self) -> bool:
  66. for f in fields(self):
  67. if isinstance(getattr(self, f.name), list):
  68. return True
  69. return False
  70. # Get all possible combinations for aspects with multiple options (as a list) set.
  71. # Calling has_multiple_variants on resulting objects will return False.
  72. def generate_variants(self) -> List['SemanticConfiguration']:
  73. my_fields = fields(self)
  74. chosen_options = ([item] if not isinstance(item,list) else item for item in (getattr(self, f.name) for f in my_fields))
  75. variants = itertools.product(*chosen_options)
  76. return [SemanticConfiguration(**{f.name: o for f,o in zip(my_fields, variant)}) for variant in variants]
  77. @dataclass
  78. class Statechart(Freezable):
  79. __slots__ = ["semantics", "scope", "datamodel", "internal_events", "internally_raised_events", "inport_events", "event_outport", "tree"]
  80. def __init__(self, semantics: SemanticConfiguration, scope: Scope, datamodel: Optional[Block], internal_events: Bitmap, internally_raised_events: Bitmap, inport_events: Dict[str, Set[int]], event_outport: Dict[str, str], tree: StateTree):
  81. super().__init__()
  82. # Semantic configuration for statechart execution
  83. self.semantics: SemanticConfiguration = semantics
  84. # Instance scope, the set of variable names (and their types and offsets in memory) that belong to the statechart
  85. self.scope: Scope = scope
  86. # Block of statements setting up the datamodel (variables in instance scope)
  87. self.datamodel: Optional[Block] = datamodel
  88. # Union of internally raised and input events. Basically all the events that a transition could be triggered by.
  89. self.internal_events: Bitmap = internal_events
  90. # All internally raised events in the statechart, may overlap with input events, as an event can be both an input event and internally raised.
  91. self.internally_raised_events: Bitmap = internally_raised_events
  92. # Mapping from inport to set of event IDs - currently unused
  93. self.inport_events: Dict[str, Bitmap] = inport_events
  94. # Mapping from event name to outport
  95. self.event_outport: Dict[str, str] = event_outport
  96. self.tree: StateTree = tree