Browse Source

Move SCCD exceptions from action_lang to their own package

Joeri Exelmans 5 years ago
parent
commit
1c4f323794

+ 1 - 1
src/sccd/action_lang/cmd/prompt.py

@@ -48,7 +48,7 @@ if __name__ == "__main__":
     except (UnexpectedToken, UnexpectedCharacters) as e:
       print(" " + " "*e.column + "^")
       print(type(e).__name__+":", e)
-    except (LarkError, ModelError, SCCDRuntimeException) as e:
+    except (LarkError, ModelStaticError, ModelRuntimeError) as e:
       print(type(e).__name__+":", e)
     except (KeyboardInterrupt, EOFError):
       print()

+ 0 - 3
src/sccd/action_lang/dynamic/exceptions.py

@@ -1,3 +0,0 @@
-
-class SCCDRuntimeException(Exception):
-  pass

+ 1 - 1
src/sccd/action_lang/dynamic/memory.py

@@ -3,7 +3,7 @@ from dataclasses import *
 from sccd.util.bitmap import *
 from sccd.util.debug import *
 from sccd.action_lang.static.scope import *
-from sccd.action_lang.dynamic.exceptions import *
+from sccd.common.exceptions import *
 from sccd.action_lang.static.expression import *
 
 @dataclass(frozen=True)

+ 0 - 3
src/sccd/action_lang/static/exceptions.py

@@ -1,3 +0,0 @@
-# Superclass for all "user errors", errors in the model being loaded.
-class ModelError(Exception):
-  pass

+ 1 - 1
src/sccd/action_lang/static/expression.py

@@ -32,7 +32,7 @@ class MemoryInterface(ABC):
 
 # Thrown if the type checker encountered something illegal.
 # Not to be confused with Python's TypeError exception.
-class StaticTypeError(ModelError):
+class StaticTypeError(ModelStaticError):
     pass
 
 class Expression(ABC):

+ 2 - 2
src/sccd/action_lang/static/scope.py

@@ -3,12 +3,12 @@ from typing import *
 from dataclasses import *
 from inspect import signature
 from sccd.action_lang.static.types import *
-from sccd.action_lang.static.exceptions import *
+from sccd.common.exceptions import *
 import itertools
 import termcolor
 
 
-class ScopeError(ModelError):
+class ScopeError(ModelStaticError):
   def __init__(self, scope, msg):
     super().__init__(msg + '\n\n' + str(scope))
 

+ 7 - 0
src/sccd/common/exceptions.py

@@ -0,0 +1,7 @@
+# Raised when the model is invalid
+class ModelStaticError(Exception):
+  pass
+
+# Raised when an error is encountered during model execution
+class ModelRuntimeError(Exception):
+  pass

+ 2 - 2
src/sccd/statechart/dynamic/memory_snapshot.py

@@ -95,7 +95,7 @@ class SnapshottingStatechartMemory(StatechartMemory):
     if race_conditions:
       variables = self.frame.scope.variables
       # some variable written to twice before refresh
-      raise SCCDRuntimeException("Race condition: More than one transition assigned a new value to variables: %s" % (", ".join(variables[offset].name for offset in bm_items(race_conditions))))
+      raise ModelRuntimeError("Race condition: More than one transition assigned a new value to variables: %s" % (", ".join(variables[offset].name for offset in bm_items(race_conditions))))
 
     self.round_dirty |= self.trans_dirty
     self.trans_dirty = Bitmap() # reset
@@ -120,7 +120,7 @@ class ReadOnlyStatechartMemory(StatechartMemory):
   def store(self, offset: int, value: Any):
     frame, offset = self.delegate._get_frame(offset)
     if frame is self.frame:
-      raise SCCDRuntimeException("Attempt to write to read-only memory.")
+      raise ModelRuntimeError("Attempt to write to read-only memory.")
 
     self.delegate.store(offset, value)
 

+ 2 - 2
src/sccd/statechart/dynamic/round.py

@@ -4,7 +4,7 @@ from sccd.statechart.dynamic.event import *
 from sccd.util.bitmap import *
 from sccd.statechart.static.tree import *
 from sccd.util.debug import *
-from sccd.action_lang.dynamic.exceptions import *
+from sccd.common.exceptions import *
 from sccd.util import timer
 
 @dataclass
@@ -306,7 +306,7 @@ class SuperRoundWithLimit(SuperRound):
 
             subrounds += 1
             if subrounds >= self.limit:
-                raise SCCDRuntimeException("%s: Limit reached! (%d×%s) Possibly a never-ending big step." % (self.name, subrounds, self.subround.name))
+                raise ModelRuntimeError("%s: Limit reached! (%d×%s) Possibly a never-ending big step." % (self.name, subrounds, self.subround.name))
 
             arenas_changed |= changed
             arenas_stabilized |= stabilized

+ 2 - 2
src/sccd/statechart/dynamic/statechart_execution.py

@@ -4,7 +4,7 @@ from sccd.statechart.dynamic.event import *
 from sccd.util.debug import print_debug
 from sccd.util.bitmap import *
 from sccd.action_lang.static.scope import *
-from sccd.action_lang.dynamic.exceptions import *
+from sccd.common.exceptions import *
 from sccd.util import timer
 
 # Set of current states etc.
@@ -141,7 +141,7 @@ class StatechartExecution:
         try:
             state_ids_bitmap = bm_union(self.statechart.tree.state_dict[state_string].opt.state_id_bitmap for state_string in state_strings)
         except KeyError as e:
-            raise SCCDRuntimeException("INSTATE argument %s: invalid state" % str(e)) from e
+            raise ModelRuntimeError("INSTATE argument %s: invalid state" % str(e)) from e
         in_state = bm_has_all(self.configuration, state_ids_bitmap)
         # if in_state:
         #     print_debug("in state"+str(state_strings))

+ 1 - 1
src/sccd/statechart/parser/xml.py

@@ -9,7 +9,7 @@ from sccd.statechart.parser.text import *
 class SkipFile(Exception):
   pass
 
-parse_f = functools.partial(parse, decorate_exceptions=(ModelError,LarkError))
+parse_f = functools.partial(parse, decorate_exceptions=(ModelStaticError,LarkError))
 
 def check_duration_type(type):
   if type != SCCDDuration:

+ 2 - 2
src/sccd/statechart/static/globals.py

@@ -2,7 +2,7 @@ from typing import *
 from sccd.util.namespace import *
 from sccd.util.duration import *
 from sccd.util.debug import *
-from sccd.action_lang.static.exceptions import ModelError
+from sccd.common.exceptions import *
 
 # Global values for all statecharts in a class diagram.
 class Globals:
@@ -30,7 +30,7 @@ class Globals:
     # Ensure delta not too big
     if delta:
       if duration(0) < gcd_delta < delta:
-        raise ModelError("Model contains duration deltas (smallest = %s) not representable with delta of %s." % (str(self.delta), str(delta)))
+        raise ModelStaticError("Model contains duration deltas (smallest = %s) not representable with delta of %s." % (str(self.delta), str(delta)))
       else:
         self.delta = delta
     else:

+ 7 - 5
src/sccd/statechart/static/priority.py

@@ -1,3 +1,4 @@
+from sccd.common.exceptions import *
 from sccd.statechart.static.tree import StateTree, Transition, State, ParallelState
 from sccd.util.graph import strongly_connected_components
 from typing import *
@@ -102,13 +103,14 @@ def get_graph(tree: StateTree, *priorities: Callable[[StateTree], EdgeList]) ->
 # Checks whether the 'priorities' given yield a valid ordering of transitions in the statechart.
 # Returns list of all transitions in statechart, ordered by priority (high -> low).
 def get_total_ordering(tree: StateTree, *priorities: Callable[[StateTree], EdgeList]) -> List[Transition]:
+    # "edges" is a list of pairs (t1, t2) of transitions, where t1 has higher priority than t2.
     edges = get_graph(tree, *priorities)
     scc = strongly_connected_components(edges)
     if len(scc) != len(tree.transition_list):
         # Priority graph contains cycles
         for component in scc:
             if len(component) > 1:
-                raise Exception("Nondeterminism! Cycle among transition priorities: " + str(component))
+                raise ModelStaticError("Cycle among transition priorities: " + str(component))
 
     total_ordering = []
 
@@ -121,18 +123,18 @@ def get_total_ordering(tree: StateTree, *priorities: Callable[[StateTree], EdgeL
             lca = tree.state_list[lca_id]
             # Transitions are orthogonal to each other (LCA is And-state):
             if isinstance(lca, ParallelState):
-                raise Exception("Nondeterminism! No priority between orthogonal transitions: " + str(transitions))
+                raise ModelStaticError("Nondeterminism! No priority between orthogonal transitions: %s, %s" % (t1, t2))
             # They have the same source:
             if t1.source is t2.source:
-                raise Exception("Nondeterminism! No priority between outgoing transitions of same state: %s, %s" % (t1, t2))
+                raise ModelStaticError("Nondeterminism! No priority between outgoing transitions of same state: %s, %s" % (t1, t2))
             # Their source states are ancestors of one another:
             if bm_has(t1.source.opt.ancestors, t2.source.opt.state_id) or bm_has(t2.source.opt.ancestors, t1.source.opt.state_id):
-                raise Exception("Nondeterminism! No priority between ancestral transitions: %s, %s" % (t1, t2))
+                raise ModelStaticError("Nondeterminism! No priority between ancestral transitions: %s, %s" % (t1, t2))
 
     remaining_transitions = set(tree.transition_list)
     remaining_edges = edges
     while len(remaining_edges) > 0:
-        # 1. Find set of highest-priority transitions (= the ones that only have outgoing edges)
+        # 1. Find set of highest-priority transitions (= the ones that have no incoming edges)
         # Such a set must exist, because we've already assured that are no cycles in the graph.
         highs = set()
         lows = set()