sysmlpy 0.80.0__tar.gz → 0.81.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/PKG-INFO +1 -1
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/pyproject.toml +1 -1
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/__init__.py +1 -1
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/__main__.py +9 -2
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/boxes_view.py +76 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/sim.py +191 -14
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/LICENSE +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/README.md +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/README.md +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/SysMLv2Parser.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr_parser.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr_visitor.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/definition.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/diff.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/evaluator.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/examples/attribute_values.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/examples/part_attributes.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/examples/tuples_sequences.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/formatting.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/README.md +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.g4 +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.g4 +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/desc.xml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/examples/camera.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/examples/toaster-system.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/examples/vehicle-model.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/antlr4/pom.xml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/grammar/classes.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/interchange.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/LICENSE +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/README.md +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/__init__.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Analysis/AnalysisTooling.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Analysis/TradeStudies.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Cause and Effect/CausationConnections.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Geometry/ShapeItems.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Geometry/SpatialItems.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Metadata/ImageMetadata.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Metadata/ParametersOfInterestMetadata.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Metadata/RiskMetadata.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQ.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAtomicNuclear.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCharacteristicNumbers.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQChemistryMolecular.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCondensedMatter.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQElectromagnetism.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQInformation.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQThermodynamics.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementRefCalculations.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementReferences.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/QuantityCalculations.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/SI.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/TensorCalculations.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/USCustomaryUnits.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/VectorCalculations.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Requirement Derivation/DerivationConnections.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Requirement Derivation/RequirementDerivation.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/Base.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/BaseFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/BooleanFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/Clocks.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/CollectionFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/Collections.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/ComplexFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/ControlFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/ControlPerformances.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/DataFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/IntegerFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/KerML.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/Links.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/Metaobjects.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/NaturalFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/NumericalFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/Objects.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/Observation.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/OccurrenceFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/Occurrences.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/Performances.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/RationalFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/RealFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/ScalarFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/ScalarValues.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/SequenceFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/SpatialFrames.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/StatePerformances.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/StringFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/Transfers.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/TransitionPerformances.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/TrigFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/Triggers.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/VectorFunctions.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/VectorValues.kerml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Actions.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Allocations.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/AnalysisCases.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Attributes.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Calculations.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Cases.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Connections.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Constraints.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Flows.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Interfaces.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Items.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Metadata.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Parts.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Ports.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Requirements.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/StandardViewDefinitions.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/States.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/SysML.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/UseCases.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/VerificationCases.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/systems/Views.sysml +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/lsp/__init__.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/lsp/__main__.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/lsp/protocol.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/lsp/server.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/lsp/stdio.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/navigate.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/plantuml.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/project.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/semantic.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/spreadsheet.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/store.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/traceability.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/us_customary_units.txt +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/usage.py +0 -0
- {sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/validator.py +0 -0
|
@@ -34,7 +34,7 @@ __all__ = [
|
|
|
34
34
|
"render_state_transition_view_svg", "boxes_view",
|
|
35
35
|
]
|
|
36
36
|
__author__ = "Jon Fox"
|
|
37
|
-
__version__ = "0.
|
|
37
|
+
__version__ = "0.81.0"
|
|
38
38
|
|
|
39
39
|
from sysmlpy.usage import (
|
|
40
40
|
Item, Attribute, Part, Port, Action, Reference, UseCase, Requirement, Interface, Message,
|
|
@@ -567,10 +567,12 @@ def cmd_sim(args) -> int:
|
|
|
567
567
|
name, _, raw = spec.partition("=")
|
|
568
568
|
values[name.strip()] = _parse_eval_value(raw)
|
|
569
569
|
|
|
570
|
+
deep = bool(getattr(args, "deep_history", False))
|
|
570
571
|
script = [t.strip() for t in (args.run or "").split(";") if t.strip()]
|
|
571
572
|
try:
|
|
572
573
|
from sysmlpy.sim import StateSimulator, SimulationError
|
|
573
|
-
sim = StateSimulator(model, focus=args.focus, values=values
|
|
574
|
+
sim = StateSimulator(model, focus=args.focus, values=values,
|
|
575
|
+
deep_history=deep)
|
|
574
576
|
except (ImportError, SimulationError) as e:
|
|
575
577
|
print(f"Simulation error: {e}", file=sys.stderr)
|
|
576
578
|
return 2
|
|
@@ -582,7 +584,7 @@ def cmd_sim(args) -> int:
|
|
|
582
584
|
print(f"{trigger}: {'fired' if fired else 'blocked'} "
|
|
583
585
|
f"-> {sim.state!r}")
|
|
584
586
|
return 0
|
|
585
|
-
run_tui(model, focus=args.focus, values=values)
|
|
587
|
+
run_tui(model, focus=args.focus, values=values, deep_history=deep)
|
|
586
588
|
return 0
|
|
587
589
|
|
|
588
590
|
|
|
@@ -967,6 +969,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
967
969
|
"-l", "--library",
|
|
968
970
|
help="Path to SysML v2 library files to use for parsing",
|
|
969
971
|
)
|
|
972
|
+
p_sim.add_argument(
|
|
973
|
+
"--deep-history", action="store_true",
|
|
974
|
+
help="History pseudostates restore the deepest visited state "
|
|
975
|
+
"(default: one level, shallow)",
|
|
976
|
+
)
|
|
970
977
|
p_sim.set_defaults(func=cmd_sim)
|
|
971
978
|
|
|
972
979
|
# -- xlsx (v0.66.0, Goal 7) -------------------------------------------------
|
|
@@ -380,6 +380,44 @@ def _top_member(item, target):
|
|
|
380
380
|
return None
|
|
381
381
|
|
|
382
382
|
|
|
383
|
+
def _pseudostate_kind(usage: dict) -> Optional[str]:
|
|
384
|
+
"""Classify a usage inside a state body as a pseudostate marker.
|
|
385
|
+
|
|
386
|
+
Recognizes history pseudostates: ``state h : HistoryUsage;`` /
|
|
387
|
+
``h : HistoryUsage;`` (typed) and — for bare *reference* usages
|
|
388
|
+
only, as a name convention — ``h;``/``history;`` (untyped).
|
|
389
|
+
Returns ``"history"`` or ``None``.
|
|
390
|
+
"""
|
|
391
|
+
if not isinstance(usage, dict):
|
|
392
|
+
return None
|
|
393
|
+
decl = usage.get("declaration") or {}
|
|
394
|
+
is_state = usage.get("name") == "StateUsage"
|
|
395
|
+
|
|
396
|
+
def _hunt(x):
|
|
397
|
+
if isinstance(x, dict):
|
|
398
|
+
if x.get("name") == "QualifiedName" and \
|
|
399
|
+
isinstance(x.get("names"), list) and x["names"]:
|
|
400
|
+
qns.append(x["names"])
|
|
401
|
+
for v in x.values():
|
|
402
|
+
_hunt(v)
|
|
403
|
+
elif isinstance(x, list):
|
|
404
|
+
for v in x:
|
|
405
|
+
_hunt(v)
|
|
406
|
+
|
|
407
|
+
qns: list = []
|
|
408
|
+
_hunt(decl)
|
|
409
|
+
typed_history = any(ns and ns[-1] == "HistoryUsage" for ns in qns)
|
|
410
|
+
if typed_history:
|
|
411
|
+
return "history"
|
|
412
|
+
if is_state:
|
|
413
|
+
return None # a real state named h is a state, not a marker
|
|
414
|
+
fd = decl.get("declaration") or {}
|
|
415
|
+
name = (fd.get("identification") or {}).get("declaredName")
|
|
416
|
+
if name in ("history", "h"):
|
|
417
|
+
return "history"
|
|
418
|
+
return None
|
|
419
|
+
|
|
420
|
+
|
|
383
421
|
def _state_declared_name(state_usage: dict) -> Optional[str]:
|
|
384
422
|
"""Extract the declaredName from a StateUsage dict."""
|
|
385
423
|
decl = state_usage.get("declaration", {})
|
|
@@ -405,6 +443,7 @@ def _collect_state_body(items: list, prefix: str = "",
|
|
|
405
443
|
"initial": <state name:str>|None,
|
|
406
444
|
"transitions": [ {name, source, target, trigger, guard}, ... ],
|
|
407
445
|
"composites": [ {name, items, ...}, ... ],
|
|
446
|
+
"pseudostates": [ {name, kind}, ... ],
|
|
408
447
|
"entry": <action label str|None>,
|
|
409
448
|
"do": <action label str|None>,
|
|
410
449
|
"exit": <action label str|None>,
|
|
@@ -416,6 +455,7 @@ def _collect_state_body(items: list, prefix: str = "",
|
|
|
416
455
|
"initial": None,
|
|
417
456
|
"transitions": [],
|
|
418
457
|
"composites": [],
|
|
458
|
+
"pseudostates": [],
|
|
419
459
|
"entry": None, "do": None, "exit": None,
|
|
420
460
|
}
|
|
421
461
|
|
|
@@ -483,6 +523,12 @@ def _collect_state_body(items: list, prefix: str = "",
|
|
|
483
523
|
if isinstance(orel, dict) and orel.get("name") == "BehaviorUsageElement":
|
|
484
524
|
su = orel.get("ownedRelationship", {})
|
|
485
525
|
if isinstance(su, dict) and su.get("name") == "StateUsage":
|
|
526
|
+
if _pseudostate_kind(su):
|
|
527
|
+
sname = _state_declared_name(su)
|
|
528
|
+
if sname:
|
|
529
|
+
result["pseudostates"].append(
|
|
530
|
+
{"name": sname, "kind": "history"})
|
|
531
|
+
continue
|
|
486
532
|
sname = _state_declared_name(su)
|
|
487
533
|
if sname:
|
|
488
534
|
sub_body = su.get("body", {})
|
|
@@ -506,9 +552,39 @@ def _collect_state_body(items: list, prefix: str = "",
|
|
|
506
552
|
"entry": None, "do": None, "exit": None,
|
|
507
553
|
"states": [], "initial": None,
|
|
508
554
|
"transitions": [], "composites": [],
|
|
555
|
+
"pseudostates": [],
|
|
509
556
|
})
|
|
510
557
|
continue
|
|
511
558
|
|
|
559
|
+
# History / pseudostate markers as bare references in a state
|
|
560
|
+
# body (``h;``, ``history;``, ``h : HistoryUsage;``). They are
|
|
561
|
+
# not states; sim treats transitions targeting them as history
|
|
562
|
+
# re-entries.
|
|
563
|
+
ps_name, ps_kind = None, None
|
|
564
|
+
for member_name in ("NonOccurrenceUsageMember",
|
|
565
|
+
"OccurrenceUsageMember"):
|
|
566
|
+
pm = _top_member(item, member_name)
|
|
567
|
+
if pm is None:
|
|
568
|
+
continue
|
|
569
|
+
orel = pm.get("ownedRelatedElement")
|
|
570
|
+
orel_list = orel if isinstance(orel, list) else (
|
|
571
|
+
[orel] if isinstance(orel, dict) else [])
|
|
572
|
+
for oe in orel_list:
|
|
573
|
+
usage = (oe.get("ownedRelatedElement")
|
|
574
|
+
if isinstance(oe, dict) else None)
|
|
575
|
+
if isinstance(usage, dict):
|
|
576
|
+
kind = _pseudostate_kind(usage)
|
|
577
|
+
if kind:
|
|
578
|
+
ps_name, ps_kind = usage, kind
|
|
579
|
+
if ps_name is not None:
|
|
580
|
+
fd = ((ps_name.get("declaration") or {}).get("declaration")
|
|
581
|
+
or {})
|
|
582
|
+
nm = (fd.get("identification") or {}).get("declaredName")
|
|
583
|
+
if nm:
|
|
584
|
+
result["pseudostates"].append(
|
|
585
|
+
{"name": nm, "kind": ps_kind})
|
|
586
|
+
continue
|
|
587
|
+
|
|
512
588
|
# If this item was a pure entry/do/exit member, we already
|
|
513
589
|
# handled it above and there's nothing else to register.
|
|
514
590
|
if entry_do_exit_handled:
|
|
@@ -44,9 +44,16 @@ Scope of this MVP (deliberate cuts, tracked in TODO.md):
|
|
|
44
44
|
still flattened implicitly
|
|
45
45
|
- one machine per simulator (``focus`` picks which); parallel regions
|
|
46
46
|
— top-level or inside a composite — raise :class:`SimulationError`
|
|
47
|
-
- effects
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
- assignment effects (``do x := 5``) execute against the simulator's
|
|
48
|
+
values (:meth:`StateSimulator.set_value`), so guards evaluated later
|
|
49
|
+
see the new value; other effects (``do <action>``, ``send``) are
|
|
50
|
+
logged only
|
|
51
|
+
- history pseudostates (``state h : HistoryUsage;``/``h :
|
|
52
|
+
HistoryUsage;``, or ``h;``/``history;`` by name convention) are
|
|
53
|
+
honored: a transition targeting one re-enters the region's last
|
|
54
|
+
active substate. Deep history restores the deepest visited state
|
|
55
|
+
when ``deep_history=True`` is passed to :class:`StateSimulator` —
|
|
56
|
+
the language has no deep-history form, so it is a simulator option
|
|
50
57
|
- completion transitions (no ``accept`` trigger) fire automatically on
|
|
51
58
|
entering a state (run-to-completion), and manually via
|
|
52
59
|
:meth:`StateSimulator.step`
|
|
@@ -189,6 +196,15 @@ class TransitionSpec(NamedTuple):
|
|
|
189
196
|
guard: Optional[str]
|
|
190
197
|
#: Effect action name (``do <action>``), or None.
|
|
191
198
|
effect: Optional[str]
|
|
199
|
+
#: For transitions targeting a history pseudostate: the flat name
|
|
200
|
+
#: of the region whose history the target remembers (``""`` =
|
|
201
|
+
#: machine root). None for ordinary transitions.
|
|
202
|
+
history_region: Optional[str] = None
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
#: Assignment-effect shape: ``name := expression`` (SysML assignment
|
|
206
|
+
#: operator; the effect text from the collector renders exactly this).
|
|
207
|
+
_ASSIGNMENT_RE = re.compile(r"^\s*([\w.]+)\s*:=\s*(.+?)\s*$", re.S)
|
|
192
208
|
|
|
193
209
|
|
|
194
210
|
def _mangle(name: str) -> str:
|
|
@@ -209,6 +225,14 @@ class MachineDescriptor(NamedTuple):
|
|
|
209
225
|
#: excluded from simulation but surfaced for diagnostics (the
|
|
210
226
|
#: validator turns these into UNRESOLVED_TRANSITION_ENDPOINT).
|
|
211
227
|
skipped: Tuple[TransitionSpec, ...] = ()
|
|
228
|
+
#: History pseudostate markers: flat marker name -> flat name of
|
|
229
|
+
#: the region whose last active substate it remembers (``""`` =
|
|
230
|
+
#: machine root).
|
|
231
|
+
history_markers: Dict[str, str] = {}
|
|
232
|
+
#: Region flat name -> default entry (initial substate leaf);
|
|
233
|
+
#: includes ``""`` -> machine initial. Fallback when no history
|
|
234
|
+
#: has been recorded yet.
|
|
235
|
+
region_defaults: Dict[str, str] = {}
|
|
212
236
|
|
|
213
237
|
|
|
214
238
|
def build_state_machine(model, focus: Optional[str] = None,
|
|
@@ -261,6 +285,11 @@ def build_state_machine(model, focus: Optional[str] = None,
|
|
|
261
285
|
# - a region declaring parallel raises (MVP cut).
|
|
262
286
|
states: List[str] = []
|
|
263
287
|
raw: List[dict] = []
|
|
288
|
+
# history pseudostate markers: flat marker name -> region flat name
|
|
289
|
+
markers_flat: Dict[str, str] = {}
|
|
290
|
+
# region flat name -> default entry (filled during expansion; the
|
|
291
|
+
# machine root is filled after the initial-state resolution below)
|
|
292
|
+
region_defaults_flat: Dict[str, str] = {}
|
|
264
293
|
|
|
265
294
|
def _expand_region(level, prefix, all_names):
|
|
266
295
|
local_flat: Dict[str, str] = {}
|
|
@@ -298,6 +327,7 @@ def build_state_machine(model, focus: Optional[str] = None,
|
|
|
298
327
|
substates_of[nm] = [flat]
|
|
299
328
|
continue
|
|
300
329
|
entry_of[nm] = entry
|
|
330
|
+
region_defaults_flat[prefix + nm] = entry
|
|
301
331
|
substates_of[nm] = (list(inner_flat.values()) +
|
|
302
332
|
list(inner_entry.values()))
|
|
303
333
|
else:
|
|
@@ -308,6 +338,20 @@ def build_state_machine(model, focus: Optional[str] = None,
|
|
|
308
338
|
all_names.setdefault(nm, local_flat.get(nm)
|
|
309
339
|
or entry_of.get(nm) or flat)
|
|
310
340
|
|
|
341
|
+
for ps in level.get("pseudostates", []) or []:
|
|
342
|
+
nm = ps.get("name") if isinstance(ps, dict) else ps
|
|
343
|
+
if not nm:
|
|
344
|
+
continue
|
|
345
|
+
flat = prefix + nm
|
|
346
|
+
region_flat = prefix[:-1] if prefix else ""
|
|
347
|
+
if nm in local_flat or nm in entry_of:
|
|
348
|
+
notes.append(
|
|
349
|
+
f"pseudostate {flat!r} shadows a state of the same "
|
|
350
|
+
"name; treating it as a state")
|
|
351
|
+
continue
|
|
352
|
+
markers_flat[flat] = region_flat
|
|
353
|
+
all_names.setdefault(nm, flat)
|
|
354
|
+
|
|
311
355
|
for t in level.get("transitions", []):
|
|
312
356
|
src, tgt = t.get("source"), t.get("target")
|
|
313
357
|
if src in substates_of and src not in local_flat:
|
|
@@ -357,6 +401,28 @@ def build_state_machine(model, focus: Optional[str] = None,
|
|
|
357
401
|
# substate) resolve to the qualified flat name
|
|
358
402
|
source = all_names.get(source, source)
|
|
359
403
|
target = all_names.get(target, target)
|
|
404
|
+
if target in markers_flat:
|
|
405
|
+
# history target: the transition re-enters the region's
|
|
406
|
+
# last active substate at fire time; the static dest is
|
|
407
|
+
# the region's default entry (used before any history)
|
|
408
|
+
region_flat = markers_flat[target]
|
|
409
|
+
dest = region_defaults_flat.get(region_flat)
|
|
410
|
+
if dest is None or dest not in states:
|
|
411
|
+
notes.append(
|
|
412
|
+
f"transition {t.get('name')!r} skipped: history "
|
|
413
|
+
f"region {region_flat or '(machine)'!r} has no "
|
|
414
|
+
"default entry to fall back to")
|
|
415
|
+
skipped.append(TransitionSpec(
|
|
416
|
+
name=t.get("name"), source=source, target=target,
|
|
417
|
+
trigger=t.get("trigger"), guard=t.get("guard"),
|
|
418
|
+
effect=t.get("effect"),
|
|
419
|
+
history_region=region_flat))
|
|
420
|
+
continue
|
|
421
|
+
transitions.append(TransitionSpec(
|
|
422
|
+
name=t.get("name"), source=source, target=dest,
|
|
423
|
+
trigger=t.get("trigger"), guard=t.get("guard"),
|
|
424
|
+
effect=t.get("effect"), history_region=region_flat))
|
|
425
|
+
continue
|
|
360
426
|
if source not in states or target not in states:
|
|
361
427
|
notes.append(
|
|
362
428
|
f"transition {t.get('name')!r} skipped: endpoint(s) "
|
|
@@ -389,9 +455,12 @@ def build_state_machine(model, focus: Optional[str] = None,
|
|
|
389
455
|
f"no entry transition in the model; starting in "
|
|
390
456
|
f"{fallback!r} (the first declared state)")
|
|
391
457
|
initial = fallback
|
|
458
|
+
region_defaults_flat[""] = initial
|
|
392
459
|
return MachineDescriptor(name=sm.get("name"), states=states,
|
|
393
460
|
initial=initial, transitions=transitions,
|
|
394
|
-
notes=notes, skipped=tuple(skipped)
|
|
461
|
+
notes=notes, skipped=tuple(skipped),
|
|
462
|
+
history_markers=markers_flat,
|
|
463
|
+
region_defaults=region_defaults_flat)
|
|
395
464
|
|
|
396
465
|
|
|
397
466
|
def load_model_grammar(model) -> dict:
|
|
@@ -422,7 +491,8 @@ class StepRecord:
|
|
|
422
491
|
def __init__(self, from_state: str, trigger: Optional[str],
|
|
423
492
|
guard: Optional[str], guard_ok: Optional[bool],
|
|
424
493
|
to_state: Optional[str], effects: List[str],
|
|
425
|
-
fired: bool, note: str = ""
|
|
494
|
+
fired: bool, note: str = "",
|
|
495
|
+
assignments: Tuple[Tuple[str, Any], ...] = ()):
|
|
426
496
|
self.from_state = from_state
|
|
427
497
|
self.trigger = trigger
|
|
428
498
|
self.guard = guard
|
|
@@ -431,13 +501,19 @@ class StepRecord:
|
|
|
431
501
|
self.effects = effects
|
|
432
502
|
self.fired = fired
|
|
433
503
|
self.note = note
|
|
504
|
+
#: (name, value) pairs applied by ``do x := <expr>`` effects.
|
|
505
|
+
self.assignments = tuple(assignments)
|
|
434
506
|
self.timestamp = time.time()
|
|
435
507
|
|
|
436
508
|
def __repr__(self):
|
|
437
509
|
arrow = "->" if self.fired else "-x"
|
|
438
510
|
trig = self.trigger or "(completion)"
|
|
439
|
-
|
|
440
|
-
|
|
511
|
+
out = (f"<{arrow} {self.from_state!r} --{trig}"
|
|
512
|
+
f"[{self.guard}]--> {self.to_state!r}>")
|
|
513
|
+
if self.assignments:
|
|
514
|
+
assign = ", ".join(f"{n} := {v!r}" for n, v in self.assignments)
|
|
515
|
+
out += f" {assign}"
|
|
516
|
+
return out
|
|
441
517
|
|
|
442
518
|
|
|
443
519
|
def _make_host(sim: "StateSimulator", n_guards: int, n_effects: int):
|
|
@@ -480,10 +556,14 @@ class StateSimulator:
|
|
|
480
556
|
"""
|
|
481
557
|
|
|
482
558
|
def __init__(self, model, focus: Optional[str] = None,
|
|
483
|
-
values: Optional[Dict[str, Any]] = None
|
|
559
|
+
values: Optional[Dict[str, Any]] = None,
|
|
560
|
+
deep_history: bool = False):
|
|
484
561
|
self.model = model
|
|
485
562
|
self.descriptor = build_state_machine(model, focus=focus)
|
|
486
563
|
self.notes = list(self.descriptor.notes)
|
|
564
|
+
#: When True, history pseudostates restore the deepest visited
|
|
565
|
+
#: state; by default (False) they restore one level (shallow).
|
|
566
|
+
self.deep_history = bool(deep_history)
|
|
487
567
|
#: name -> value; guards evaluate against these (overrides on
|
|
488
568
|
#: top of the model's collected attribute values).
|
|
489
569
|
self.values: Dict[str, Any] = dict(values or {})
|
|
@@ -494,10 +574,66 @@ class StateSimulator:
|
|
|
494
574
|
pass
|
|
495
575
|
self.log: List[StepRecord] = []
|
|
496
576
|
self._pending_effects: List[str] = []
|
|
577
|
+
self._pending_assignments: List[Tuple[str, Any]] = []
|
|
578
|
+
#: region flat name -> last active direct substate of that
|
|
579
|
+
#: region ("" = machine root)
|
|
580
|
+
self._history: Dict[str, str] = {}
|
|
497
581
|
self._host = _make_host(
|
|
498
582
|
self, len(self.descriptor.transitions),
|
|
499
583
|
len(self.descriptor.transitions))
|
|
500
584
|
self._build()
|
|
585
|
+
self._record_history(self.state)
|
|
586
|
+
|
|
587
|
+
# -- history ------------------------------------------------------------
|
|
588
|
+
|
|
589
|
+
def _record_history(self, state: str):
|
|
590
|
+
"""Remember the active direct substate of every enclosing region.
|
|
591
|
+
|
|
592
|
+
For state ``C.Inner.Deep.S`` this records ``"" -> C``,
|
|
593
|
+
``C -> C.Inner``, ``C.Inner -> C.Inner.Deep`` and
|
|
594
|
+
``C.Inner.Deep -> C.Inner.Deep.S`` — i.e. each region maps to
|
|
595
|
+
its direct active child, which is what shallow history resumes;
|
|
596
|
+
deep history follows the chain down.
|
|
597
|
+
"""
|
|
598
|
+
if not state:
|
|
599
|
+
return
|
|
600
|
+
parts = state.split(".")
|
|
601
|
+
for i in range(len(parts)):
|
|
602
|
+
self._history[".".join(parts[:i])] = ".".join(parts[:i + 1])
|
|
603
|
+
|
|
604
|
+
def _resolve_history(self, region_flat: str) -> Optional[str]:
|
|
605
|
+
"""State to resume when re-entering *region_flat* via history."""
|
|
606
|
+
rd = self.descriptor.region_defaults
|
|
607
|
+
default = rd.get(region_flat) or self.descriptor.initial
|
|
608
|
+
s = self._history.get(region_flat)
|
|
609
|
+
if s is None:
|
|
610
|
+
return default
|
|
611
|
+
if not self.deep_history:
|
|
612
|
+
# shallow: the recorded direct child; if it is a composite,
|
|
613
|
+
# enter at its initial substate
|
|
614
|
+
if s in self.descriptor.states:
|
|
615
|
+
return s
|
|
616
|
+
return rd.get(s) or default
|
|
617
|
+
seen = set()
|
|
618
|
+
while (s is not None and s not in self.descriptor.states
|
|
619
|
+
and s not in seen):
|
|
620
|
+
seen.add(s)
|
|
621
|
+
s = self._history.get(s) or rd.get(s)
|
|
622
|
+
return s or default
|
|
623
|
+
|
|
624
|
+
def _apply_history(self, t: TransitionSpec) -> str:
|
|
625
|
+
"""Post-fire state adjustment for history-targeting transitions.
|
|
626
|
+
|
|
627
|
+
pytransitions needs a concrete ``dest`` per transition, so
|
|
628
|
+
history transitions are defined to the region's default entry
|
|
629
|
+
and the actual (recorded) state is applied right after firing.
|
|
630
|
+
"""
|
|
631
|
+
if t.history_region is None:
|
|
632
|
+
return t.target
|
|
633
|
+
resolved = self._resolve_history(t.history_region)
|
|
634
|
+
if resolved and resolved != self.state:
|
|
635
|
+
self._host.state = resolved
|
|
636
|
+
return resolved or t.target
|
|
501
637
|
|
|
502
638
|
# -- construction -------------------------------------------------------
|
|
503
639
|
|
|
@@ -591,16 +727,27 @@ class StateSimulator:
|
|
|
591
727
|
self, len(self.descriptor.transitions),
|
|
592
728
|
len(self.descriptor.transitions))
|
|
593
729
|
self._build()
|
|
730
|
+
self._history.clear()
|
|
731
|
+
self._record_history(self.state)
|
|
594
732
|
|
|
595
733
|
def _fire(self, index: int) -> bool:
|
|
596
734
|
t = self.descriptor.transitions[index]
|
|
597
735
|
self._pending_effects.clear()
|
|
736
|
+
self._pending_assignments.clear()
|
|
598
737
|
fired = bool(getattr(self._host, f"fire_{index}")())
|
|
599
738
|
if fired:
|
|
739
|
+
to_state = self._apply_history(t)
|
|
740
|
+
self._record_history(self.state)
|
|
741
|
+
note = ""
|
|
742
|
+
if t.history_region is not None and to_state != t.target:
|
|
743
|
+
note = (f"history: resumed {to_state!r} in region "
|
|
744
|
+
f"{t.history_region or '(machine)'!r}")
|
|
600
745
|
self.log.append(StepRecord(
|
|
601
|
-
t.source, t.trigger, t.guard, True,
|
|
602
|
-
list(self._pending_effects), True
|
|
746
|
+
t.source, t.trigger, t.guard, True, to_state,
|
|
747
|
+
list(self._pending_effects), True, note,
|
|
748
|
+
assignments=tuple(self._pending_assignments)))
|
|
603
749
|
self._pending_effects.clear()
|
|
750
|
+
self._pending_assignments.clear()
|
|
604
751
|
self._run_completion()
|
|
605
752
|
return True
|
|
606
753
|
self.log.append(StepRecord(
|
|
@@ -617,11 +764,22 @@ class StateSimulator:
|
|
|
617
764
|
if t.source == current and t.trigger is None:
|
|
618
765
|
if self._eval_guard(i):
|
|
619
766
|
self._pending_effects.clear()
|
|
767
|
+
self._pending_assignments.clear()
|
|
620
768
|
getattr(self._host, f"fire_{i}")()
|
|
769
|
+
to_state = self._apply_history(t)
|
|
770
|
+
self._record_history(self.state)
|
|
771
|
+
note = ""
|
|
772
|
+
if t.history_region is not None \
|
|
773
|
+
and to_state != t.target:
|
|
774
|
+
note = (f"history: resumed {to_state!r} "
|
|
775
|
+
f"in region "
|
|
776
|
+
f"{t.history_region or '(machine)'!r}")
|
|
621
777
|
self.log.append(StepRecord(
|
|
622
|
-
t.source, None, t.guard, True,
|
|
623
|
-
list(self._pending_effects), True
|
|
778
|
+
t.source, None, t.guard, True, to_state,
|
|
779
|
+
list(self._pending_effects), True, note,
|
|
780
|
+
assignments=tuple(self._pending_assignments)))
|
|
624
781
|
self._pending_effects.clear()
|
|
782
|
+
self._pending_assignments.clear()
|
|
625
783
|
fired_any = True
|
|
626
784
|
break
|
|
627
785
|
if not fired_any:
|
|
@@ -672,8 +830,25 @@ class StateSimulator:
|
|
|
672
830
|
|
|
673
831
|
def _do_effect(self, index: int):
|
|
674
832
|
effect = self.descriptor.transitions[index].effect
|
|
675
|
-
if effect:
|
|
833
|
+
if not effect:
|
|
834
|
+
return
|
|
835
|
+
m = _ASSIGNMENT_RE.match(effect)
|
|
836
|
+
if m:
|
|
837
|
+
# Assignment effect (``do x := <expr>``): evaluate and
|
|
838
|
+
# apply through set_value so later guards see the result.
|
|
839
|
+
name, expr = m.group(1), m.group(2)
|
|
840
|
+
try:
|
|
841
|
+
value = evaluate_expression(
|
|
842
|
+
expr, model=self.model, bindings=self.values)
|
|
843
|
+
except EvaluationError as e:
|
|
844
|
+
self._pending_effects.append(
|
|
845
|
+
f"{effect} (not evaluated: {e})")
|
|
846
|
+
return
|
|
847
|
+
self.set_value(name, value)
|
|
848
|
+
self._pending_assignments.append((name, value))
|
|
676
849
|
self._pending_effects.append(effect)
|
|
850
|
+
return
|
|
851
|
+
self._pending_effects.append(effect)
|
|
677
852
|
|
|
678
853
|
|
|
679
854
|
# ---------------------------------------------------------------------------
|
|
@@ -704,6 +879,7 @@ def _render(sim: StateSimulator) -> str:
|
|
|
704
879
|
|
|
705
880
|
def run_tui(model, focus: Optional[str] = None,
|
|
706
881
|
values: Optional[Dict[str, Any]] = None,
|
|
882
|
+
deep_history: bool = False,
|
|
707
883
|
input_func=input, output=print) -> Optional[StateSimulator]:
|
|
708
884
|
"""Interactive simulate-test loop; returns the simulator on exit.
|
|
709
885
|
|
|
@@ -712,7 +888,8 @@ def run_tui(model, focus: Optional[str] = None,
|
|
|
712
888
|
prints one snapshot and returns instead of looping.
|
|
713
889
|
"""
|
|
714
890
|
try:
|
|
715
|
-
sim = StateSimulator(model, focus=focus, values=values
|
|
891
|
+
sim = StateSimulator(model, focus=focus, values=values,
|
|
892
|
+
deep_history=deep_history)
|
|
716
893
|
except SimulationError as e:
|
|
717
894
|
output(f"simulation: {e}")
|
|
718
895
|
return None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp
RENAMED
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py
RENAMED
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml
RENAMED
|
File without changes
|
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml
RENAMED
|
File without changes
|
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.80.0 → sysmlpy-0.81.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|