sysmlpy 0.74.0__tar.gz → 0.76.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.74.0 → sysmlpy-0.76.0}/PKG-INFO +1 -1
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/pyproject.toml +1 -1
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/__init__.py +1 -1
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr_parser.py +11 -4
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/project.py +66 -10
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/semantic.py +362 -1
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/LICENSE +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/README.md +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/__main__.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/README.md +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/SysMLv2Parser.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr_visitor.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/boxes_view.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/definition.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/diff.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/evaluator.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/examples/attribute_values.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/examples/part_attributes.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/examples/tuples_sequences.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/formatting.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/README.md +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.g4 +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.g4 +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/desc.xml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/examples/camera.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/examples/toaster-system.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/examples/vehicle-model.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/antlr4/pom.xml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/grammar/classes.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/interchange.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/LICENSE +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/README.md +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/__init__.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Analysis/AnalysisTooling.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Analysis/TradeStudies.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Cause and Effect/CausationConnections.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Geometry/ShapeItems.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Geometry/SpatialItems.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Metadata/ImageMetadata.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Metadata/ParametersOfInterestMetadata.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Metadata/RiskMetadata.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQ.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAtomicNuclear.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCharacteristicNumbers.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQChemistryMolecular.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCondensedMatter.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQElectromagnetism.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQInformation.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQThermodynamics.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementRefCalculations.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementReferences.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/QuantityCalculations.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/SI.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/TensorCalculations.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/USCustomaryUnits.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/VectorCalculations.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Requirement Derivation/DerivationConnections.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Requirement Derivation/RequirementDerivation.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/Base.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/BaseFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/BooleanFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/Clocks.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/CollectionFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/Collections.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/ComplexFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/ControlFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/ControlPerformances.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/DataFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/IntegerFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/KerML.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/Links.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/Metaobjects.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/NaturalFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/NumericalFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/Objects.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/Observation.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/OccurrenceFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/Occurrences.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/Performances.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/RationalFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/RealFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/ScalarFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/ScalarValues.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/SequenceFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/SpatialFrames.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/StatePerformances.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/StringFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/Transfers.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/TransitionPerformances.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/TrigFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/Triggers.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/VectorFunctions.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/kernel/VectorValues.kerml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Actions.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Allocations.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/AnalysisCases.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Attributes.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Calculations.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Cases.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Connections.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Constraints.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Flows.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Interfaces.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Items.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Metadata.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Parts.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Ports.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Requirements.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/StandardViewDefinitions.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/States.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/SysML.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/UseCases.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/VerificationCases.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/systems/Views.sysml +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/lsp/__init__.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/lsp/__main__.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/lsp/protocol.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/lsp/server.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/lsp/stdio.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/navigate.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/plantuml.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/sim.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/spreadsheet.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/store.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/traceability.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/us_customary_units.txt +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/usage.py +0 -0
- {sysmlpy-0.74.0 → sysmlpy-0.76.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.76.0"
|
|
38
38
|
|
|
39
39
|
from sysmlpy.usage import (
|
|
40
40
|
Item, Attribute, Part, Port, Action, Reference, UseCase, Requirement, Interface, Message,
|
|
@@ -74,8 +74,9 @@ def parse(source, library=None, recover=False, prediction_mode="sll"):
|
|
|
74
74
|
prediction_mode : {"sll", "ll"}, default "sll"
|
|
75
75
|
``"sll"`` (default) runs the fast SLL pass with LL fallback.
|
|
76
76
|
``"ll"`` forces the full-context pass directly (slower; useful
|
|
77
|
-
for debugging). ``"
|
|
78
|
-
|
|
77
|
+
for debugging). ``"sll_only"`` keeps every pass in SLL
|
|
78
|
+
prediction — including the fallback pass — so diagnostics
|
|
79
|
+
reflect SLL behaviour (error parity with the fast path).
|
|
79
80
|
|
|
80
81
|
Returns
|
|
81
82
|
-------
|
|
@@ -127,14 +128,20 @@ def parse(source, library=None, recover=False, prediction_mode="sll"):
|
|
|
127
128
|
# errors but re-run without bail to build the partial tree.
|
|
128
129
|
pass
|
|
129
130
|
|
|
130
|
-
# ── Stage 2: full
|
|
131
|
+
# ── Stage 2: full parse (fallback / forced mode) ──────────────────
|
|
131
132
|
lexer, token_stream, parser = _make_parser(content)
|
|
132
133
|
error_listener = ANTLRErrorListener()
|
|
133
134
|
lexer.addErrorListener(error_listener)
|
|
134
135
|
parser.addErrorListener(error_listener)
|
|
135
136
|
from antlr4.error.ErrorStrategy import DefaultErrorStrategy
|
|
136
137
|
parser._errHandler = DefaultErrorStrategy()
|
|
137
|
-
|
|
138
|
+
# SLL error parity (Goal 10): an explicit "sll_only" request stays
|
|
139
|
+
# in SLL prediction so its diagnostics match the fast pass; every
|
|
140
|
+
# other fallback (sll -> ll, forced ll) uses full LL prediction.
|
|
141
|
+
if prediction_mode == "sll_only":
|
|
142
|
+
parser._interp.predictionMode = PredictionMode.SLL
|
|
143
|
+
else:
|
|
144
|
+
parser._interp.predictionMode = PredictionMode.LL
|
|
138
145
|
tree = parser.rootNamespace()
|
|
139
146
|
|
|
140
147
|
# Check for errors
|
|
@@ -233,17 +233,73 @@ def _extract_imports(content: str) -> list[str]:
|
|
|
233
233
|
Returns a list of qualified names like ``['ScalarValues', 'ISQ']``.
|
|
234
234
|
Handles quoted package names (e.g., ``'Some Package'``) and the
|
|
235
235
|
``all`` keyword (e.g., ``import all Types::*``).
|
|
236
|
+
|
|
237
|
+
Since v0.76.0 this scans the SysML v2 lexer token stream instead
|
|
238
|
+
of a regex over raw text (Goal 10 "regex to parser" item), which
|
|
239
|
+
fixes three defects of the old regex:
|
|
240
|
+
|
|
241
|
+
- a bare ``import X::Y;`` (no visibility keyword) was missed —
|
|
242
|
+
the visibility prefix is optional per the SysML grammar and is
|
|
243
|
+
now correctly treated as such
|
|
244
|
+
- imports inside comments produced false positives
|
|
245
|
+
- imports inside string literals (e.g. ``doc about "..."``)
|
|
246
|
+
produced false positives
|
|
247
|
+
|
|
248
|
+
Syntax-error tolerance: the lexer keeps producing tokens for
|
|
249
|
+
partially broken sources (dependency scanning must not require a
|
|
250
|
+
parseable file), so scanning continues past stray tokens; an
|
|
251
|
+
import with a stray token in its name run is skipped.
|
|
236
252
|
"""
|
|
237
|
-
imports = []
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
253
|
+
imports: list[str] = []
|
|
254
|
+
try:
|
|
255
|
+
from sysmlpy.antlr_parser import _make_parser
|
|
256
|
+
from sysmlpy.antlr.SysMLv2Lexer import SysMLv2Lexer
|
|
257
|
+
_lexer, token_stream, _parser = _make_parser(content)
|
|
258
|
+
token_stream.fill()
|
|
259
|
+
tokens = token_stream.tokens
|
|
260
|
+
except Exception:
|
|
261
|
+
return imports
|
|
262
|
+
|
|
263
|
+
from antlr4.Token import Token
|
|
264
|
+
|
|
265
|
+
visible = [t for t in tokens
|
|
266
|
+
if t.type != Token.EOF
|
|
267
|
+
and t.channel == Token.DEFAULT_CHANNEL]
|
|
268
|
+
|
|
269
|
+
NAME_TYPES = frozenset((SysMLv2Lexer.IDENTIFIER, SysMLv2Lexer.STRING))
|
|
270
|
+
COLON_COLON = SysMLv2Lexer.COLON_COLON
|
|
271
|
+
STAR = SysMLv2Lexer.STAR
|
|
272
|
+
STAR_STAR = SysMLv2Lexer.STAR_STAR
|
|
273
|
+
SEMI = SysMLv2Lexer.SEMI
|
|
274
|
+
ALL = SysMLv2Lexer.ALL
|
|
275
|
+
|
|
276
|
+
i = 0
|
|
277
|
+
n = len(visible)
|
|
278
|
+
while i < n:
|
|
279
|
+
tok = visible[i]
|
|
280
|
+
if tok.type != SysMLv2Lexer.IMPORT:
|
|
281
|
+
i += 1
|
|
282
|
+
continue
|
|
283
|
+
# Collect the import run up to the terminating ';'
|
|
284
|
+
j = i + 1
|
|
285
|
+
parts: list[str] = []
|
|
286
|
+
aborted = False
|
|
287
|
+
while j < n and visible[j].type != SEMI:
|
|
288
|
+
t = visible[j]
|
|
289
|
+
if t.type in NAME_TYPES:
|
|
290
|
+
parts.append(t.text)
|
|
291
|
+
elif t.type in (ALL, COLON_COLON, STAR, STAR_STAR):
|
|
292
|
+
pass # 'all' keyword, namespace separators, wildcards
|
|
293
|
+
else:
|
|
294
|
+
aborted = True # stray token — not a well-formed import
|
|
295
|
+
break
|
|
296
|
+
j += 1
|
|
297
|
+
if parts and not aborted:
|
|
298
|
+
imports.append("::".join(parts))
|
|
299
|
+
# advance past the run (or the aborted token) and its ';' if present
|
|
300
|
+
i = j
|
|
301
|
+
if i < n and visible[i].type == SEMI:
|
|
302
|
+
i += 1
|
|
247
303
|
return imports
|
|
248
304
|
|
|
249
305
|
|
|
@@ -1533,6 +1533,22 @@ def _parse_dimension(dim: Optional[str]) -> Optional[dict[str, int]]:
|
|
|
1533
1533
|
return dims
|
|
1534
1534
|
|
|
1535
1535
|
|
|
1536
|
+
def _dims_mul(a: dict[str, int], b: dict[str, int]) -> dict[str, int]:
|
|
1537
|
+
"""Multiply two dimension dicts (add exponents, drop zeros)."""
|
|
1538
|
+
out = dict(a)
|
|
1539
|
+
for k, v in b.items():
|
|
1540
|
+
out[k] = out.get(k, 0) + v
|
|
1541
|
+
return {k: v for k, v in out.items() if v != 0}
|
|
1542
|
+
|
|
1543
|
+
|
|
1544
|
+
def _dims_div(a: dict[str, int], b: dict[str, int]) -> dict[str, int]:
|
|
1545
|
+
"""Divide two dimension dicts (subtract exponents, drop zeros)."""
|
|
1546
|
+
out = dict(a)
|
|
1547
|
+
for k, v in b.items():
|
|
1548
|
+
out[k] = out.get(k, 0) - v
|
|
1549
|
+
return {k: v for k, v in out.items() if v != 0}
|
|
1550
|
+
|
|
1551
|
+
|
|
1536
1552
|
def _dimension_to_pint(dims: Optional[dict[str, int]]) -> Optional[Any]:
|
|
1537
1553
|
"""Map a SysML dimension dict to a pint dimensionality.
|
|
1538
1554
|
|
|
@@ -2107,6 +2123,263 @@ class ExpressionTypeChecker:
|
|
|
2107
2123
|
if lhs_cat in ("boolean", "string") or rhs_cat in ("boolean", "string"):
|
|
2108
2124
|
self._emit_mismatch(op, lhs_cat, rhs_cat, element, issues)
|
|
2109
2125
|
|
|
2126
|
+
# -- unit-dimension derivation (Goal 10) ---------------------------------
|
|
2127
|
+
|
|
2128
|
+
def check_derivations(self, model: Any) -> list[SemanticIssue]:
|
|
2129
|
+
"""Derive ``*`` / ``/`` dimension algebra and compare with typing.
|
|
2130
|
+
|
|
2131
|
+
For every expression owner whose declared type carries a known
|
|
2132
|
+
quantity dimension (library ``*Value`` / ``*Unit`` definitions),
|
|
2133
|
+
the initializer's dimension is derived algebraically:
|
|
2134
|
+
|
|
2135
|
+
- ``a * b`` adds exponents, ``a / b`` subtracts them
|
|
2136
|
+
- ``a ** n`` (literal integer ``n``) multiplies them
|
|
2137
|
+
- ``+`` / ``-`` chains require equal operand dimensions
|
|
2138
|
+
- dimensionless literals are the multiplicative identity
|
|
2139
|
+
|
|
2140
|
+
A mismatch between the derived dimension and the declared
|
|
2141
|
+
typing is reported as ``UNIT_DIMENSION_DERIVATION_MISMATCH``.
|
|
2142
|
+
Conservative skips: any operand with unknown dimension, non-
|
|
2143
|
+
literal exponents, ``%``, boolean/string/relational levels,
|
|
2144
|
+
and initializers with no quantity-typed operand at all (a bare
|
|
2145
|
+
literal like ``= 70`` cannot reveal its intended unit).
|
|
2146
|
+
"""
|
|
2147
|
+
issues: list[SemanticIssue] = []
|
|
2148
|
+
self._walk_derivation_owners(model, issues, [])
|
|
2149
|
+
return issues
|
|
2150
|
+
|
|
2151
|
+
def _walk_derivation_owners(
|
|
2152
|
+
self,
|
|
2153
|
+
element: Any,
|
|
2154
|
+
issues: list[SemanticIssue],
|
|
2155
|
+
scope_path: list[str],
|
|
2156
|
+
) -> None:
|
|
2157
|
+
if element is None:
|
|
2158
|
+
return
|
|
2159
|
+
name = getattr(element, "name", None)
|
|
2160
|
+
elem_type = type(element).__name__
|
|
2161
|
+
is_container = getattr(element, "is_definition", False) or elem_type == "Package"
|
|
2162
|
+
child_scope = scope_path
|
|
2163
|
+
if is_container and name is not None and elem_type != "Model":
|
|
2164
|
+
child_scope = scope_path + [name]
|
|
2165
|
+
|
|
2166
|
+
if elem_type in _EXPRESSION_OWNER_TYPES:
|
|
2167
|
+
grammar = getattr(element, "grammar", None)
|
|
2168
|
+
if grammar is not None:
|
|
2169
|
+
typed = getattr(element, "typed_by_name", None)
|
|
2170
|
+
if typed:
|
|
2171
|
+
declared = self._declared_dimension(str(typed))
|
|
2172
|
+
if declared is not None:
|
|
2173
|
+
try:
|
|
2174
|
+
grammar_def = grammar.get_definition()
|
|
2175
|
+
except Exception:
|
|
2176
|
+
grammar_def = None
|
|
2177
|
+
if grammar_def is not None:
|
|
2178
|
+
for expr in _find_owned_expressions(grammar_def):
|
|
2179
|
+
self._check_derivation(
|
|
2180
|
+
expr, element, str(typed), declared,
|
|
2181
|
+
scope_path, issues)
|
|
2182
|
+
|
|
2183
|
+
for child in getattr(element, "children", []):
|
|
2184
|
+
self._walk_derivation_owners(child, issues, child_scope)
|
|
2185
|
+
|
|
2186
|
+
def _declared_dimension(self, type_name: str) -> Optional[dict[str, int]]:
|
|
2187
|
+
"""Dimension dict for a declared type name, or None when unknown."""
|
|
2188
|
+
dim_str = self._dimensions.get(type_name)
|
|
2189
|
+
if not dim_str:
|
|
2190
|
+
simple = type_name.rsplit("::", 1)[-1]
|
|
2191
|
+
dim_str = self._dimensions.get(simple)
|
|
2192
|
+
if not dim_str:
|
|
2193
|
+
return None
|
|
2194
|
+
return _parse_dimension(dim_str)
|
|
2195
|
+
|
|
2196
|
+
def _check_derivation(
|
|
2197
|
+
self,
|
|
2198
|
+
expr_dict: dict,
|
|
2199
|
+
element: Any,
|
|
2200
|
+
type_name: str,
|
|
2201
|
+
declared: dict[str, int],
|
|
2202
|
+
scope_path: list[str],
|
|
2203
|
+
issues: list[SemanticIssue],
|
|
2204
|
+
) -> None:
|
|
2205
|
+
node = expr_dict.get("expression")
|
|
2206
|
+
if not isinstance(node, dict):
|
|
2207
|
+
return
|
|
2208
|
+
derived, contributed = self._derive_dimension(node, scope_path)
|
|
2209
|
+
if derived is None or not contributed:
|
|
2210
|
+
return
|
|
2211
|
+
if derived != declared:
|
|
2212
|
+
issues.append(SemanticIssue(
|
|
2213
|
+
severity="error",
|
|
2214
|
+
code="UNIT_DIMENSION_DERIVATION_MISMATCH",
|
|
2215
|
+
message=(
|
|
2216
|
+
f"Initializer of '{getattr(element, 'name', '?')}' derives "
|
|
2217
|
+
f"dimension '{_format_dimension(derived)}' but declared type "
|
|
2218
|
+
f"'{type_name}' has dimension '{_format_dimension(declared)}'"
|
|
2219
|
+
),
|
|
2220
|
+
element=element,
|
|
2221
|
+
reference=_format_dimension(declared),
|
|
2222
|
+
))
|
|
2223
|
+
|
|
2224
|
+
def _derive_dimension(
|
|
2225
|
+
self,
|
|
2226
|
+
node: Any,
|
|
2227
|
+
scope_path: list[str],
|
|
2228
|
+
) -> tuple:
|
|
2229
|
+
"""Algebraically derive the dimension of an expression dict.
|
|
2230
|
+
|
|
2231
|
+
Returns ``(dims, contributed)`` where ``dims`` is ``None`` when
|
|
2232
|
+
the expression is not statically derivable and ``contributed``
|
|
2233
|
+
is True when at least one quantity-typed operand was seen
|
|
2234
|
+
(bare-literal initializers stay silent).
|
|
2235
|
+
"""
|
|
2236
|
+
if not isinstance(node, dict):
|
|
2237
|
+
return (None, False)
|
|
2238
|
+
name = node.get("name")
|
|
2239
|
+
|
|
2240
|
+
if name == "OwnedExpression":
|
|
2241
|
+
return self._derive_dimension(node.get("expression"), scope_path)
|
|
2242
|
+
if name == "ConditionalExpression":
|
|
2243
|
+
operands = node.get("operand", []) or []
|
|
2244
|
+
if len(operands) != 1:
|
|
2245
|
+
return (None, False)
|
|
2246
|
+
return self._derive_dimension(operands[0], scope_path)
|
|
2247
|
+
|
|
2248
|
+
# Operator-less levels are pure wrappers (the visitor always
|
|
2249
|
+
# emits the full NullCoalescing → Implies → … chain); with an
|
|
2250
|
+
# operator present the level is boolean-valued — not derivable.
|
|
2251
|
+
if name == "NullCoalescingExpression":
|
|
2252
|
+
if node.get("operator"):
|
|
2253
|
+
return (None, False)
|
|
2254
|
+
return self._derive_dimension(node.get("implies"), scope_path)
|
|
2255
|
+
if name in ("ImpliesExpression", "OrExpression", "XorExpression",
|
|
2256
|
+
"AndExpression"):
|
|
2257
|
+
if node.get("operator") or node.get("operand") \
|
|
2258
|
+
or node.get("operation"):
|
|
2259
|
+
return (None, False)
|
|
2260
|
+
child_key = {"ImpliesExpression": "or",
|
|
2261
|
+
"OrExpression": "xor",
|
|
2262
|
+
"XorExpression": "and",
|
|
2263
|
+
"AndExpression": "equality"}[name]
|
|
2264
|
+
return self._derive_dimension(node.get(child_key), scope_path)
|
|
2265
|
+
if name == "EqualityExpression":
|
|
2266
|
+
if node.get("operation"):
|
|
2267
|
+
return (None, False)
|
|
2268
|
+
return self._derive_dimension(
|
|
2269
|
+
node.get("classification"), scope_path)
|
|
2270
|
+
if name == "ClassificationExpression":
|
|
2271
|
+
if node.get("operator"):
|
|
2272
|
+
return (None, False)
|
|
2273
|
+
return self._derive_dimension(
|
|
2274
|
+
node.get("relational"), scope_path)
|
|
2275
|
+
if name == "RelationalExpression":
|
|
2276
|
+
if node.get("operation"):
|
|
2277
|
+
return (None, False)
|
|
2278
|
+
return self._derive_dimension(node.get("range"), scope_path)
|
|
2279
|
+
|
|
2280
|
+
if name == "RangeExpression":
|
|
2281
|
+
if node.get("operator"):
|
|
2282
|
+
return (None, False) # a .. b — bounds may differ
|
|
2283
|
+
return self._derive_dimension(node.get("additive"), scope_path)
|
|
2284
|
+
|
|
2285
|
+
if name == "AdditiveExpression":
|
|
2286
|
+
dims, contributed = self._derive_dimension(
|
|
2287
|
+
node.get("multiplicitive"), scope_path)
|
|
2288
|
+
for op_dict in node.get("operation", []) or []:
|
|
2289
|
+
if not isinstance(op_dict, dict):
|
|
2290
|
+
continue
|
|
2291
|
+
op = op_dict.get("operator")
|
|
2292
|
+
rhs, c = self._derive_dimension(
|
|
2293
|
+
op_dict.get("operand"), scope_path)
|
|
2294
|
+
if op not in ("+", "-") or dims is None or rhs is None \
|
|
2295
|
+
or dims != rhs:
|
|
2296
|
+
return (None, False)
|
|
2297
|
+
contributed = contributed or c
|
|
2298
|
+
return (dims, contributed)
|
|
2299
|
+
|
|
2300
|
+
if name == "MultiplicativeExpression":
|
|
2301
|
+
dims, contributed = self._derive_dimension(
|
|
2302
|
+
node.get("exponential"), scope_path)
|
|
2303
|
+
for op_dict in node.get("operation", []) or []:
|
|
2304
|
+
if not isinstance(op_dict, dict):
|
|
2305
|
+
continue
|
|
2306
|
+
op = op_dict.get("operator")
|
|
2307
|
+
rhs, c = self._derive_dimension(
|
|
2308
|
+
op_dict.get("operand"), scope_path)
|
|
2309
|
+
if dims is None or rhs is None:
|
|
2310
|
+
return (None, False)
|
|
2311
|
+
contributed = contributed or c
|
|
2312
|
+
if op == "*":
|
|
2313
|
+
dims = _dims_mul(dims, rhs)
|
|
2314
|
+
elif op == "/":
|
|
2315
|
+
dims = _dims_div(dims, rhs)
|
|
2316
|
+
else: # '%' and anything else — not derivable
|
|
2317
|
+
return (None, False)
|
|
2318
|
+
return (dims, contributed)
|
|
2319
|
+
|
|
2320
|
+
if name == "ExponentiationExpression":
|
|
2321
|
+
dims, contributed = self._derive_dimension(
|
|
2322
|
+
node.get("unary"), scope_path)
|
|
2323
|
+
if dims is None:
|
|
2324
|
+
return (None, False)
|
|
2325
|
+
# Two shapes: parallel operator/operand lists (visitor form)
|
|
2326
|
+
# or operation entries with nested operator/operand dicts.
|
|
2327
|
+
operator_list = node.get("operator")
|
|
2328
|
+
if isinstance(operator_list, list) and operator_list:
|
|
2329
|
+
operand_list = node.get("operand", []) or []
|
|
2330
|
+
for op, rhs_node in zip(operator_list, operand_list):
|
|
2331
|
+
if op not in ("**", "^"):
|
|
2332
|
+
return (None, False)
|
|
2333
|
+
exponent = const_fold(rhs_node)
|
|
2334
|
+
if not isinstance(exponent, int) \
|
|
2335
|
+
or isinstance(exponent, bool):
|
|
2336
|
+
return (None, False)
|
|
2337
|
+
dims = {k: v * exponent for k, v in dims.items()}
|
|
2338
|
+
return (dims, contributed)
|
|
2339
|
+
for op_dict in node.get("operation", []) or []:
|
|
2340
|
+
if not isinstance(op_dict, dict):
|
|
2341
|
+
continue
|
|
2342
|
+
op = op_dict.get("operator")
|
|
2343
|
+
rhs_node = op_dict.get("operand")
|
|
2344
|
+
if op not in ("**", "^"):
|
|
2345
|
+
return (None, False)
|
|
2346
|
+
exponent = const_fold(rhs_node)
|
|
2347
|
+
if not isinstance(exponent, int) or isinstance(exponent, bool):
|
|
2348
|
+
return (None, False)
|
|
2349
|
+
dims = {k: v * exponent for k, v in dims.items()}
|
|
2350
|
+
return (dims, contributed)
|
|
2351
|
+
|
|
2352
|
+
if name == "UnaryExpression":
|
|
2353
|
+
op = node.get("operator")
|
|
2354
|
+
if op and op not in ("-", "+"):
|
|
2355
|
+
return (None, False) # 'not' etc. — boolean
|
|
2356
|
+
return self._derive_leaf(node.get("extent"), scope_path)
|
|
2357
|
+
|
|
2358
|
+
if name in ("ExtentExpression", "PrimaryExpression", "BaseExpression"):
|
|
2359
|
+
return self._derive_leaf(node, scope_path)
|
|
2360
|
+
|
|
2361
|
+
# Leaf nodes (FeatureReferenceExpression etc.)
|
|
2362
|
+
return self._derive_leaf(node, scope_path)
|
|
2363
|
+
|
|
2364
|
+
def _derive_leaf(self, node: Any, scope_path: list[str]) -> tuple:
|
|
2365
|
+
"""Dimension of a leaf operand: literal, typed reference or unwrap."""
|
|
2366
|
+
if not isinstance(node, dict):
|
|
2367
|
+
return (None, False)
|
|
2368
|
+
if node.get("name") in ("LiteralInteger", "LiteralReal",
|
|
2369
|
+
"LiteralInfinity"):
|
|
2370
|
+
return ({}, False)
|
|
2371
|
+
dims = self._dimension_of_operand(node, scope_path)
|
|
2372
|
+
if dims is not None:
|
|
2373
|
+
return (dims, True)
|
|
2374
|
+
# Parenthesized / wrapped operands: descend through wrapper keys
|
|
2375
|
+
for key in ("primary", "base", "expression", "ownedRelationship"):
|
|
2376
|
+
child = node.get(key)
|
|
2377
|
+
if isinstance(child, dict):
|
|
2378
|
+
result = self._derive_dimension(child, scope_path)
|
|
2379
|
+
if result[0] is not None:
|
|
2380
|
+
return result
|
|
2381
|
+
return (None, False)
|
|
2382
|
+
|
|
2110
2383
|
# -- unit dimension safety ---------------------------------------------
|
|
2111
2384
|
|
|
2112
2385
|
def _check_unit_dimensions(self, op, lhs, rhs, element, scope_path, issues) -> None:
|
|
@@ -2500,6 +2773,8 @@ class SemanticAnalyzer:
|
|
|
2500
2773
|
# Step 4c: Expression type checking & unit-dimension safety
|
|
2501
2774
|
# (v0.55.0 Phase C).
|
|
2502
2775
|
issues.extend(self._check_expression_types(model, symtab, lib_roots))
|
|
2776
|
+
issues.extend(
|
|
2777
|
+
self._check_expression_derivations(model, symtab, lib_roots))
|
|
2503
2778
|
|
|
2504
2779
|
# Step 5: OCL well-formedness constraints
|
|
2505
2780
|
issues.extend(self._check_duplicate_names(symtab))
|
|
@@ -3100,6 +3375,16 @@ class SemanticAnalyzer:
|
|
|
3100
3375
|
checker = ExpressionTypeChecker(self, symtab, lib_roots)
|
|
3101
3376
|
return checker.check_units(model)
|
|
3102
3377
|
|
|
3378
|
+
def _check_expression_derivations(
|
|
3379
|
+
self,
|
|
3380
|
+
model: Any,
|
|
3381
|
+
symtab: SymbolTable,
|
|
3382
|
+
lib_roots: list[Path] | None = None,
|
|
3383
|
+
) -> list[SemanticIssue]:
|
|
3384
|
+
"""Derive ``*``/``/`` dimension algebra vs declared typing."""
|
|
3385
|
+
checker = ExpressionTypeChecker(self, symtab, lib_roots)
|
|
3386
|
+
return checker.check_derivations(model)
|
|
3387
|
+
|
|
3103
3388
|
# -- OCL well-formedness constraints ------------------------------------
|
|
3104
3389
|
|
|
3105
3390
|
def _check_trigger_payloads(
|
|
@@ -3560,7 +3845,7 @@ class SemanticAnalyzer:
|
|
|
3560
3845
|
return issues
|
|
3561
3846
|
|
|
3562
3847
|
def _check_connector_directions(self, model: Any) -> list[SemanticIssue]:
|
|
3563
|
-
"""Check connection
|
|
3848
|
+
"""Check connection ends: directions (Goal 9) + types (Goal 10).
|
|
3564
3849
|
|
|
3565
3850
|
``connection c connect a.p1 to b.p2;`` — when both end ports
|
|
3566
3851
|
carry explicit directions and neither is ``inout``, wiring
|
|
@@ -3570,6 +3855,14 @@ class SemanticAnalyzer:
|
|
|
3570
3855
|
error). Ends without a direction keyword, ``inout`` ends,
|
|
3571
3856
|
chains deeper than two segments and unresolvable parts are
|
|
3572
3857
|
skipped.
|
|
3858
|
+
|
|
3859
|
+
Goal 10 (connector-end compatibility depth): when both ends
|
|
3860
|
+
resolve to typings that are local ``port def`` names and
|
|
3861
|
+
neither is a (transitive) specialization of the other, the
|
|
3862
|
+
connection flags CONNECTOR_END_TYPE_MISMATCH (warning) —
|
|
3863
|
+
conjugation only makes ports of the *same* (or related) port
|
|
3864
|
+
definition compatible. Ends typed by library/external port
|
|
3865
|
+
definitions are skipped (no local subclass data).
|
|
3573
3866
|
"""
|
|
3574
3867
|
issues: list[SemanticIssue] = []
|
|
3575
3868
|
try:
|
|
@@ -3582,6 +3875,7 @@ class SemanticAnalyzer:
|
|
|
3582
3875
|
part_typing: dict = {} # part usage name -> typed-by name
|
|
3583
3876
|
member_typing: dict = {} # (container name, member) -> typed-by
|
|
3584
3877
|
supertypes: dict = {} # def name -> {superclassifier names}
|
|
3878
|
+
port_defs: set = set() # local port def names (Goal 10)
|
|
3585
3879
|
connections: list = [] # (name, scope_stack, [chain, ...])
|
|
3586
3880
|
|
|
3587
3881
|
def walk2(node, scope_stack):
|
|
@@ -3612,6 +3906,8 @@ class SemanticAnalyzer:
|
|
|
3612
3906
|
if sups:
|
|
3613
3907
|
supertypes.setdefault(declared, set()).update(
|
|
3614
3908
|
sups)
|
|
3909
|
+
if nm == "PortDefinition":
|
|
3910
|
+
port_defs.add(declared)
|
|
3615
3911
|
if nm == "PortUsage":
|
|
3616
3912
|
d = _port_direction(node)
|
|
3617
3913
|
if scope_stack:
|
|
@@ -3715,6 +4011,55 @@ class SemanticAnalyzer:
|
|
|
3715
4011
|
return None, False # known container, no such port
|
|
3716
4012
|
return None, True # external/library type: skip
|
|
3717
4013
|
|
|
4014
|
+
def end_typing(chain, scope_stack):
|
|
4015
|
+
"""Typed-by name of an end chain's final segment, or None."""
|
|
4016
|
+
if not chain:
|
|
4017
|
+
return None
|
|
4018
|
+
if len(chain) == 1:
|
|
4019
|
+
name = chain[0]
|
|
4020
|
+
for scope in reversed(scope_stack):
|
|
4021
|
+
t = member_typing.get((scope, name))
|
|
4022
|
+
if t:
|
|
4023
|
+
return t
|
|
4024
|
+
return part_typing.get(name)
|
|
4025
|
+
first = chain[0]
|
|
4026
|
+
cur = part_typing.get(first)
|
|
4027
|
+
if cur is None:
|
|
4028
|
+
for scope in reversed(scope_stack):
|
|
4029
|
+
t = member_typing.get((scope, first))
|
|
4030
|
+
if t:
|
|
4031
|
+
cur = t
|
|
4032
|
+
break
|
|
4033
|
+
if cur is None:
|
|
4034
|
+
return None
|
|
4035
|
+
for seg in chain[1:-1]:
|
|
4036
|
+
t = member_typing.get((cur, seg))
|
|
4037
|
+
if t is None:
|
|
4038
|
+
t = member_typing.get((first, seg))
|
|
4039
|
+
if t is None:
|
|
4040
|
+
return None
|
|
4041
|
+
cur = t
|
|
4042
|
+
t = member_typing.get((cur, chain[-1]))
|
|
4043
|
+
if t is None:
|
|
4044
|
+
t = member_typing.get((first, chain[-1]))
|
|
4045
|
+
return t
|
|
4046
|
+
|
|
4047
|
+
def _sub(a, b):
|
|
4048
|
+
"""True when a is b or a (transitively) specializes b."""
|
|
4049
|
+
if a == b:
|
|
4050
|
+
return True
|
|
4051
|
+
seen = set()
|
|
4052
|
+
stack = [a]
|
|
4053
|
+
while stack:
|
|
4054
|
+
cur = stack.pop()
|
|
4055
|
+
if cur == b:
|
|
4056
|
+
return True
|
|
4057
|
+
if cur in seen:
|
|
4058
|
+
continue
|
|
4059
|
+
seen.add(cur)
|
|
4060
|
+
stack.extend(supertypes.get(cur, ()))
|
|
4061
|
+
return False
|
|
4062
|
+
|
|
3718
4063
|
for cname, cstack, chains in connections:
|
|
3719
4064
|
d1, r1 = end_resolve(chains[0], cstack)
|
|
3720
4065
|
d2, r2 = end_resolve(chains[1], cstack)
|
|
@@ -3736,6 +4081,22 @@ class SemanticAnalyzer:
|
|
|
3736
4081
|
f"'{'.'.join(chains[1])}' does not resolve"),
|
|
3737
4082
|
reference=cname,
|
|
3738
4083
|
))
|
|
4084
|
+
# Goal 10: end-type compatibility (port defs, local only)
|
|
4085
|
+
t1 = end_typing(chains[0], cstack)
|
|
4086
|
+
t2 = end_typing(chains[1], cstack)
|
|
4087
|
+
if (t1 and t2 and t1 in port_defs and t2 in port_defs
|
|
4088
|
+
and not _sub(t1, t2) and not _sub(t2, t1)):
|
|
4089
|
+
issues.append(SemanticIssue(
|
|
4090
|
+
severity="warning",
|
|
4091
|
+
code="CONNECTOR_END_TYPE_MISMATCH",
|
|
4092
|
+
message=(
|
|
4093
|
+
f"Connection '{cname}' binds "
|
|
4094
|
+
f"'{'.'.join(chains[0])}' (typed '{t1}') to "
|
|
4095
|
+
f"'{'.'.join(chains[1])}' (typed '{t2}'); "
|
|
4096
|
+
"connected port definitions are unrelated"
|
|
4097
|
+
),
|
|
4098
|
+
reference=cname,
|
|
4099
|
+
))
|
|
3739
4100
|
if not d1 or not d2:
|
|
3740
4101
|
continue
|
|
3741
4102
|
if d1 == "inout" or d2 == "inout":
|
|
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.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp
RENAMED
|
File without changes
|
{sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py
RENAMED
|
File without changes
|
{sysmlpy-0.74.0 → sysmlpy-0.76.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.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.74.0 → sysmlpy-0.76.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.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml
RENAMED
|
File without changes
|
|
File without changes
|
{sysmlpy-0.74.0 → sysmlpy-0.76.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.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.74.0 → sysmlpy-0.76.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.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.74.0 → sysmlpy-0.76.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml
RENAMED
|
File without changes
|
|
File without changes
|
{sysmlpy-0.74.0 → sysmlpy-0.76.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.74.0 → sysmlpy-0.76.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
|