sysmlpy 0.41.0__tar.gz → 0.42.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.41.0 → sysmlpy-0.42.0}/PKG-INFO +3 -1
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/README.md +2 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/pyproject.toml +1 -1
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/__init__.py +1 -1
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr_visitor.py +135 -149
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/classes.py +26 -17
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/semantic.py +42 -9
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/usage.py +19 -47
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/LICENSE +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/__main__.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/README.md +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/SysMLv2Parser.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/antlr_parser.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/boxes_view.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/definition.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/examples/attribute_values.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/examples/part_attributes.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/examples/tuples_sequences.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/formatting.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/README.md +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.g4 +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.g4 +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/desc.xml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/examples/camera.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/examples/toaster-system.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/examples/vehicle-model.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/grammar/antlr4/pom.xml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/LICENSE +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/README.md +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/__init__.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Analysis/AnalysisTooling.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Analysis/TradeStudies.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Cause and Effect/CausationConnections.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Geometry/ShapeItems.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Geometry/SpatialItems.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Metadata/ImageMetadata.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Metadata/ParametersOfInterestMetadata.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Metadata/RiskMetadata.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQ.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAtomicNuclear.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCharacteristicNumbers.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQChemistryMolecular.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCondensedMatter.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQElectromagnetism.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQInformation.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/ISQThermodynamics.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementRefCalculations.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementReferences.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/QuantityCalculations.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/SI.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/TensorCalculations.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/USCustomaryUnits.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Quantities and Units/VectorCalculations.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Requirement Derivation/DerivationConnections.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/domain/Requirement Derivation/RequirementDerivation.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/Base.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/BaseFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/BooleanFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/Clocks.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/CollectionFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/Collections.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/ComplexFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/ControlFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/ControlPerformances.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/DataFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/IntegerFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/KerML.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/Links.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/Metaobjects.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/NaturalFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/NumericalFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/Objects.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/Observation.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/OccurrenceFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/Occurrences.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/Performances.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/RationalFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/RealFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/ScalarFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/ScalarValues.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/SequenceFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/SpatialFrames.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/StatePerformances.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/StringFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/Transfers.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/TransitionPerformances.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/TrigFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/Triggers.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/VectorFunctions.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/kernel/VectorValues.kerml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Actions.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Allocations.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/AnalysisCases.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Attributes.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Calculations.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Cases.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Connections.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Constraints.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Flows.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Interfaces.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Items.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Metadata.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Parts.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Ports.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Requirements.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/StandardViewDefinitions.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/States.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/SysML.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/UseCases.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/VerificationCases.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/library/systems/Views.sysml +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/navigate.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/plantuml.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/project.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/store.py +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/us_customary_units.txt +0 -0
- {sysmlpy-0.41.0 → sysmlpy-0.42.0}/src/sysmlpy/validator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sysmlpy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.42.0
|
|
4
4
|
Summary:
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Author: Jon R. Fox (mycr0ft)
|
|
@@ -39,6 +39,8 @@ The project had diverged so much from sysml2py that a new name, sysmlpy, was sel
|
|
|
39
39
|
|
|
40
40
|

|
|
41
41
|
|
|
42
|
+
**v0.42.0:** Two deep fixes in the specialization layer. (1) `satisfy R : T by p;` and `assert someConstraint : CType;` crashed with `NameError` — the makers called a helper that was never defined; all three sites now use `_build_full_specialization_from_fsp`. (2) Chained re-declarations (`attribute :> base.x;`) dropped every segment after the first, at both visitor and grammar layers — new visitor helpers emit one Owned* dict per source chain (head + `OwnedFeatureChain`), grammar classes keep both parts, `redefined_name` resolves to the leaf segment, and the semantic analyzer now reports/resolves full dotted names (`Undefined symbol 'missing.chain'`). 14 tests in `tests/redefined_name_test.py`.
|
|
43
|
+
|
|
42
44
|
**v0.41.0:** Full-specialization capture across all usage kinds — v0.40.0 fixed `attributeUsage` only; actions, calculations, constraints, requirements, use cases, interfaces and nested occurrences still dropped `:>`, `:>>`, `::>` specializations. New `_full_specialization_for_ctx` helper walks any usage-like context to its featureSpecializationPart; twelve visitor sites now use it (typed-by kept as fallback). `Action.load_from_grammar` captures all four kinds and the hand-rolled dumps on Action/Interface/UseCase/Requirement render them (`action a2 ::> RefType;`). `Usage.redefined_name` now works on deeper declaration nestings too. 10 tests in `tests/redefined_name_test.py`.
|
|
43
45
|
|
|
44
46
|
**v0.40.0:** `References` (`::>` / `references` keyword) implemented end-to-end — previously the grammar-side `FeatureSpecialization` had a silent "not yet implemented" stub and the visitor never emitted dicts for it, so `ref attribute ::> X;` lost its specialization on round-trip (dump emitted `attribute ;`). New `References` grammar class mirrors `Redefinitions`; visitor branches in both full-specialization builders now cover the operator and keyword forms. The top-level `attributeUsage` path was the only one still using the typed-by-only helper; it now uses `_build_full_specialization_from_ctx` so all four kinds (Typings, Subsettings, Redefinitions, References) round-trip. `redefined_name` / `display_name` already handled this case. New `test_attribute_ref_references_operator_roundtrip` in `tests/grammar_test.py`; two new cases in `tests/redefined_name_test.py`. 97/97 grammar round-trip tests pass.
|
|
@@ -14,6 +14,8 @@ The project had diverged so much from sysml2py that a new name, sysmlpy, was sel
|
|
|
14
14
|
|
|
15
15
|

|
|
16
16
|
|
|
17
|
+
**v0.42.0:** Two deep fixes in the specialization layer. (1) `satisfy R : T by p;` and `assert someConstraint : CType;` crashed with `NameError` — the makers called a helper that was never defined; all three sites now use `_build_full_specialization_from_fsp`. (2) Chained re-declarations (`attribute :> base.x;`) dropped every segment after the first, at both visitor and grammar layers — new visitor helpers emit one Owned* dict per source chain (head + `OwnedFeatureChain`), grammar classes keep both parts, `redefined_name` resolves to the leaf segment, and the semantic analyzer now reports/resolves full dotted names (`Undefined symbol 'missing.chain'`). 14 tests in `tests/redefined_name_test.py`.
|
|
18
|
+
|
|
17
19
|
**v0.41.0:** Full-specialization capture across all usage kinds — v0.40.0 fixed `attributeUsage` only; actions, calculations, constraints, requirements, use cases, interfaces and nested occurrences still dropped `:>`, `:>>`, `::>` specializations. New `_full_specialization_for_ctx` helper walks any usage-like context to its featureSpecializationPart; twelve visitor sites now use it (typed-by kept as fallback). `Action.load_from_grammar` captures all four kinds and the hand-rolled dumps on Action/Interface/UseCase/Requirement render them (`action a2 ::> RefType;`). `Usage.redefined_name` now works on deeper declaration nestings too. 10 tests in `tests/redefined_name_test.py`.
|
|
18
20
|
|
|
19
21
|
**v0.40.0:** `References` (`::>` / `references` keyword) implemented end-to-end — previously the grammar-side `FeatureSpecialization` had a silent "not yet implemented" stub and the visitor never emitted dicts for it, so `ref attribute ::> X;` lost its specialization on round-trip (dump emitted `attribute ;`). New `References` grammar class mirrors `Redefinitions`; visitor branches in both full-specialization builders now cover the operator and keyword forms. The top-level `attributeUsage` path was the only one still using the typed-by-only helper; it now uses `_build_full_specialization_from_ctx` so all four kinds (Typings, Subsettings, Redefinitions, References) round-trip. `redefined_name` / `display_name` already handled this case. New `test_attribute_ref_references_operator_roundtrip` in `tests/grammar_test.py`; two new cases in `tests/redefined_name_test.py`. 97/97 grammar round-trip tests pass.
|
|
@@ -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.42.0"
|
|
29
29
|
|
|
30
30
|
from sysmlpy.usage import (
|
|
31
31
|
Item, Attribute, Part, Port, Action, Reference, UseCase, Requirement, Interface, Message,
|
|
@@ -2212,7 +2212,7 @@ def _make_assert_constraint_usage_dict(acu_ctx, prefix=None):
|
|
|
2212
2212
|
|
|
2213
2213
|
if hasattr(acu_ctx, 'featureSpecializationPart') and acu_ctx.featureSpecializationPart():
|
|
2214
2214
|
fsp_ctx = acu_ctx.featureSpecializationPart()
|
|
2215
|
-
fsp =
|
|
2215
|
+
fsp = _build_full_specialization_from_fsp(fsp_ctx)
|
|
2216
2216
|
|
|
2217
2217
|
declaration = None
|
|
2218
2218
|
if hasattr(acu_ctx, 'constraintUsageDeclaration') and acu_ctx.constraintUsageDeclaration():
|
|
@@ -2315,7 +2315,7 @@ def _make_satisfy_requirement_usage_dict(sru_ctx, prefix=None):
|
|
|
2315
2315
|
|
|
2316
2316
|
if hasattr(sru_ctx, 'featureSpecializationPart') and sru_ctx.featureSpecializationPart():
|
|
2317
2317
|
fsp_ctx = sru_ctx.featureSpecializationPart()
|
|
2318
|
-
fsp =
|
|
2318
|
+
fsp = _build_full_specialization_from_fsp(fsp_ctx)
|
|
2319
2319
|
elif hasattr(sru_ctx, 'REQUIREMENT') and sru_ctx.REQUIREMENT():
|
|
2320
2320
|
if hasattr(sru_ctx, 'usageDeclaration') and sru_ctx.usageDeclaration():
|
|
2321
2321
|
ud = sru_ctx.usageDeclaration()
|
|
@@ -9111,7 +9111,7 @@ def _visit_requirement_constraint_usage(rcu_ctx):
|
|
|
9111
9111
|
fs = []
|
|
9112
9112
|
if hasattr(rcu_ctx, 'featureSpecializationPart') and rcu_ctx.featureSpecializationPart():
|
|
9113
9113
|
fsp_ctx = rcu_ctx.featureSpecializationPart()
|
|
9114
|
-
fsp =
|
|
9114
|
+
fsp = _build_full_specialization_from_fsp(fsp_ctx)
|
|
9115
9115
|
if fsp and "specialization" in fsp:
|
|
9116
9116
|
fs = fsp["specialization"]
|
|
9117
9117
|
|
|
@@ -11561,6 +11561,68 @@ def _get_action_usage_subsetted_by(ctx):
|
|
|
11561
11561
|
return None
|
|
11562
11562
|
|
|
11563
11563
|
|
|
11564
|
+
def _dotted_segments(owned_ctx):
|
|
11565
|
+
"""Segments of an ownedSubsetting / ownedRedefinition /
|
|
11566
|
+
ownedReferenceSubsetting context.
|
|
11567
|
+
|
|
11568
|
+
Grammar: qualifiedName (DOT qualifiedName)* — e.g. ``base.x`` yields
|
|
11569
|
+
``['base', 'x']``. Each segment may itself be '::'-qualified.
|
|
11570
|
+
"""
|
|
11571
|
+
segs = []
|
|
11572
|
+
if owned_ctx is None:
|
|
11573
|
+
return segs
|
|
11574
|
+
for c2 in owned_ctx.children:
|
|
11575
|
+
if type(c2).__name__ == 'QualifiedNameContext':
|
|
11576
|
+
segs.append(c2.getText())
|
|
11577
|
+
return segs
|
|
11578
|
+
|
|
11579
|
+
|
|
11580
|
+
def _emit_owned_chain(dict_name, feature_key, segs):
|
|
11581
|
+
"""Build an Owned{Subsetting,Redefinition,ReferenceSubsetting} dict
|
|
11582
|
+
from dotted segments: first segment becomes the direct feature, the
|
|
11583
|
+
remainder become an OwnedFeatureChain so chained forms like
|
|
11584
|
+
``:> base.x`` survive round-trip."""
|
|
11585
|
+
head = {
|
|
11586
|
+
"name": "QualifiedName",
|
|
11587
|
+
"names": segs[0].split("::"),
|
|
11588
|
+
}
|
|
11589
|
+
owned_related = []
|
|
11590
|
+
if len(segs) > 1:
|
|
11591
|
+
chain_elements = [
|
|
11592
|
+
{
|
|
11593
|
+
"name": "OwnedFeatureChaining",
|
|
11594
|
+
"chainingFeature": {"name": "QualifiedName", "names": s.split("::")},
|
|
11595
|
+
}
|
|
11596
|
+
for s in segs[1:]
|
|
11597
|
+
]
|
|
11598
|
+
owned_related.append({
|
|
11599
|
+
"name": "OwnedFeatureChain",
|
|
11600
|
+
"feature": {
|
|
11601
|
+
"name": "FeatureChain",
|
|
11602
|
+
"ownedRelationship": chain_elements,
|
|
11603
|
+
},
|
|
11604
|
+
})
|
|
11605
|
+
return {
|
|
11606
|
+
"name": dict_name,
|
|
11607
|
+
feature_key: head,
|
|
11608
|
+
"ownedRelatedElement": owned_related,
|
|
11609
|
+
}
|
|
11610
|
+
|
|
11611
|
+
|
|
11612
|
+
def _collect_owned_contexts(wrapper_children, direct_type, wrapper_types):
|
|
11613
|
+
"""Yield each Owned*Context found under a Subsettings/Redefinitions/
|
|
11614
|
+
References rule context. Handles both direct children and one of the
|
|
11615
|
+
keyword-wrapper contexts (SubsetsContext, RedefinesContext, …)."""
|
|
11616
|
+
for child in wrapper_children:
|
|
11617
|
+
child_name = type(child).__name__
|
|
11618
|
+
if child_name == direct_type:
|
|
11619
|
+
yield child
|
|
11620
|
+
elif child_name in wrapper_types:
|
|
11621
|
+
for c3 in child.children:
|
|
11622
|
+
if type(c3).__name__ == direct_type:
|
|
11623
|
+
yield c3
|
|
11624
|
+
|
|
11625
|
+
|
|
11564
11626
|
def _full_specialization_for_ctx(ctx):
|
|
11565
11627
|
"""Best-effort full specialization for any usage-like context.
|
|
11566
11628
|
|
|
@@ -11848,30 +11910,19 @@ def _build_full_specialization_from_ctx(ctx):
|
|
|
11848
11910
|
# redef_ctx can be a single RedefinitionsContext or a list
|
|
11849
11911
|
if not isinstance(redef_ctx, list):
|
|
11850
11912
|
redef_ctx = [redef_ctx]
|
|
11851
|
-
|
|
11913
|
+
owned = []
|
|
11852
11914
|
for rc in redef_ctx:
|
|
11853
|
-
#
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
if type(c3).__name__ == 'QualifiedNameContext':
|
|
11865
|
-
redef_names.append(c3.getText())
|
|
11866
|
-
if redef_names:
|
|
11867
|
-
owned = [
|
|
11868
|
-
{
|
|
11869
|
-
"name": "OwnedRedefinition",
|
|
11870
|
-
"redefinedFeature": {"name": "QualifiedName", "names": n.split("::")},
|
|
11871
|
-
"ownedRelatedElement": []
|
|
11872
|
-
}
|
|
11873
|
-
for n in redef_names
|
|
11874
|
-
]
|
|
11915
|
+
# OwnedRedefinitionContext may be a dotted chain
|
|
11916
|
+
# (qualifiedName (DOT qualifiedName)*).
|
|
11917
|
+
for or_ctx in _collect_owned_contexts(
|
|
11918
|
+
rc.children, 'OwnedRedefinitionContext',
|
|
11919
|
+
('RedefinesContext',),
|
|
11920
|
+
):
|
|
11921
|
+
segs = _dotted_segments(or_ctx)
|
|
11922
|
+
if segs:
|
|
11923
|
+
owned.append(_emit_owned_chain(
|
|
11924
|
+
'OwnedRedefinition', 'redefinedFeature', segs))
|
|
11925
|
+
if owned:
|
|
11875
11926
|
specialization_list.append({
|
|
11876
11927
|
"name": "FeatureSpecialization",
|
|
11877
11928
|
"ownedRelationship": {
|
|
@@ -11886,36 +11937,19 @@ def _build_full_specialization_from_ctx(ctx):
|
|
|
11886
11937
|
# sub_ctx can be a single SubsettingsContext or a list
|
|
11887
11938
|
if not isinstance(sub_ctx, list):
|
|
11888
11939
|
sub_ctx = [sub_ctx]
|
|
11889
|
-
|
|
11940
|
+
owned = []
|
|
11890
11941
|
for sc in sub_ctx:
|
|
11891
|
-
#
|
|
11892
|
-
|
|
11893
|
-
|
|
11894
|
-
|
|
11895
|
-
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
|
|
11902
|
-
if type(c3).__name__ == 'QualifiedNameContext':
|
|
11903
|
-
sub_names.append(c3.getText())
|
|
11904
|
-
elif child_name == 'SpecializesContext':
|
|
11905
|
-
for c2 in child.children:
|
|
11906
|
-
if type(c2).__name__ == 'OwnedSubsettingContext':
|
|
11907
|
-
for c3 in c2.children:
|
|
11908
|
-
if type(c3).__name__ == 'QualifiedNameContext':
|
|
11909
|
-
sub_names.append(c3.getText())
|
|
11910
|
-
if sub_names:
|
|
11911
|
-
owned = [
|
|
11912
|
-
{
|
|
11913
|
-
"name": "OwnedSubsetting",
|
|
11914
|
-
"subsettedFeature": {"name": "QualifiedName", "names": n.split("::")},
|
|
11915
|
-
"ownedRelatedElement": []
|
|
11916
|
-
}
|
|
11917
|
-
for n in sub_names
|
|
11918
|
-
]
|
|
11942
|
+
# Each Owned*Context may be a dotted chain
|
|
11943
|
+
# (qualifiedName (DOT qualifiedName)*).
|
|
11944
|
+
for os_ctx in _collect_owned_contexts(
|
|
11945
|
+
sc.children, 'OwnedSubsettingContext',
|
|
11946
|
+
('SubsetsContext', 'SpecializesContext'),
|
|
11947
|
+
):
|
|
11948
|
+
segs = _dotted_segments(os_ctx)
|
|
11949
|
+
if segs:
|
|
11950
|
+
owned.append(_emit_owned_chain(
|
|
11951
|
+
'OwnedSubsetting', 'subsettedFeature', segs))
|
|
11952
|
+
if owned:
|
|
11919
11953
|
specialization_list.append({
|
|
11920
11954
|
"name": "FeatureSpecialization",
|
|
11921
11955
|
"ownedRelationship": {
|
|
@@ -11929,29 +11963,18 @@ def _build_full_specialization_from_ctx(ctx):
|
|
|
11929
11963
|
ref_ctx = spec.references()
|
|
11930
11964
|
if not isinstance(ref_ctx, list):
|
|
11931
11965
|
ref_ctx = [ref_ctx]
|
|
11932
|
-
|
|
11966
|
+
owned = []
|
|
11933
11967
|
for rc in ref_ctx:
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
if type(c3).__name__ == 'QualifiedNameContext':
|
|
11945
|
-
ref_names.append(c3.getText())
|
|
11946
|
-
if ref_names:
|
|
11947
|
-
owned = [
|
|
11948
|
-
{
|
|
11949
|
-
"name": "OwnedReferenceSubsetting",
|
|
11950
|
-
"referencedFeature": {"name": "QualifiedName", "names": n.split("::")},
|
|
11951
|
-
"ownedRelatedElement": []
|
|
11952
|
-
}
|
|
11953
|
-
for n in ref_names
|
|
11954
|
-
]
|
|
11968
|
+
# OwnedReferenceSubsettingContext may be a dotted chain.
|
|
11969
|
+
for ors_ctx in _collect_owned_contexts(
|
|
11970
|
+
rc.children, 'OwnedReferenceSubsettingContext',
|
|
11971
|
+
('ReferencesContext',),
|
|
11972
|
+
):
|
|
11973
|
+
segs = _dotted_segments(ors_ctx)
|
|
11974
|
+
if segs:
|
|
11975
|
+
owned.append(_emit_owned_chain(
|
|
11976
|
+
'OwnedReferenceSubsetting', 'referencedFeature', segs))
|
|
11977
|
+
if owned:
|
|
11955
11978
|
specialization_list.append({
|
|
11956
11979
|
"name": "FeatureSpecialization",
|
|
11957
11980
|
"ownedRelationship": {
|
|
@@ -12242,29 +12265,19 @@ def _build_full_specialization_from_fsp(fsp):
|
|
|
12242
12265
|
redef_ctx = spec.redefinitions()
|
|
12243
12266
|
if not isinstance(redef_ctx, list):
|
|
12244
12267
|
redef_ctx = [redef_ctx]
|
|
12245
|
-
|
|
12268
|
+
owned = []
|
|
12246
12269
|
for rc in redef_ctx:
|
|
12247
|
-
|
|
12248
|
-
|
|
12249
|
-
|
|
12250
|
-
|
|
12251
|
-
|
|
12252
|
-
|
|
12253
|
-
|
|
12254
|
-
|
|
12255
|
-
|
|
12256
|
-
|
|
12257
|
-
|
|
12258
|
-
redef_names.append(c3.getText())
|
|
12259
|
-
if redef_names:
|
|
12260
|
-
owned = [
|
|
12261
|
-
{
|
|
12262
|
-
"name": "OwnedRedefinition",
|
|
12263
|
-
"redefinedFeature": {"name": "QualifiedName", "names": n.split("::")},
|
|
12264
|
-
"ownedRelatedElement": []
|
|
12265
|
-
}
|
|
12266
|
-
for n in redef_names
|
|
12267
|
-
]
|
|
12270
|
+
# OwnedRedefinitionContext may be a dotted chain
|
|
12271
|
+
# (qualifiedName (DOT qualifiedName)*).
|
|
12272
|
+
for or_ctx in _collect_owned_contexts(
|
|
12273
|
+
rc.children, 'OwnedRedefinitionContext',
|
|
12274
|
+
('RedefinesContext',),
|
|
12275
|
+
):
|
|
12276
|
+
segs = _dotted_segments(or_ctx)
|
|
12277
|
+
if segs:
|
|
12278
|
+
owned.append(_emit_owned_chain(
|
|
12279
|
+
'OwnedRedefinition', 'redefinedFeature', segs))
|
|
12280
|
+
if owned:
|
|
12268
12281
|
specialization_list.append({
|
|
12269
12282
|
"name": "FeatureSpecialization",
|
|
12270
12283
|
"ownedRelationship": {
|
|
@@ -12278,35 +12291,19 @@ def _build_full_specialization_from_fsp(fsp):
|
|
|
12278
12291
|
sub_ctx = spec.subsettings()
|
|
12279
12292
|
if not isinstance(sub_ctx, list):
|
|
12280
12293
|
sub_ctx = [sub_ctx]
|
|
12281
|
-
|
|
12294
|
+
owned = []
|
|
12282
12295
|
for sc in sub_ctx:
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
sub_names.append(c3.getText())
|
|
12295
|
-
elif child_name == 'SpecializesContext':
|
|
12296
|
-
for c2 in child.children:
|
|
12297
|
-
if type(c2).__name__ == 'OwnedSubsettingContext':
|
|
12298
|
-
for c3 in c2.children:
|
|
12299
|
-
if type(c3).__name__ == 'QualifiedNameContext':
|
|
12300
|
-
sub_names.append(c3.getText())
|
|
12301
|
-
if sub_names:
|
|
12302
|
-
owned = [
|
|
12303
|
-
{
|
|
12304
|
-
"name": "OwnedSubsetting",
|
|
12305
|
-
"subsettedFeature": {"name": "QualifiedName", "names": n.split("::")},
|
|
12306
|
-
"ownedRelatedElement": []
|
|
12307
|
-
}
|
|
12308
|
-
for n in sub_names
|
|
12309
|
-
]
|
|
12296
|
+
# Each Owned*Context may be a dotted chain
|
|
12297
|
+
# (qualifiedName (DOT qualifiedName)*).
|
|
12298
|
+
for os_ctx in _collect_owned_contexts(
|
|
12299
|
+
sc.children, 'OwnedSubsettingContext',
|
|
12300
|
+
('SubsetsContext', 'SpecializesContext'),
|
|
12301
|
+
):
|
|
12302
|
+
segs = _dotted_segments(os_ctx)
|
|
12303
|
+
if segs:
|
|
12304
|
+
owned.append(_emit_owned_chain(
|
|
12305
|
+
'OwnedSubsetting', 'subsettedFeature', segs))
|
|
12306
|
+
if owned:
|
|
12310
12307
|
specialization_list.append({
|
|
12311
12308
|
"name": "FeatureSpecialization",
|
|
12312
12309
|
"ownedRelationship": {
|
|
@@ -12320,29 +12317,18 @@ def _build_full_specialization_from_fsp(fsp):
|
|
|
12320
12317
|
ref_ctx = spec.references()
|
|
12321
12318
|
if not isinstance(ref_ctx, list):
|
|
12322
12319
|
ref_ctx = [ref_ctx]
|
|
12323
|
-
|
|
12320
|
+
owned = []
|
|
12324
12321
|
for rc in ref_ctx:
|
|
12325
|
-
|
|
12326
|
-
|
|
12327
|
-
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
if type(c3).__name__ == 'QualifiedNameContext':
|
|
12336
|
-
ref_names.append(c3.getText())
|
|
12337
|
-
if ref_names:
|
|
12338
|
-
owned = [
|
|
12339
|
-
{
|
|
12340
|
-
"name": "OwnedReferenceSubsetting",
|
|
12341
|
-
"referencedFeature": {"name": "QualifiedName", "names": n.split("::")},
|
|
12342
|
-
"ownedRelatedElement": []
|
|
12343
|
-
}
|
|
12344
|
-
for n in ref_names
|
|
12345
|
-
]
|
|
12322
|
+
# OwnedReferenceSubsettingContext may be a dotted chain.
|
|
12323
|
+
for ors_ctx in _collect_owned_contexts(
|
|
12324
|
+
rc.children, 'OwnedReferenceSubsettingContext',
|
|
12325
|
+
('ReferencesContext',),
|
|
12326
|
+
):
|
|
12327
|
+
segs = _dotted_segments(ors_ctx)
|
|
12328
|
+
if segs:
|
|
12329
|
+
owned.append(_emit_owned_chain(
|
|
12330
|
+
'OwnedReferenceSubsetting', 'referencedFeature', segs))
|
|
12331
|
+
if owned:
|
|
12346
12332
|
specialization_list.append({
|
|
12347
12333
|
"name": "FeatureSpecialization",
|
|
12348
12334
|
"ownedRelationship": {
|
|
@@ -8243,33 +8243,40 @@ class References:
|
|
|
8243
8243
|
class OwnedRedefinition:
|
|
8244
8244
|
def __init__(self, definition):
|
|
8245
8245
|
if valid_definition(definition, "OwnedRedefinition"):
|
|
8246
|
+
# A dotted chain (:>> base.x) carries BOTH the head
|
|
8247
|
+
# qualifiedName and one OwnedFeatureChain per remaining
|
|
8248
|
+
# segment. Keep both so chained forms survive round-trip.
|
|
8249
|
+
self.redefinedFeature = None
|
|
8246
8250
|
if definition["redefinedFeature"] is not None:
|
|
8247
8251
|
self.redefinedFeature = QualifiedName(definition["redefinedFeature"])
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
self.elements
|
|
8251
|
-
for element in definition["ownedRelatedElement"]:
|
|
8252
|
-
self.elements.append(OwnedFeatureChain(element))
|
|
8252
|
+
self.elements = []
|
|
8253
|
+
for element in definition.get("ownedRelatedElement", []) or []:
|
|
8254
|
+
self.elements.append(OwnedFeatureChain(element))
|
|
8253
8255
|
|
|
8254
8256
|
def dump(self):
|
|
8257
|
+
parts = []
|
|
8255
8258
|
if self.redefinedFeature is not None:
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
+
parts.append(self.redefinedFeature.dump())
|
|
8260
|
+
parts.extend([e.dump() for e in self.elements])
|
|
8261
|
+
return ".".join(parts) if parts else ""
|
|
8259
8262
|
|
|
8260
8263
|
def get_definition(self):
|
|
8261
|
-
if self.redefinedFeature is not None:
|
|
8264
|
+
if self.redefinedFeature is not None and not self.elements:
|
|
8262
8265
|
return {
|
|
8263
8266
|
"name": self.__class__.__name__,
|
|
8264
8267
|
"redefinedFeature": self.redefinedFeature.get_definition(),
|
|
8265
8268
|
"ownedRelatedElement": [],
|
|
8266
8269
|
}
|
|
8267
8270
|
else:
|
|
8268
|
-
|
|
8271
|
+
output = {
|
|
8269
8272
|
"name": self.__class__.__name__,
|
|
8270
|
-
"redefinedFeature": None,
|
|
8273
|
+
"redefinedFeature": self.redefinedFeature.get_definition() if self.redefinedFeature is not None else None,
|
|
8271
8274
|
"ownedRelatedElement": [e.get_definition() for e in self.elements],
|
|
8272
8275
|
}
|
|
8276
|
+
if self.redefinedFeature is None and not self.elements:
|
|
8277
|
+
# Fully empty: keep legacy shape
|
|
8278
|
+
pass
|
|
8279
|
+
return output
|
|
8273
8280
|
|
|
8274
8281
|
|
|
8275
8282
|
class Subsettings:
|
|
@@ -8298,15 +8305,17 @@ class OwnedSubsetting:
|
|
|
8298
8305
|
def __init__(self, definition):
|
|
8299
8306
|
if valid_definition(definition, "OwnedSubsetting"):
|
|
8300
8307
|
# subsettedFeature = QualifiedName | ownedRelatedElement += OwnedFeatureChain
|
|
8308
|
+
# A dotted chain (:> base.x) carries BOTH: the head qualifiedName
|
|
8309
|
+
# plus one OwnedFeatureChain per remaining segment. Keep both so
|
|
8310
|
+
# chained forms survive round-trip (v0.42.0).
|
|
8311
|
+
self.elements = []
|
|
8301
8312
|
if definition["subsettedFeature"] is not None:
|
|
8302
|
-
self.elements
|
|
8303
|
-
|
|
8304
|
-
self.elements
|
|
8305
|
-
for element in definition["ownedRelatedElement"]:
|
|
8306
|
-
self.elements.append(OwnedFeatureChain(element))
|
|
8313
|
+
self.elements.append(QualifiedName(definition["subsettedFeature"]))
|
|
8314
|
+
for element in definition.get("ownedRelatedElement", []) or []:
|
|
8315
|
+
self.elements.append(OwnedFeatureChain(element))
|
|
8307
8316
|
|
|
8308
8317
|
def dump(self):
|
|
8309
|
-
return "
|
|
8318
|
+
return ".".join([child.dump() for child in self.elements])
|
|
8310
8319
|
|
|
8311
8320
|
def get_definition(self):
|
|
8312
8321
|
output = {
|
|
@@ -948,20 +948,23 @@ class ReferenceCollector:
|
|
|
948
948
|
self, sub: Any, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]
|
|
949
949
|
) -> None:
|
|
950
950
|
for child in getattr(sub, "children", []):
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
951
|
+
segments = _chain_segments(child)
|
|
952
|
+
if segments:
|
|
953
|
+
# Namespace qualification joins with '::', feature chains
|
|
954
|
+
# with '.' (e.g. base.x).
|
|
955
|
+
# Namespace qualification stays inside a segment ('A::B');
|
|
956
|
+
# feature-chain segments join with '.'.
|
|
957
|
+
results.append((".".join(segments), element, scope_path))
|
|
955
958
|
|
|
956
959
|
def _collect_redefinitions(
|
|
957
960
|
self, red: Any, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]
|
|
958
961
|
) -> None:
|
|
959
962
|
for child in getattr(red, "children", []):
|
|
960
|
-
|
|
961
|
-
if
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
963
|
+
segments = _chain_segments(child)
|
|
964
|
+
if segments:
|
|
965
|
+
# Namespace qualification stays inside a segment ('A::B');
|
|
966
|
+
# feature-chain segments join with '.'.
|
|
967
|
+
results.append((".".join(segments), element, scope_path))
|
|
965
968
|
|
|
966
969
|
def _collect_subclassification(
|
|
967
970
|
self, sc: Any, element: Any, results: list[tuple[str, Any, list[str]]], scope_path: list[str]
|
|
@@ -973,6 +976,36 @@ class ReferenceCollector:
|
|
|
973
976
|
results.append(("::".join(names), element, scope_path))
|
|
974
977
|
|
|
975
978
|
|
|
979
|
+
|
|
980
|
+
def _chain_segments(child: Any) -> list[str]:
|
|
981
|
+
"""Reference segments of an Owned*Subsetting/Redefinition child, in order.
|
|
982
|
+
|
|
983
|
+
Each returned string is one feature-chain segment: a QualifiedName keeps
|
|
984
|
+
its internal ``::`` namespace qualification (``A::B``), while dotted
|
|
985
|
+
chain steps become separate segments (``:> base.x`` -> ``['base','x']``).
|
|
986
|
+
"""
|
|
987
|
+
segments: list[str] = []
|
|
988
|
+
qn = getattr(child, "redefinedFeature", None) or getattr(
|
|
989
|
+
child, "referencedFeature", None
|
|
990
|
+
) or getattr(child, "subsettedFeature", None)
|
|
991
|
+
if qn is not None:
|
|
992
|
+
names = getattr(qn, "names", [])
|
|
993
|
+
if names:
|
|
994
|
+
segments.append("::".join(names))
|
|
995
|
+
for el in getattr(child, "elements", []) or []:
|
|
996
|
+
if hasattr(el, "names") and getattr(el, "names", []):
|
|
997
|
+
# Bare QualifiedName element (OwnedSubsetting single form)
|
|
998
|
+
segments.append("::".join(el.names))
|
|
999
|
+
elif hasattr(el, "feature"):
|
|
1000
|
+
for seg in getattr(el.feature, "children", []) or []:
|
|
1001
|
+
cf = getattr(seg, "chainingFeature", None)
|
|
1002
|
+
if cf is not None:
|
|
1003
|
+
names = getattr(cf, "names", [])
|
|
1004
|
+
if names:
|
|
1005
|
+
segments.append("::".join(names))
|
|
1006
|
+
return segments
|
|
1007
|
+
|
|
1008
|
+
|
|
976
1009
|
# ---------------------------------------------------------------------------
|
|
977
1010
|
# Semantic Analyzer
|
|
978
1011
|
# ---------------------------------------------------------------------------
|
|
@@ -33,29 +33,6 @@ def _is_uuid(s: str) -> bool:
|
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
def _qn_last_name(qn):
|
|
37
|
-
"""Return the last identifier segment of a QualifiedName, or None."""
|
|
38
|
-
if qn is None:
|
|
39
|
-
return None
|
|
40
|
-
names = getattr(qn, "names", None)
|
|
41
|
-
if names:
|
|
42
|
-
return names[-1]
|
|
43
|
-
return None
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def _feature_chain_last_name(chain):
|
|
47
|
-
"""Walk a chain of OwnedFeatureChain segments; return the last identifier
|
|
48
|
-
segment of the final segment, or None."""
|
|
49
|
-
if chain is None:
|
|
50
|
-
return None
|
|
51
|
-
feature = getattr(chain, "feature", None)
|
|
52
|
-
children = getattr(feature, "children", None) or []
|
|
53
|
-
last_seg = None
|
|
54
|
-
for seg in children:
|
|
55
|
-
last_seg = _qn_last_name(getattr(seg, "chainingFeature", None))
|
|
56
|
-
return last_seg
|
|
57
|
-
|
|
58
|
-
|
|
59
36
|
def _resolve_name_from_specialization(specialization):
|
|
60
37
|
"""Find the most user-visible identifier in a ``FeatureSpecializationPart``.
|
|
61
38
|
|
|
@@ -76,36 +53,31 @@ def _resolve_name_from_specialization(specialization):
|
|
|
76
53
|
if rel is None:
|
|
77
54
|
continue
|
|
78
55
|
for child in getattr(rel, "children", None) or []:
|
|
79
|
-
# OwnedRedefinition / OwnedReferenceSubsetting
|
|
80
|
-
#
|
|
81
|
-
|
|
56
|
+
# OwnedRedefinition / OwnedReferenceSubsetting / OwnedSubsetting:
|
|
57
|
+
# a dotted chain (:> base.x) keeps the head QualifiedName plus
|
|
58
|
+
# one OwnedFeatureChain per remaining segment. Collect every
|
|
59
|
+
# segment in order and resolve to the last one.
|
|
60
|
+
segments = []
|
|
61
|
+
qn = (
|
|
82
62
|
getattr(child, "redefinedFeature", None)
|
|
83
|
-
|
|
84
|
-
getattr(child, "referencedFeature", None)
|
|
63
|
+
or getattr(child, "referencedFeature", None)
|
|
85
64
|
)
|
|
86
|
-
if qn:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
65
|
+
if qn is not None and getattr(qn, "names", None):
|
|
66
|
+
segments.extend(qn.names)
|
|
67
|
+
for el in getattr(child, "elements", None) or []:
|
|
68
|
+
if hasattr(el, "names") and el.names:
|
|
69
|
+
segments.extend(el.names)
|
|
70
|
+
elif hasattr(el, "feature"):
|
|
71
|
+
for seg in getattr(el.feature, "children", []) or []:
|
|
72
|
+
cf = getattr(seg, "chainingFeature", None)
|
|
73
|
+
if cf is not None and getattr(cf, "names", None):
|
|
74
|
+
segments.extend(cf.names)
|
|
75
|
+
if segments:
|
|
76
|
+
return segments[-1]
|
|
98
77
|
# First chain resolved; stop looking further.
|
|
99
78
|
return None
|
|
100
79
|
return None
|
|
101
80
|
|
|
102
|
-
|
|
103
|
-
def _qn_owner():
|
|
104
|
-
"""Return the QualifiedName class without importing it at module
|
|
105
|
-
load time (avoids a cycle with the visitor package)."""
|
|
106
|
-
from sysmlpy.grammar.classes import QualifiedName
|
|
107
|
-
return QualifiedName
|
|
108
|
-
|
|
109
81
|
# Load custom US Customary unit definitions
|
|
110
82
|
_us_customary_path = os.path.join(os.path.dirname(__file__), "us_customary_units.txt")
|
|
111
83
|
if os.path.exists(_us_customary_path):
|