sysmlpy 0.83.0__tar.gz → 0.85.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.83.0 → sysmlpy-0.85.0}/PKG-INFO +1 -1
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/pyproject.toml +1 -1
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/__init__.py +6 -1
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr_parser.py +17 -0
- sysmlpy-0.85.0/src/sysmlpy/dfa_cache.py +374 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/evaluator.py +454 -24
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/classes.py +9 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/interchange.py +187 -14
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/LICENSE +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/README.md +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/__main__.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/README.md +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/SysMLv2Parser.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/antlr_visitor.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/boxes_view.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/definition.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/diff.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/examples/attribute_values.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/examples/part_attributes.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/examples/tuples_sequences.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/formatting.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/README.md +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.g4 +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.g4 +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/desc.xml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/examples/camera.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/examples/toaster-system.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/examples/vehicle-model.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/grammar/antlr4/pom.xml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/LICENSE +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/README.md +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/__init__.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Analysis/AnalysisTooling.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Analysis/TradeStudies.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Cause and Effect/CausationConnections.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Geometry/ShapeItems.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Geometry/SpatialItems.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Metadata/ImageMetadata.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Metadata/ParametersOfInterestMetadata.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Metadata/RiskMetadata.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQ.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAtomicNuclear.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCharacteristicNumbers.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQChemistryMolecular.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCondensedMatter.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQElectromagnetism.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQInformation.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/ISQThermodynamics.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementRefCalculations.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementReferences.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/QuantityCalculations.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/SI.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/TensorCalculations.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/USCustomaryUnits.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Quantities and Units/VectorCalculations.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Requirement Derivation/DerivationConnections.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/domain/Requirement Derivation/RequirementDerivation.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/Base.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/BaseFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/BooleanFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/Clocks.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/CollectionFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/Collections.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/ComplexFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/ControlFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/ControlPerformances.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/DataFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/IntegerFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/KerML.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/Links.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/Metaobjects.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/NaturalFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/NumericalFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/Objects.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/Observation.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/OccurrenceFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/Occurrences.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/Performances.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/RationalFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/RealFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/ScalarFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/ScalarValues.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/SequenceFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/SpatialFrames.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/StatePerformances.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/StringFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/Transfers.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/TransitionPerformances.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/TrigFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/Triggers.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/VectorFunctions.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/kernel/VectorValues.kerml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Actions.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Allocations.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/AnalysisCases.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Attributes.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Calculations.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Cases.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Connections.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Constraints.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Flows.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Interfaces.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Items.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Metadata.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Parts.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Ports.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Requirements.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/StandardViewDefinitions.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/States.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/SysML.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/UseCases.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/VerificationCases.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/library/systems/Views.sysml +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/lsp/__init__.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/lsp/__main__.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/lsp/protocol.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/lsp/server.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/lsp/stdio.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/navigate.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/plantuml.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/project.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/semantic.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/sim.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/spreadsheet.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/store.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/traceability.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/us_customary_units.txt +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.0}/src/sysmlpy/usage.py +0 -0
- {sysmlpy-0.83.0 → sysmlpy-0.85.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.85.0"
|
|
38
38
|
|
|
39
39
|
from sysmlpy.usage import (
|
|
40
40
|
Item, Attribute, Part, Port, Action, Reference, UseCase, Requirement, Interface, Message,
|
|
@@ -454,5 +454,10 @@ def __getattr__(name):
|
|
|
454
454
|
fn = getattr(_diff, name)
|
|
455
455
|
globals()[name] = fn
|
|
456
456
|
return fn
|
|
457
|
+
if name == "set_dfa_cache":
|
|
458
|
+
from sysmlpy import dfa_cache as _dc
|
|
459
|
+
fn = _dc.set_dfa_cache
|
|
460
|
+
globals()[name] = fn
|
|
461
|
+
return fn
|
|
457
462
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
458
463
|
|
|
@@ -138,6 +138,11 @@ def _parse_tree(content, recover=False, prediction_mode="sll"):
|
|
|
138
138
|
"""Two-stage ANTLR parse (no rescue); the body of historical parse()."""
|
|
139
139
|
force_ll = prediction_mode == "ll"
|
|
140
140
|
sll_only = prediction_mode == "sll_only" or force_ll
|
|
141
|
+
|
|
142
|
+
# Persistent DFA cache (v0.84.0): reinstate the prediction caches
|
|
143
|
+
# warmed by previous processes before the first parse of this one.
|
|
144
|
+
from sysmlpy import dfa_cache as _dfa_cache
|
|
145
|
+
_dfa_cache.maybe_load()
|
|
141
146
|
|
|
142
147
|
if not force_ll:
|
|
143
148
|
# ── Stage 1: SLL fast-path ────────────────────────────────────
|
|
@@ -159,6 +164,7 @@ def _parse_tree(content, recover=False, prediction_mode="sll"):
|
|
|
159
164
|
sll_errors = ["<sll>"]
|
|
160
165
|
if tree is not None and not error_listener.errors:
|
|
161
166
|
# ── fast path succeeded ──────────────────────────────────
|
|
167
|
+
_maybe_save_dfa_cache()
|
|
162
168
|
if recover:
|
|
163
169
|
return tree, []
|
|
164
170
|
return tree
|
|
@@ -186,15 +192,26 @@ def _parse_tree(content, recover=False, prediction_mode="sll"):
|
|
|
186
192
|
# Check for errors
|
|
187
193
|
if error_listener.errors:
|
|
188
194
|
if recover:
|
|
195
|
+
_maybe_save_dfa_cache()
|
|
189
196
|
return tree, error_listener.errors
|
|
190
197
|
raise SysMLSyntaxError("\n".join(error_listener.errors))
|
|
191
198
|
|
|
199
|
+
_maybe_save_dfa_cache()
|
|
192
200
|
if recover:
|
|
193
201
|
return tree, []
|
|
194
202
|
|
|
195
203
|
return tree
|
|
196
204
|
|
|
197
205
|
|
|
206
|
+
def _maybe_save_dfa_cache():
|
|
207
|
+
"""Persist the warmed DFA cache once per process (never fatal)."""
|
|
208
|
+
try:
|
|
209
|
+
from sysmlpy import dfa_cache
|
|
210
|
+
dfa_cache.maybe_save()
|
|
211
|
+
except Exception:
|
|
212
|
+
pass
|
|
213
|
+
|
|
214
|
+
|
|
198
215
|
def _rescue_constraint_bodies(content, language="English"):
|
|
199
216
|
"""Salvage constraint bodies that do not parse as SysML/KerML.
|
|
200
217
|
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Persistent ANTLR DFA cache (v0.84.0 — Adoption Roadmap Goal 11 Batch 5).
|
|
3
|
+
|
|
4
|
+
The generated SysML v2 parser/lexer share class-level ATN + DFA caches,
|
|
5
|
+
so prediction structures are built once per *process* — but every fresh
|
|
6
|
+
process (CLI invocation, LSP session start, first test run) pays that
|
|
7
|
+
cold-start cost again. On a 27 KB model the first parse measured
|
|
8
|
+
**8.4 s** versus **1.2 s** for an in-process warm parse: ~85 % of the
|
|
9
|
+
first parse is adaptive-prediction DFA construction.
|
|
10
|
+
|
|
11
|
+
This module serializes the warmed parser + lexer ATN/DFA graphs with
|
|
12
|
+
``pickle`` after a successful parse and reinstalls them at the start of
|
|
13
|
+
subsequent processes, eliminating the cold start.
|
|
14
|
+
|
|
15
|
+
Design notes
|
|
16
|
+
------------
|
|
17
|
+
* The *whole* reachable graph is pickled (ATN objects, DFA states, the
|
|
18
|
+
prediction-context cache) and assigned back to the generated classes'
|
|
19
|
+
class attributes on load. Pickle preserves shared substructures, so
|
|
20
|
+
the restored graph is self-consistent — no state re-wiring needed.
|
|
21
|
+
* The cache file is keyed by SHA-1 of both serialized ATNs + the
|
|
22
|
+
antlr4 runtime version + the sysmlpy version + pickle protocol, so a
|
|
23
|
+
stale or regenerated grammar can never load a mismatched cache.
|
|
24
|
+
* Cache failures must never break parsing: every load/save is wrapped
|
|
25
|
+
and degrades to the normal (uncached) behavior with a one-time
|
|
26
|
+
warning.
|
|
27
|
+
* Trust: the cache is read from the user's own cache directory
|
|
28
|
+
(``XDG_CACHE_HOME``/``~/.cache/sysmlpy`` or an explicit override) —
|
|
29
|
+
like any Python pickle it must only contain locally generated data;
|
|
30
|
+
point the directory at a trusted location or disable with
|
|
31
|
+
``SYSSMLPY_DFA_CACHE=off``.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
import hashlib
|
|
37
|
+
import os
|
|
38
|
+
import pickle
|
|
39
|
+
import sys
|
|
40
|
+
import threading
|
|
41
|
+
import warnings
|
|
42
|
+
from typing import Any, Dict, Optional, Tuple
|
|
43
|
+
|
|
44
|
+
_CACHE_PROTOCOL = 4 # stable across Python 3.8+; avoids protocol drift
|
|
45
|
+
_MAX_CACHE_BYTES = 256 * 1024 * 1024 # refuse absurd cache files on load
|
|
46
|
+
|
|
47
|
+
# RLock: stats()/set_dfa_cache() re-enter while held
|
|
48
|
+
_lock = threading.RLock()
|
|
49
|
+
_state: Dict[str, Any] = {
|
|
50
|
+
"enabled": None, # None = not overridden by set_dfa_cache()
|
|
51
|
+
"directory": None, # None = default (env/XDG/~/.cache/sysmlpy)
|
|
52
|
+
"load_attempted": False,
|
|
53
|
+
"loaded": False,
|
|
54
|
+
"save_attempted": False,
|
|
55
|
+
"saved": False,
|
|
56
|
+
"saved_states": 0,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
# configuration
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _env_disabled() -> bool:
|
|
66
|
+
return os.environ.get("SYSSMLPY_DFA_CACHE", "").strip().lower() in (
|
|
67
|
+
"0", "off", "false", "no", "disable", "disabled")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _env_directory() -> Optional[str]:
|
|
71
|
+
val = os.environ.get("SYSSMLPY_DFA_CACHE", "").strip()
|
|
72
|
+
if val and val.lower() not in (
|
|
73
|
+
"0", "off", "false", "no", "disable", "disabled", "on", "1",
|
|
74
|
+
"true", "yes", "enable", "enabled"):
|
|
75
|
+
return val
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def is_enabled() -> bool:
|
|
80
|
+
"""Whether the DFA cache should participate in parsing."""
|
|
81
|
+
with _lock:
|
|
82
|
+
if _state["enabled"] is not None:
|
|
83
|
+
return _state["enabled"]
|
|
84
|
+
return not _env_disabled()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def set_dfa_cache(enabled: Optional[bool] = None,
|
|
88
|
+
directory: Optional[str] = None) -> Dict[str, Any]:
|
|
89
|
+
"""Configure the persistent DFA cache.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
enabled : bool, optional
|
|
94
|
+
``True``/``False`` force the cache on/off for this process;
|
|
95
|
+
``None`` (default) keeps the ``SYSSMLPY_DFA_CACHE`` env default.
|
|
96
|
+
directory : str, optional
|
|
97
|
+
Override the cache directory for this process; ``None`` keeps
|
|
98
|
+
the env/default location.
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
dict
|
|
103
|
+
``{"enabled": bool, "directory": str}`` — the effective settings.
|
|
104
|
+
"""
|
|
105
|
+
with _lock:
|
|
106
|
+
if enabled is not None:
|
|
107
|
+
_state["enabled"] = bool(enabled)
|
|
108
|
+
if directory is not None:
|
|
109
|
+
_state["directory"] = directory
|
|
110
|
+
return {"enabled": is_enabled(),
|
|
111
|
+
"directory": _cache_directory()}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _cache_directory() -> str:
|
|
115
|
+
with _lock:
|
|
116
|
+
override = _state["directory"]
|
|
117
|
+
if override:
|
|
118
|
+
return override
|
|
119
|
+
env_dir = _env_directory()
|
|
120
|
+
if env_dir:
|
|
121
|
+
return env_dir
|
|
122
|
+
root = os.environ.get("XDG_CACHE_HOME") or os.path.expanduser(
|
|
123
|
+
os.path.join("~", ".cache"))
|
|
124
|
+
return os.path.join(root, "sysmlpy")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def cache_key() -> str:
|
|
128
|
+
"""Stable key binding the cache file to the grammar + runtime."""
|
|
129
|
+
import antlr4 as _antlr4
|
|
130
|
+
from sysmlpy.antlr import SysMLv2Lexer, SysMLv2Parser
|
|
131
|
+
|
|
132
|
+
parts = [
|
|
133
|
+
SysMLv2Parser.serializedATN(),
|
|
134
|
+
SysMLv2Lexer.serializedATN(),
|
|
135
|
+
getattr(SysMLv2Parser, "grammarFileName", "SysMLv2Parser.g4"),
|
|
136
|
+
getattr(SysMLv2Lexer, "grammarFileName", "SysMLv2Lexer.g4"),
|
|
137
|
+
"antlr4=" + getattr(_antlr4, "__version__", "unknown"),
|
|
138
|
+
"sysmlpy=" + _sysmlpy_version(),
|
|
139
|
+
f"pickle={_CACHE_PROTOCOL}",
|
|
140
|
+
]
|
|
141
|
+
h = hashlib.sha1()
|
|
142
|
+
for part in parts:
|
|
143
|
+
# serializedATN() is a list of ints — pickle gives a stable
|
|
144
|
+
# byte form for both lists and strings
|
|
145
|
+
h.update(hashlib.sha1(
|
|
146
|
+
pickle.dumps(part, protocol=_CACHE_PROTOCOL)).digest())
|
|
147
|
+
h.update(b"\x00")
|
|
148
|
+
return h.hexdigest()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _sysmlpy_version() -> str:
|
|
152
|
+
try:
|
|
153
|
+
import sysmlpy
|
|
154
|
+
return getattr(sysmlpy, "__version__", "unknown")
|
|
155
|
+
except Exception:
|
|
156
|
+
return "unknown"
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def cache_file() -> str:
|
|
160
|
+
"""Full path of the DFA cache file for this grammar version."""
|
|
161
|
+
return os.path.join(_cache_directory(),
|
|
162
|
+
"dfa-%s.pkl" % cache_key()[:16])
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
# ---------------------------------------------------------------------------
|
|
166
|
+
# load / save
|
|
167
|
+
# ---------------------------------------------------------------------------
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _classes() -> Tuple[type, type]:
|
|
171
|
+
# NB: ``sysmlpy.antlr`` is a namespace package whose submodule names
|
|
172
|
+
# shadow the class names — import the classes from their modules
|
|
173
|
+
from sysmlpy.antlr.SysMLv2Lexer import SysMLv2Lexer as _Lexer
|
|
174
|
+
from sysmlpy.antlr.SysMLv2Parser import SysMLv2Parser as _Parser
|
|
175
|
+
return _Parser, _Lexer
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _payload() -> Tuple[Any, ...]:
|
|
179
|
+
"""The pickled state: parser + lexer ATN/DFA/context-cache attrs."""
|
|
180
|
+
P, L = _classes()
|
|
181
|
+
return (P.atn, P.decisionsToDFA, P.sharedContextCache,
|
|
182
|
+
L.atn, L.decisionsToDFA)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _rebind_empty_contexts(payload: Tuple[Any, ...]) -> Tuple[Any, ...]:
|
|
186
|
+
"""Re-point pickled empty prediction contexts at the live singleton.
|
|
187
|
+
|
|
188
|
+
``EmptyPredictionContext`` is identity-comparable in the runtime
|
|
189
|
+
(``__eq__`` is ``self is other`` and ``isEmpty()`` is
|
|
190
|
+
``self is self.EMPTY``), so unpickled copies must be replaced by the
|
|
191
|
+
live ``PredictionContext.EMPTY`` singleton, and the shared cache
|
|
192
|
+
rebuilt, or prediction diverges from the pristine parser.
|
|
193
|
+
"""
|
|
194
|
+
from antlr4.PredictionContext import (
|
|
195
|
+
PredictionContext as _PC,
|
|
196
|
+
PredictionContextCache,
|
|
197
|
+
EmptyPredictionContext,
|
|
198
|
+
)
|
|
199
|
+
from antlr4.atn.SemanticContext import SemanticContext
|
|
200
|
+
|
|
201
|
+
live_empty = _PC.EMPTY
|
|
202
|
+
live_none = SemanticContext.NONE
|
|
203
|
+
seen: set = set()
|
|
204
|
+
|
|
205
|
+
def fix(ctx):
|
|
206
|
+
if ctx is None:
|
|
207
|
+
return None
|
|
208
|
+
if isinstance(ctx, EmptyPredictionContext):
|
|
209
|
+
return live_empty
|
|
210
|
+
cid = id(ctx)
|
|
211
|
+
if cid in seen:
|
|
212
|
+
return ctx
|
|
213
|
+
seen.add(cid)
|
|
214
|
+
# NB: SingletonPredictionContext stores its parent as
|
|
215
|
+
# ``parentCtx``; ArrayPredictionContext as ``parents``
|
|
216
|
+
parent = getattr(ctx, "parentCtx", None)
|
|
217
|
+
if parent is not None:
|
|
218
|
+
ctx.parentCtx = fix(parent)
|
|
219
|
+
parents = getattr(ctx, "parents", None)
|
|
220
|
+
if parents is not None:
|
|
221
|
+
ctx.parents = [fix(p) for p in parents]
|
|
222
|
+
return ctx
|
|
223
|
+
|
|
224
|
+
def fix_sem(sc):
|
|
225
|
+
if sc is None:
|
|
226
|
+
return None
|
|
227
|
+
if isinstance(sc, type(live_none)):
|
|
228
|
+
return live_none
|
|
229
|
+
return sc
|
|
230
|
+
|
|
231
|
+
P_ctx = payload[2]
|
|
232
|
+
rebuilt = PredictionContextCache()
|
|
233
|
+
for ctx in P_ctx.cache.values():
|
|
234
|
+
rebuilt.add(fix(ctx))
|
|
235
|
+
|
|
236
|
+
# DFA config sets also hold prediction contexts that never made it
|
|
237
|
+
# into the shared cache — rebind those graphs as well
|
|
238
|
+
for dfa_list in (payload[1], payload[4]):
|
|
239
|
+
for dfa in dfa_list:
|
|
240
|
+
for state in dfa.states.values():
|
|
241
|
+
configs = getattr(state, "configs", None)
|
|
242
|
+
if configs is None:
|
|
243
|
+
continue
|
|
244
|
+
for cfg in getattr(configs, "configs", []) or []:
|
|
245
|
+
context = getattr(cfg, "context", None)
|
|
246
|
+
if context is not None:
|
|
247
|
+
cfg.context = fix(context)
|
|
248
|
+
cfg.semanticContext = fix_sem(
|
|
249
|
+
getattr(cfg, "semanticContext", None))
|
|
250
|
+
predicates = getattr(state, "predicates", None)
|
|
251
|
+
if predicates:
|
|
252
|
+
state.predicates = [
|
|
253
|
+
(alt, live_none if isinstance(pred, type(live_none))
|
|
254
|
+
else pred)
|
|
255
|
+
for alt, pred in predicates
|
|
256
|
+
]
|
|
257
|
+
return (payload[0], payload[1], rebuilt, payload[3], payload[4])
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def _install(payload: Tuple[Any, ...]) -> None:
|
|
261
|
+
payload = _rebind_empty_contexts(payload)
|
|
262
|
+
P_atn, P_dfa, P_ctx, L_atn, L_dfa = payload
|
|
263
|
+
P, L = _classes()
|
|
264
|
+
P.atn = P_atn
|
|
265
|
+
P.decisionsToDFA = P_dfa
|
|
266
|
+
P.sharedContextCache = P_ctx
|
|
267
|
+
L.atn = L_atn
|
|
268
|
+
L.decisionsToDFA = L_dfa
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def load_dfa_cache(path: Optional[str] = None) -> bool:
|
|
272
|
+
"""Try to install a persisted DFA cache. Returns True on success.
|
|
273
|
+
|
|
274
|
+
Safe to call repeatedly (loads at most once per process) and never
|
|
275
|
+
raises: any problem falls back to the normal uncached path with a
|
|
276
|
+
one-time warning.
|
|
277
|
+
"""
|
|
278
|
+
with _lock:
|
|
279
|
+
if _state["load_attempted"]:
|
|
280
|
+
return _state["loaded"]
|
|
281
|
+
_state["load_attempted"] = True
|
|
282
|
+
if not is_enabled():
|
|
283
|
+
return False
|
|
284
|
+
path = path or cache_file()
|
|
285
|
+
try:
|
|
286
|
+
if not os.path.isfile(path):
|
|
287
|
+
return False
|
|
288
|
+
if os.path.getsize(path) > _MAX_CACHE_BYTES:
|
|
289
|
+
raise ValueError("cache file exceeds size guard")
|
|
290
|
+
with open(path, "rb") as f:
|
|
291
|
+
payload = pickle.load(f)
|
|
292
|
+
if not isinstance(payload, tuple) or len(payload) != 5:
|
|
293
|
+
raise ValueError("unexpected cache payload shape")
|
|
294
|
+
with _lock:
|
|
295
|
+
_install(payload)
|
|
296
|
+
_state["loaded"] = True
|
|
297
|
+
return True
|
|
298
|
+
except Exception as exc:
|
|
299
|
+
warnings.warn(
|
|
300
|
+
f"DFA cache load failed ({type(exc).__name__}: {exc}); "
|
|
301
|
+
f"parsing continues without it", stacklevel=3)
|
|
302
|
+
return False
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def save_dfa_cache(path: Optional[str] = None) -> bool:
|
|
306
|
+
"""Persist the (warm) DFA cache. Returns True when written.
|
|
307
|
+
|
|
308
|
+
Never raises; failures degrade to a one-time warning. Skipped when
|
|
309
|
+
the cache is disabled or nothing new to save.
|
|
310
|
+
"""
|
|
311
|
+
with _lock:
|
|
312
|
+
if _state["save_attempted"]:
|
|
313
|
+
return _state["saved"]
|
|
314
|
+
_state["save_attempted"] = True
|
|
315
|
+
if not is_enabled():
|
|
316
|
+
return False
|
|
317
|
+
path = path or cache_file()
|
|
318
|
+
try:
|
|
319
|
+
if os.path.isfile(path):
|
|
320
|
+
with _lock:
|
|
321
|
+
_state["saved"] = False
|
|
322
|
+
return False
|
|
323
|
+
P, L = _classes()
|
|
324
|
+
payload = _payload()
|
|
325
|
+
blob = pickle.dumps(payload, protocol=_CACHE_PROTOCOL)
|
|
326
|
+
states = sum(len(dfa.states) for dfa in payload[1])
|
|
327
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
328
|
+
tmp = path + ".tmp-%d" % os.getpid()
|
|
329
|
+
with open(tmp, "wb") as f:
|
|
330
|
+
f.write(blob)
|
|
331
|
+
os.replace(tmp, path)
|
|
332
|
+
with _lock:
|
|
333
|
+
_state["saved"] = True
|
|
334
|
+
_state["saved_states"] = states
|
|
335
|
+
return True
|
|
336
|
+
except Exception as exc:
|
|
337
|
+
warnings.warn(
|
|
338
|
+
f"DFA cache save failed ({type(exc).__name__}: {exc}); "
|
|
339
|
+
f"parsing continues without it", stacklevel=3)
|
|
340
|
+
return False
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def maybe_load() -> None:
|
|
344
|
+
"""Lazy hook: attempt the cache load once per process."""
|
|
345
|
+
load_dfa_cache()
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def maybe_save() -> None:
|
|
349
|
+
"""Lazy hook: persist the warm cache once per process, if missing."""
|
|
350
|
+
save_dfa_cache()
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def reset_for_tests() -> None:
|
|
354
|
+
"""Reset process state (load/save flags); used by the test suite."""
|
|
355
|
+
with _lock:
|
|
356
|
+
for key in ("load_attempted", "loaded", "save_attempted",
|
|
357
|
+
"saved", "saved_states"):
|
|
358
|
+
_state[key] = False if key != "saved_states" else 0
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def stats() -> Dict[str, Any]:
|
|
362
|
+
"""Current cache state (for tests and diagnostics)."""
|
|
363
|
+
with _lock:
|
|
364
|
+
return {
|
|
365
|
+
"enabled": is_enabled(),
|
|
366
|
+
"directory": _cache_directory(),
|
|
367
|
+
"file": cache_file(),
|
|
368
|
+
"key": cache_key(),
|
|
369
|
+
"load_attempted": _state["load_attempted"],
|
|
370
|
+
"loaded": _state["loaded"],
|
|
371
|
+
"save_attempted": _state["save_attempted"],
|
|
372
|
+
"saved": _state["saved"],
|
|
373
|
+
"saved_states": _state["saved_states"],
|
|
374
|
+
}
|