99
1010import 'package:meta/meta.dart' ;
1111import 'package:rohd/rohd.dart' ;
12+ import 'package:rohd/src/modules/conditionals/always.dart' ;
1213import 'package:rohd/src/modules/conditionals/ssa.dart' ;
1314
1415/// Represents an some logical assignments or actions that will only happen
@@ -28,20 +29,67 @@ abstract class Conditional {
2829 /// This is used for things like [Sequential] 's pre-tick values.
2930 Map <Logic , LogicValue > _driverValueOverrideMap = {};
3031
32+ /// The [Conditional] that contains this [Conditional] , if there is one.
33+ ///
34+ /// This is only initialized after it's been included inside an [Always] .
35+ late final Conditional ? _parentConditional;
36+
37+ /// The [Always] parent of this [Conditional] , if there is one.
38+ ///
39+ /// This is only initialized after it's been included inside an [Always] .
40+ late final Always _parentAlways;
41+
42+ /// A string representing the hierarchical path to this [Conditional] ,
43+ /// including the module path to the [_parentAlways] and the names of
44+ /// [Conditional] s within that [Always] down to `this` one.
45+ ///
46+ /// If this [Conditional] is not yet registered within an [Always] , or if the
47+ /// [_parentAlways] has not yet been built, this will only include the runtime
48+ /// type of this [Conditional] .
49+ @protected
50+ @internal
51+ String get hierarchyString => [
52+ if (_isRegistered && _parentAlways.hasBuilt)
53+ _parentConditional? .hierarchyString ?? _parentAlways.hierarchicalName,
54+ runtimeType
55+ ].join ('.' );
56+
57+ /// Indicates whether [updateRegistration] has been called on this
58+ /// [Conditional] already.
59+ bool _isRegistered = false ;
60+
61+ /// Updates registration information for the [Conditional] , passed down from
62+ /// the parent [Always] or [Conditional] .
63+ ///
3164 /// Updates the values of [_assignedReceiverToOutputMap] and
3265 /// [_assignedDriverToInputMap] and passes them down to all sub-[Conditional] s
3366 /// as well.
3467 @internal
35- void updateAssignmentMaps (
36- Map <Logic , Logic > assignedReceiverToOutputMap,
37- Map <Logic , Logic > assignedDriverToInputMap,
38- ) {
68+ void updateRegistration ({
69+ required Map <Logic , Logic > assignedReceiverToOutputMap,
70+ required Map <Logic , Logic > assignedDriverToInputMap,
71+ required Conditional ? parentConditional,
72+ required Always parentAlways,
73+ }) {
74+ if (_isRegistered) {
75+ throw InvalidConditionalException ('Conditional $this is already included'
76+ ' as part of another block: $hierarchyString ' );
77+ }
78+
3979 _assignedReceiverToOutputMap = assignedReceiverToOutputMap;
4080 _assignedDriverToInputMap = assignedDriverToInputMap;
81+ _parentConditional = parentConditional;
82+ _parentAlways = parentAlways;
4183 for (final conditional in conditionals) {
42- conditional.updateAssignmentMaps (
43- assignedReceiverToOutputMap, assignedDriverToInputMap);
84+ conditional.updateRegistration (
85+ assignedReceiverToOutputMap: assignedReceiverToOutputMap,
86+ assignedDriverToInputMap: assignedDriverToInputMap,
87+ parentConditional: this ,
88+ parentAlways: parentAlways,
89+ );
4490 }
91+
92+ _isRegistered = true ;
4593 }
4694
4795 /// Updates the value of [_driverValueOverrideMap] and passes it down to all
@@ -204,7 +252,7 @@ abstract class Conditional {
204252 receiverOutput.put (LogicValue .x);
205253 }
206254 } on WriteAfterReadException catch (e) {
207- throw e.cloneWithAddedPath (' at (driving X) $this ' );
255+ throw e.cloneWithAddedPath (' at (driving X) $this [$ hierarchyString ] ' );
208256 }
209257
210258 drivenSignals? .addAll (receivers);
0 commit comments