sysmlpy 0.58.0__tar.gz → 0.60.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.58.0 → sysmlpy-0.60.0}/PKG-INFO +1 -1
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/pyproject.toml +1 -1
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/__init__.py +1 -1
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr_visitor.py +14 -5
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/classes.py +5 -4
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/semantic.py +240 -32
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/LICENSE +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/README.md +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/__main__.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/README.md +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Parser.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr_parser.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/boxes_view.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/definition.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/examples/attribute_values.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/examples/part_attributes.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/examples/tuples_sequences.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/formatting.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/README.md +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.g4 +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.g4 +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/desc.xml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/examples/camera.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/examples/toaster-system.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/examples/vehicle-model.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/pom.xml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/LICENSE +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/README.md +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/__init__.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Analysis/AnalysisTooling.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Analysis/TradeStudies.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Cause and Effect/CausationConnections.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Geometry/ShapeItems.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Geometry/SpatialItems.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Metadata/ImageMetadata.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Metadata/ParametersOfInterestMetadata.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Metadata/RiskMetadata.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQ.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAtomicNuclear.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCharacteristicNumbers.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQChemistryMolecular.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCondensedMatter.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQElectromagnetism.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQInformation.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQThermodynamics.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementRefCalculations.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementReferences.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/QuantityCalculations.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/SI.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/TensorCalculations.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/USCustomaryUnits.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/VectorCalculations.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Requirement Derivation/DerivationConnections.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Requirement Derivation/RequirementDerivation.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Base.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/BaseFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/BooleanFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Clocks.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/CollectionFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Collections.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/ComplexFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/ControlFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/ControlPerformances.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/DataFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/IntegerFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/KerML.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Links.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Metaobjects.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/NaturalFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/NumericalFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Objects.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Observation.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/OccurrenceFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Occurrences.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Performances.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/RationalFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/RealFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/ScalarFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/ScalarValues.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/SequenceFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/SpatialFrames.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/StatePerformances.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/StringFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Transfers.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/TransitionPerformances.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/TrigFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Triggers.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/VectorFunctions.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/VectorValues.kerml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Actions.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Allocations.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/AnalysisCases.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Attributes.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Calculations.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Cases.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Connections.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Constraints.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Flows.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Interfaces.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Items.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Metadata.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Parts.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Ports.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Requirements.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/StandardViewDefinitions.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/States.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/SysML.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/UseCases.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/VerificationCases.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Views.sysml +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/navigate.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/plantuml.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/project.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/store.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/us_customary_units.txt +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/usage.py +0 -0
- {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/validator.py +0 -0
|
@@ -25,7 +25,7 @@ __all__ = [
|
|
|
25
25
|
"render_state_transition_view_svg", "boxes_view",
|
|
26
26
|
]
|
|
27
27
|
__author__ = "Jon Fox"
|
|
28
|
-
__version__ = "0.
|
|
28
|
+
__version__ = "0.60.0"
|
|
29
29
|
|
|
30
30
|
from sysmlpy.usage import (
|
|
31
31
|
Item, Attribute, Part, Port, Action, Reference, UseCase, Requirement, Interface, Message,
|
|
@@ -7148,10 +7148,12 @@ def _extract_multiplicity_from_mp(mp_ctx):
|
|
|
7148
7148
|
else:
|
|
7149
7149
|
return None
|
|
7150
7150
|
|
|
7151
|
+
is_ordered = bool(mp_ctx.ORDERED()) if hasattr(mp_ctx, 'ORDERED') else False
|
|
7152
|
+
is_nonunique = bool(mp_ctx.NONUNIQUE()) if hasattr(mp_ctx, 'NONUNIQUE') else False
|
|
7151
7153
|
return {
|
|
7152
7154
|
"name": "MultiplicityPart",
|
|
7153
|
-
"isOrdered":
|
|
7154
|
-
"isNonunique":
|
|
7155
|
+
"isOrdered": is_ordered,
|
|
7156
|
+
"isNonunique": is_nonunique,
|
|
7155
7157
|
"ownedRelationship": [
|
|
7156
7158
|
{
|
|
7157
7159
|
"name": "OwnedMultiplicity",
|
|
@@ -13597,11 +13599,18 @@ def _get_multiplicity_part(fsp_ctx):
|
|
|
13597
13599
|
bound_dicts = [_make_bound(members[0].getText()), _make_bound(members[1].getText())]
|
|
13598
13600
|
else:
|
|
13599
13601
|
return None
|
|
13600
|
-
|
|
13602
|
+
|
|
13603
|
+
# ORDERED / NONUNIQUE indicators follow ownedMultiplicity in
|
|
13604
|
+
# multiplicityPart (grammar: `ownedMultiplicity ( ORDERED ( NONUNIQUE )?
|
|
13605
|
+
# | NONUNIQUE ( ORDERED )? )?`). Previously hardcoded False, silently
|
|
13606
|
+
# dropping the keywords on dump.
|
|
13607
|
+
is_ordered = bool(mp_ctx.ORDERED()) if hasattr(mp_ctx, 'ORDERED') else False
|
|
13608
|
+
is_nonunique = bool(mp_ctx.NONUNIQUE()) if hasattr(mp_ctx, 'NONUNIQUE') else False
|
|
13609
|
+
|
|
13601
13610
|
return {
|
|
13602
13611
|
"name": "MultiplicityPart",
|
|
13603
|
-
"isOrdered":
|
|
13604
|
-
"isNonunique":
|
|
13612
|
+
"isOrdered": is_ordered,
|
|
13613
|
+
"isNonunique": is_nonunique,
|
|
13605
13614
|
"ownedRelationship": [
|
|
13606
13615
|
{
|
|
13607
13616
|
"name": "OwnedMultiplicity",
|
|
@@ -8380,15 +8380,16 @@ class MultiplicityPart:
|
|
|
8380
8380
|
def dump(self):
|
|
8381
8381
|
output = [child.dump() for child in self.children]
|
|
8382
8382
|
|
|
8383
|
-
|
|
8383
|
+
# isOrdered/isOrdered2 are populated from the same dict field during
|
|
8384
|
+
# round-trip (the ANTLR dict carries a single isOrdered flag), so the
|
|
8385
|
+
# X OR Y logic below never fired — silently dropping the keyword on
|
|
8386
|
+
# `attribute x[3] ordered;`. Emit whichever flag is set (v0.59.0).
|
|
8387
|
+
if self.isOrdered or self.isOrdered2:
|
|
8384
8388
|
output.append("ordered")
|
|
8385
8389
|
|
|
8386
8390
|
if self.isNonunique or self.isNonunique2:
|
|
8387
8391
|
output.append("nonunique")
|
|
8388
8392
|
|
|
8389
|
-
if self.isOrdered2 and not self.isOrdered:
|
|
8390
|
-
output.append("ordered")
|
|
8391
|
-
|
|
8392
8393
|
return " ".join(output)
|
|
8393
8394
|
|
|
8394
8395
|
def get_definition(self):
|
|
@@ -821,16 +821,21 @@ class SymbolTable:
|
|
|
821
821
|
class ReferenceCollector:
|
|
822
822
|
"""Collect all qualified-name references from a model's grammar tree.
|
|
823
823
|
|
|
824
|
-
Returns list of ``(qualified_name_str, element, scope_path)`` tuples
|
|
825
|
-
``scope_path`` is the list of scope names from root to the element
|
|
824
|
+
Returns list of ``(qualified_name_str, element, scope_path, kind)`` tuples
|
|
825
|
+
where ``scope_path`` is the list of scope names from root to the element
|
|
826
|
+
and ``kind`` is the reference relationship: ``"typing"``, ``"subsetting"``,
|
|
827
|
+
``"redefinition"``, or ``"subclassification"``. The kind lets the
|
|
828
|
+
feature-chain check (v0.60.0) tell genuine feature chains (subsetting /
|
|
829
|
+
redefinition) apart from *type* references (typings / subclassification),
|
|
830
|
+
which are namespace paths and must not be chain-checked.
|
|
826
831
|
"""
|
|
827
832
|
|
|
828
|
-
def collect(self, model: Any) -> list[tuple[str, Any, list[str]]]:
|
|
829
|
-
results: list[tuple[str, Any, list[str]]] = []
|
|
833
|
+
def collect(self, model: Any) -> list[tuple[str, Any, list[str], str]]:
|
|
834
|
+
results: list[tuple[str, Any, list[str], str]] = []
|
|
830
835
|
self._walk(model, results, [])
|
|
831
836
|
return results
|
|
832
837
|
|
|
833
|
-
def _walk(self, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]) -> None:
|
|
838
|
+
def _walk(self, element: Any, results: list[tuple[str, Any, list[str], str]], scope_path: list[str]) -> None:
|
|
834
839
|
if element is None:
|
|
835
840
|
return
|
|
836
841
|
|
|
@@ -850,7 +855,7 @@ class ReferenceCollector:
|
|
|
850
855
|
self._walk(child, results, child_scope)
|
|
851
856
|
|
|
852
857
|
def _extract_from_grammar(
|
|
853
|
-
self, grammar: Any, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]
|
|
858
|
+
self, grammar: Any, element: Any, results: list[tuple[str, Any, list[str], str]], scope_path: list[str]
|
|
854
859
|
) -> None:
|
|
855
860
|
usage = getattr(grammar, "usage", None)
|
|
856
861
|
if usage is None:
|
|
@@ -874,7 +879,7 @@ class ReferenceCollector:
|
|
|
874
879
|
self._collect_specialization_part(spec, element, results, scope_path)
|
|
875
880
|
|
|
876
881
|
def _collect_specialization_part(
|
|
877
|
-
self, spec: Any, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]
|
|
882
|
+
self, spec: Any, element: Any, results: list[tuple[str, Any, list[str], str]], scope_path: list[str]
|
|
878
883
|
) -> None:
|
|
879
884
|
if spec is None:
|
|
880
885
|
return
|
|
@@ -886,7 +891,7 @@ class ReferenceCollector:
|
|
|
886
891
|
self._collect_feature_specialization(fs, element, results, scope_path)
|
|
887
892
|
|
|
888
893
|
def _collect_feature_specialization(
|
|
889
|
-
self, fs: Any, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]
|
|
894
|
+
self, fs: Any, element: Any, results: list[tuple[str, Any, list[str], str]], scope_path: list[str]
|
|
890
895
|
) -> None:
|
|
891
896
|
if fs is None:
|
|
892
897
|
return
|
|
@@ -898,7 +903,7 @@ class ReferenceCollector:
|
|
|
898
903
|
rel_type = type(rel).__name__
|
|
899
904
|
|
|
900
905
|
if rel_type == "Typings":
|
|
901
|
-
self._collect_typings(rel, element, results, scope_path)
|
|
906
|
+
self._collect_typings(rel, element, results, scope_path, "typing")
|
|
902
907
|
elif rel_type == "Subsettings":
|
|
903
908
|
self._collect_subsettings(rel, element, results, scope_path)
|
|
904
909
|
elif rel_type == "Redefinitions":
|
|
@@ -907,18 +912,20 @@ class ReferenceCollector:
|
|
|
907
912
|
self._collect_subclassification(rel, element, results, scope_path)
|
|
908
913
|
|
|
909
914
|
def _collect_typings(
|
|
910
|
-
self, typings: Any, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]
|
|
915
|
+
self, typings: Any, element: Any, results: list[tuple[str, Any, list[str], str]], scope_path: list[str],
|
|
916
|
+
kind: str = "typing",
|
|
911
917
|
) -> None:
|
|
912
918
|
tb = getattr(typings, "typing", None)
|
|
913
919
|
if tb is not None:
|
|
914
920
|
for ft in getattr(tb, "relationships", []):
|
|
915
|
-
self._collect_feature_typing(ft, element, results, scope_path)
|
|
921
|
+
self._collect_feature_typing(ft, element, results, scope_path, kind)
|
|
916
922
|
|
|
917
923
|
for ft in getattr(typings, "relationships", []):
|
|
918
|
-
self._collect_feature_typing(ft, element, results, scope_path)
|
|
924
|
+
self._collect_feature_typing(ft, element, results, scope_path, kind)
|
|
919
925
|
|
|
920
926
|
def _collect_feature_typing(
|
|
921
|
-
self, ft: Any, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]
|
|
927
|
+
self, ft: Any, element: Any, results: list[tuple[str, Any, list[str], str]], scope_path: list[str],
|
|
928
|
+
kind: str = "typing",
|
|
922
929
|
) -> None:
|
|
923
930
|
if ft is None:
|
|
924
931
|
return
|
|
@@ -936,17 +943,17 @@ class ReferenceCollector:
|
|
|
936
943
|
if qn is not None:
|
|
937
944
|
names = getattr(qn, "names", [])
|
|
938
945
|
if names:
|
|
939
|
-
results.append(("::".join(names), element, scope_path))
|
|
946
|
+
results.append(("::".join(names), element, scope_path, kind))
|
|
940
947
|
|
|
941
948
|
elif rel_type == "ConjugatedPortTyping":
|
|
942
949
|
qn = getattr(rel, "name", None)
|
|
943
950
|
if qn is not None:
|
|
944
951
|
names = getattr(qn, "names", [])
|
|
945
952
|
if names:
|
|
946
|
-
results.append(("::".join(names), element, scope_path))
|
|
953
|
+
results.append(("::".join(names), element, scope_path, kind))
|
|
947
954
|
|
|
948
955
|
def _collect_subsettings(
|
|
949
|
-
self, sub: Any, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]
|
|
956
|
+
self, sub: Any, element: Any, results: list[tuple[str, Any, list[str], str]], scope_path: list[str]
|
|
950
957
|
) -> None:
|
|
951
958
|
for child in getattr(sub, "children", []):
|
|
952
959
|
segments = _chain_segments(child)
|
|
@@ -955,26 +962,26 @@ class ReferenceCollector:
|
|
|
955
962
|
# with '.' (e.g. base.x).
|
|
956
963
|
# Namespace qualification stays inside a segment ('A::B');
|
|
957
964
|
# feature-chain segments join with '.'.
|
|
958
|
-
results.append((".".join(segments), element, scope_path))
|
|
965
|
+
results.append((".".join(segments), element, scope_path, "subsetting"))
|
|
959
966
|
|
|
960
967
|
def _collect_redefinitions(
|
|
961
|
-
self, red: Any, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]
|
|
968
|
+
self, red: Any, element: Any, results: list[tuple[str, Any, list[str], str]], scope_path: list[str]
|
|
962
969
|
) -> None:
|
|
963
970
|
for child in getattr(red, "children", []):
|
|
964
971
|
segments = _chain_segments(child)
|
|
965
972
|
if segments:
|
|
966
973
|
# Namespace qualification stays inside a segment ('A::B');
|
|
967
974
|
# feature-chain segments join with '.'.
|
|
968
|
-
results.append((".".join(segments), element, scope_path))
|
|
975
|
+
results.append((".".join(segments), element, scope_path, "redefinition"))
|
|
969
976
|
|
|
970
977
|
def _collect_subclassification(
|
|
971
|
-
self, sc: Any, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]
|
|
978
|
+
self, sc: Any, element: Any, results: list[tuple[str, Any, list[str], str]], scope_path: list[str]
|
|
972
979
|
) -> None:
|
|
973
980
|
for child in getattr(sc, "children", []):
|
|
974
981
|
for el in getattr(child, "elements", []):
|
|
975
982
|
names = getattr(el, "names", [])
|
|
976
983
|
if names:
|
|
977
|
-
results.append(("::".join(names), element, scope_path))
|
|
984
|
+
results.append(("::".join(names), element, scope_path, "subclassification"))
|
|
978
985
|
|
|
979
986
|
|
|
980
987
|
|
|
@@ -2275,7 +2282,7 @@ class SemanticAnalyzer:
|
|
|
2275
2282
|
references = collector.collect(model)
|
|
2276
2283
|
|
|
2277
2284
|
# Step 4: Cross-reference using scope-aware lookup
|
|
2278
|
-
for ref_str, element, scope_path in references:
|
|
2285
|
+
for ref_str, element, scope_path, _kind in references:
|
|
2279
2286
|
if self._is_resolved(ref_str, symtab, scope_path, lib_roots):
|
|
2280
2287
|
if self._is_implicit_library_reference(ref_str, symtab, scope_path, lib_roots):
|
|
2281
2288
|
issues.append(SemanticIssue(
|
|
@@ -2288,6 +2295,12 @@ class SemanticAnalyzer:
|
|
|
2288
2295
|
reference=ref_str,
|
|
2289
2296
|
))
|
|
2290
2297
|
continue
|
|
2298
|
+
# v0.60.0: members of an enclosing usage's declared type are
|
|
2299
|
+
# visible features inside the usage's body — resolve chained
|
|
2300
|
+
# references (and single members) through the context types
|
|
2301
|
+
# before flagging the symbol as undefined.
|
|
2302
|
+
if self._resolve_through_context(ref_str, symtab, element):
|
|
2303
|
+
continue
|
|
2291
2304
|
issues.append(SemanticIssue(
|
|
2292
2305
|
severity="error",
|
|
2293
2306
|
code="UNDEFINED_SYMBOL",
|
|
@@ -2616,9 +2629,14 @@ class SemanticAnalyzer:
|
|
|
2616
2629
|
# Dotted feature chains (`wheel1.mass`): resolve the head, then
|
|
2617
2630
|
# each successive step as a member of the previous step's element.
|
|
2618
2631
|
if "." in ref_str and self._resolve_feature_chain(
|
|
2619
|
-
ref_str, symtab, scope_path, lib_roots
|
|
2632
|
+
ref_str, symtab, scope_path, lib_roots, element=element
|
|
2620
2633
|
):
|
|
2621
2634
|
continue
|
|
2635
|
+
# Single identifiers (and chains whose head could not be found
|
|
2636
|
+
# from the scope) may still be members of an enclosing usage's
|
|
2637
|
+
# declared type (v0.60.0).
|
|
2638
|
+
if self._resolve_through_context(ref_str, symtab, element):
|
|
2639
|
+
continue
|
|
2622
2640
|
issues.append(SemanticIssue(
|
|
2623
2641
|
severity="error",
|
|
2624
2642
|
code="UNRESOLVED_EXPRESSION_IDENTIFIER",
|
|
@@ -2636,6 +2654,7 @@ class SemanticAnalyzer:
|
|
|
2636
2654
|
symtab: SymbolTable,
|
|
2637
2655
|
scope_path: list[str],
|
|
2638
2656
|
lib_roots: list[Path] | None = None,
|
|
2657
|
+
element: Any = None,
|
|
2639
2658
|
) -> bool:
|
|
2640
2659
|
"""Resolve a dotted feature chain like ``wheel1.hub.mass``.
|
|
2641
2660
|
|
|
@@ -2643,11 +2662,25 @@ class SemanticAnalyzer:
|
|
|
2643
2662
|
scope; each subsequent segment must exist as a named child of the
|
|
2644
2663
|
previous segment's element (feature navigation through part
|
|
2645
2664
|
structure).
|
|
2665
|
+
|
|
2666
|
+
Since v0.60.0, when a segment is not found among the current
|
|
2667
|
+
element's structural children, navigation continues through the
|
|
2668
|
+
element's *declared type* (``Usage.typed_by_name``): the segment is
|
|
2669
|
+
looked up as a member of the type definition, following subsetting
|
|
2670
|
+
inheritance. This resolves chains like ``wheels.hub.mass`` where
|
|
2671
|
+
``hub`` is a feature of ``Wheel`` (the type of ``wheels``) rather
|
|
2672
|
+
than a structural child of the ``wheels`` usage.
|
|
2673
|
+
|
|
2674
|
+
When the head itself does not resolve from the symbol-table scope
|
|
2675
|
+
(e.g. a chain inside a usage body: ``part myCar : Car { attribute
|
|
2676
|
+
w = engine.power; }`` — ``engine`` is a member of ``Car``, the
|
|
2677
|
+
declared type of ``myCar``), *element*'s context types are tried
|
|
2678
|
+
via :meth:`_resolve_through_context`.
|
|
2646
2679
|
"""
|
|
2647
2680
|
segments = ref_str.split(".")
|
|
2648
2681
|
head = segments[0]
|
|
2649
2682
|
if not self._is_resolved(head, symtab, scope_path, lib_roots):
|
|
2650
|
-
return
|
|
2683
|
+
return self._resolve_through_context(ref_str, symtab, element)
|
|
2651
2684
|
|
|
2652
2685
|
# Locate the head element by walking to its scope
|
|
2653
2686
|
current_table = symtab
|
|
@@ -2663,14 +2696,169 @@ class SemanticAnalyzer:
|
|
|
2663
2696
|
if current_element is None:
|
|
2664
2697
|
return False
|
|
2665
2698
|
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2699
|
+
# Type of the current navigation position (name of its definition).
|
|
2700
|
+
current_type = self._get_element_type(current_element)
|
|
2701
|
+
|
|
2702
|
+
return self._walk_chain_segments(
|
|
2703
|
+
segments[1:], current_element, current_type, symtab
|
|
2704
|
+
)
|
|
2705
|
+
|
|
2706
|
+
def _walk_chain_segments(
|
|
2707
|
+
self,
|
|
2708
|
+
segments: list[str],
|
|
2709
|
+
current_element: Any,
|
|
2710
|
+
current_type: Optional[str],
|
|
2711
|
+
symtab: SymbolTable,
|
|
2712
|
+
) -> bool:
|
|
2713
|
+
"""Walk the remaining *segments* of a feature chain.
|
|
2714
|
+
|
|
2715
|
+
Each segment is located first among the current element's
|
|
2716
|
+
structural children, then — as a fallback — as a feature of the
|
|
2717
|
+
current element's declared type (see
|
|
2718
|
+
:meth:`_resolve_segment_through_type`).
|
|
2719
|
+
"""
|
|
2720
|
+
for segment in segments:
|
|
2721
|
+
# 1) Structural navigation: find `segment` among the current
|
|
2722
|
+
# element's descendants, stopping at that element's own
|
|
2723
|
+
# subtree boundary.
|
|
2724
|
+
next_element = self._find_member(current_element, segment)
|
|
2725
|
+
if next_element is not None:
|
|
2726
|
+
current_element = next_element
|
|
2727
|
+
next_type = self._get_element_type(next_element)
|
|
2728
|
+
if next_type is not None:
|
|
2729
|
+
current_type = next_type
|
|
2730
|
+
continue
|
|
2731
|
+
|
|
2732
|
+
# 2) Type-definition navigation (v0.60.0): look `segment` up as
|
|
2733
|
+
# a feature of the current element's declared type.
|
|
2734
|
+
resolved = self._resolve_segment_through_type(
|
|
2735
|
+
segment, current_type, symtab
|
|
2736
|
+
)
|
|
2737
|
+
if resolved is None:
|
|
2671
2738
|
return False
|
|
2739
|
+
current_element, current_type = resolved
|
|
2672
2740
|
return True
|
|
2673
2741
|
|
|
2742
|
+
def _context_types_for_resolution(self, element: Any) -> list[str]:
|
|
2743
|
+
"""Declared type names visible to *element* as feature scopes.
|
|
2744
|
+
|
|
2745
|
+
Walks the element's parent chain and collects the declared type of
|
|
2746
|
+
each enclosing *usage* (innermost first) — a usage inherits the
|
|
2747
|
+
members of its type, so ``part myCar : Car`` makes ``engine`` (a
|
|
2748
|
+
member of ``Car``) visible inside myCar's body. Stops at the first
|
|
2749
|
+
enclosing definition: definition members are already visible via
|
|
2750
|
+
the symbol table's scope walk.
|
|
2751
|
+
"""
|
|
2752
|
+
types: list[str] = []
|
|
2753
|
+
seen: set[str] = set()
|
|
2754
|
+
node = element
|
|
2755
|
+
while node is not None and type(node).__name__ != "Model":
|
|
2756
|
+
if getattr(node, "is_definition", False):
|
|
2757
|
+
break
|
|
2758
|
+
declared = self._get_element_type(node)
|
|
2759
|
+
if declared and declared not in seen:
|
|
2760
|
+
seen.add(declared)
|
|
2761
|
+
types.append(declared)
|
|
2762
|
+
node = getattr(node, "parent", None)
|
|
2763
|
+
return types
|
|
2764
|
+
|
|
2765
|
+
def _resolve_through_context(
|
|
2766
|
+
self,
|
|
2767
|
+
ref_str: str,
|
|
2768
|
+
symtab: SymbolTable,
|
|
2769
|
+
element: Any,
|
|
2770
|
+
) -> bool:
|
|
2771
|
+
"""Resolve a chained reference through the element's context types.
|
|
2772
|
+
|
|
2773
|
+
Members of an enclosing usage's declared type are visible features
|
|
2774
|
+
inside the usage's body: in
|
|
2775
|
+
|
|
2776
|
+
``part myCar : Car { attribute carPower :\u003e engine::power; }``
|
|
2777
|
+
|
|
2778
|
+
the head ``engine`` is a member of ``Car`` (myCar's type) and
|
|
2779
|
+
``power`` a member of ``Engine`` (engine's type). Namespace
|
|
2780
|
+
qualifiers (``::``) and feature-chain dots (``.``) are treated
|
|
2781
|
+
uniformly as segment separators. Strictly existence-based: every
|
|
2782
|
+
segment must resolve, so typos still produce errors (v0.60.0).
|
|
2783
|
+
"""
|
|
2784
|
+
if element is None:
|
|
2785
|
+
return False
|
|
2786
|
+
segments = [
|
|
2787
|
+
seg
|
|
2788
|
+
for part in ref_str.split(".")
|
|
2789
|
+
for seg in part.split("::")
|
|
2790
|
+
if seg
|
|
2791
|
+
]
|
|
2792
|
+
if not segments:
|
|
2793
|
+
return False
|
|
2794
|
+
head = segments[0]
|
|
2795
|
+
for context_type in self._context_types_for_resolution(element):
|
|
2796
|
+
resolved = self._resolve_segment_through_type(
|
|
2797
|
+
head, context_type, symtab
|
|
2798
|
+
)
|
|
2799
|
+
if resolved is None:
|
|
2800
|
+
continue
|
|
2801
|
+
current_element, current_type = resolved
|
|
2802
|
+
if len(segments) == 1:
|
|
2803
|
+
return True
|
|
2804
|
+
if self._walk_chain_segments(
|
|
2805
|
+
segments[1:], current_element, current_type, symtab
|
|
2806
|
+
):
|
|
2807
|
+
return True
|
|
2808
|
+
return False
|
|
2809
|
+
|
|
2810
|
+
def _resolve_segment_through_type(
|
|
2811
|
+
self,
|
|
2812
|
+
segment: str,
|
|
2813
|
+
current_type: Optional[str],
|
|
2814
|
+
symtab: SymbolTable,
|
|
2815
|
+
) -> Optional[tuple[Any, Optional[str]]]:
|
|
2816
|
+
"""Resolve *segment* as a feature of the definition named *current_type*.
|
|
2817
|
+
|
|
2818
|
+
Returns ``(member_element, feature_type_name)`` on success so the
|
|
2819
|
+
chain walk can continue from the resolved feature, or ``None`` when
|
|
2820
|
+
the feature does not exist on the type (directly or inherited).
|
|
2821
|
+
"""
|
|
2822
|
+
if current_type is None:
|
|
2823
|
+
return None
|
|
2824
|
+
|
|
2825
|
+
# Accept qualified type names ('ScalarValues::Real') by trying the
|
|
2826
|
+
# full name first, then the simple name.
|
|
2827
|
+
def_names = [current_type]
|
|
2828
|
+
if "::" in current_type:
|
|
2829
|
+
def_names.append(current_type.split("::")[-1])
|
|
2830
|
+
|
|
2831
|
+
for def_name in def_names:
|
|
2832
|
+
def_info = symtab._definition_features.get(def_name)
|
|
2833
|
+
if def_info is None:
|
|
2834
|
+
continue
|
|
2835
|
+
|
|
2836
|
+
if segment in def_info["features"]:
|
|
2837
|
+
defining_type = def_name
|
|
2838
|
+
else:
|
|
2839
|
+
# Inherited feature: walk the supertype chain.
|
|
2840
|
+
defining_type = symtab.find_defining_type_for_feature(
|
|
2841
|
+
segment, def_name
|
|
2842
|
+
)
|
|
2843
|
+
if defining_type is None:
|
|
2844
|
+
continue
|
|
2845
|
+
|
|
2846
|
+
feature_type = self._get_feature_type(
|
|
2847
|
+
segment, defining_type, symtab
|
|
2848
|
+
)
|
|
2849
|
+
|
|
2850
|
+
# Locate the member element for further structural navigation.
|
|
2851
|
+
defining_info = symtab._definition_features.get(defining_type)
|
|
2852
|
+
member_element = None
|
|
2853
|
+
if defining_info is not None:
|
|
2854
|
+
member_element = self._find_member(
|
|
2855
|
+
defining_info["element"], segment
|
|
2856
|
+
)
|
|
2857
|
+
|
|
2858
|
+
return member_element, feature_type
|
|
2859
|
+
|
|
2860
|
+
return None
|
|
2861
|
+
|
|
2674
2862
|
@staticmethod
|
|
2675
2863
|
def _find_member(element: Any, name: str) -> Optional[Any]:
|
|
2676
2864
|
"""Find a member named *name* within *element*'s subtree (1 level + nesting)."""
|
|
@@ -3139,12 +3327,22 @@ class SemanticAnalyzer:
|
|
|
3139
3327
|
|
|
3140
3328
|
Validates that in a feature chain like 'a.b.c', the type of 'a' has
|
|
3141
3329
|
feature 'b', and the type of 'b' has feature 'c'.
|
|
3330
|
+
|
|
3331
|
+
Only subsetting / redefinition references are chain-checked: their
|
|
3332
|
+
targets are genuinely feature chains (``a::b`` / ``a.b``). Typing and
|
|
3333
|
+
subclassification references carry *type* names (``ScalarValues::Real``
|
|
3334
|
+
is a namespace-qualified type, not a chain of features) and are
|
|
3335
|
+
validated as plain symbols by the cross-reference pass; chain-checking
|
|
3336
|
+
them produced false ``INCOMPATIBLE_FEATURE_CHAIN`` errors on every
|
|
3337
|
+
qualified type name (fixed in v0.60.0).
|
|
3142
3338
|
"""
|
|
3143
3339
|
issues: list[SemanticIssue] = []
|
|
3144
3340
|
collector = ReferenceCollector()
|
|
3145
3341
|
references = collector.collect(model)
|
|
3146
3342
|
|
|
3147
|
-
for ref_str, element, scope_path in references:
|
|
3343
|
+
for ref_str, element, scope_path, kind in references:
|
|
3344
|
+
if kind not in ("subsetting", "redefinition"):
|
|
3345
|
+
continue
|
|
3148
3346
|
if "::" not in ref_str:
|
|
3149
3347
|
continue
|
|
3150
3348
|
|
|
@@ -3183,8 +3381,18 @@ class SemanticAnalyzer:
|
|
|
3183
3381
|
reference=ref_str,
|
|
3184
3382
|
))
|
|
3185
3383
|
break
|
|
3186
|
-
|
|
3187
|
-
|
|
3384
|
+
# Advance to the inherited feature's *declared type* so
|
|
3385
|
+
# the next segment is validated against the feature's
|
|
3386
|
+
# type, not against the supertype that declares it
|
|
3387
|
+
# (v0.60.0 — 'engine' declared on Vehicle but typed by
|
|
3388
|
+
# 'Engine' means the next segment must be a member of
|
|
3389
|
+
# Engine, not of Vehicle).
|
|
3390
|
+
next_type = self._get_feature_type(part, defining, symtab)
|
|
3391
|
+
if next_type is None:
|
|
3392
|
+
# Undeclared feature type: remaining chain cannot
|
|
3393
|
+
# be validated.
|
|
3394
|
+
break
|
|
3395
|
+
current_type = next_type
|
|
3188
3396
|
else:
|
|
3189
3397
|
# Feature found - get its type for next iteration
|
|
3190
3398
|
next_type = self._get_feature_type(part, current_type, symtab)
|
|
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.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp
RENAMED
|
File without changes
|
{sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py
RENAMED
|
File without changes
|
{sysmlpy-0.58.0 → sysmlpy-0.60.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
|
{sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.58.0 → sysmlpy-0.60.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.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml
RENAMED
|
File without changes
|
|
File without changes
|
{sysmlpy-0.58.0 → sysmlpy-0.60.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.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.58.0 → sysmlpy-0.60.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.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml
RENAMED
|
File without changes
|
|
File without changes
|
{sysmlpy-0.58.0 → sysmlpy-0.60.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.58.0 → sysmlpy-0.60.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
|