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.
Files changed (148) hide show
  1. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/PKG-INFO +1 -1
  2. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/pyproject.toml +1 -1
  3. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/__init__.py +1 -1
  4. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr_visitor.py +14 -5
  5. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/classes.py +5 -4
  6. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/semantic.py +240 -32
  7. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/LICENSE +0 -0
  8. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/README.md +0 -0
  9. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/__main__.py +0 -0
  10. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/README.md +0 -0
  11. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Lexer.interp +0 -0
  12. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Lexer.py +0 -0
  13. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Lexer.tokens +0 -0
  14. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Parser.interp +0 -0
  15. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Parser.py +0 -0
  16. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2Parser.tokens +0 -0
  17. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2ParserListener.py +0 -0
  18. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/SysMLv2ParserVisitor.py +0 -0
  19. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
  20. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
  21. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
  22. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/antlr_parser.py +0 -0
  23. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/boxes_view.py +0 -0
  24. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/definition.py +0 -0
  25. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/examples/attribute_values.py +0 -0
  26. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/examples/part_attributes.py +0 -0
  27. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/examples/tuples_sequences.py +0 -0
  28. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/formatting.py +0 -0
  29. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/README.md +0 -0
  30. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.g4 +0 -0
  31. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
  32. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
  33. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
  34. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.g4 +0 -0
  35. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.interp +0 -0
  36. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.py +0 -0
  37. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.tokens +0 -0
  38. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserListener.py +0 -0
  39. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserVisitor.py +0 -0
  40. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/desc.xml +0 -0
  41. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/examples/camera.sysml +0 -0
  42. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/examples/toaster-system.sysml +0 -0
  43. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/examples/vehicle-model.sysml +0 -0
  44. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/grammar/antlr4/pom.xml +0 -0
  45. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/LICENSE +0 -0
  46. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/README.md +0 -0
  47. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/__init__.py +0 -0
  48. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Analysis/AnalysisTooling.sysml +0 -0
  49. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml +0 -0
  50. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml +0 -0
  51. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Analysis/TradeStudies.sysml +0 -0
  52. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Cause and Effect/CausationConnections.sysml +0 -0
  53. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml +0 -0
  54. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Geometry/ShapeItems.sysml +0 -0
  55. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Geometry/SpatialItems.sysml +0 -0
  56. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Metadata/ImageMetadata.sysml +0 -0
  57. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml +0 -0
  58. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Metadata/ParametersOfInterestMetadata.sysml +0 -0
  59. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Metadata/RiskMetadata.sysml +0 -0
  60. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQ.sysml +0 -0
  61. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml +0 -0
  62. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAtomicNuclear.sysml +0 -0
  63. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml +0 -0
  64. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCharacteristicNumbers.sysml +0 -0
  65. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQChemistryMolecular.sysml +0 -0
  66. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCondensedMatter.sysml +0 -0
  67. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQElectromagnetism.sysml +0 -0
  68. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQInformation.sysml +0 -0
  69. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml +0 -0
  70. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml +0 -0
  71. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml +0 -0
  72. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/ISQThermodynamics.sysml +0 -0
  73. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementRefCalculations.sysml +0 -0
  74. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementReferences.sysml +0 -0
  75. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml +0 -0
  76. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/QuantityCalculations.sysml +0 -0
  77. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/SI.sysml +0 -0
  78. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml +0 -0
  79. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/TensorCalculations.sysml +0 -0
  80. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml +0 -0
  81. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/USCustomaryUnits.sysml +0 -0
  82. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Quantities and Units/VectorCalculations.sysml +0 -0
  83. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Requirement Derivation/DerivationConnections.sysml +0 -0
  84. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/domain/Requirement Derivation/RequirementDerivation.sysml +0 -0
  85. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Base.kerml +0 -0
  86. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/BaseFunctions.kerml +0 -0
  87. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/BooleanFunctions.kerml +0 -0
  88. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Clocks.kerml +0 -0
  89. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/CollectionFunctions.kerml +0 -0
  90. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Collections.kerml +0 -0
  91. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/ComplexFunctions.kerml +0 -0
  92. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/ControlFunctions.kerml +0 -0
  93. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/ControlPerformances.kerml +0 -0
  94. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/DataFunctions.kerml +0 -0
  95. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml +0 -0
  96. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/IntegerFunctions.kerml +0 -0
  97. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/KerML.kerml +0 -0
  98. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Links.kerml +0 -0
  99. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Metaobjects.kerml +0 -0
  100. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/NaturalFunctions.kerml +0 -0
  101. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/NumericalFunctions.kerml +0 -0
  102. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Objects.kerml +0 -0
  103. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Observation.kerml +0 -0
  104. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/OccurrenceFunctions.kerml +0 -0
  105. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Occurrences.kerml +0 -0
  106. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Performances.kerml +0 -0
  107. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/RationalFunctions.kerml +0 -0
  108. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/RealFunctions.kerml +0 -0
  109. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/ScalarFunctions.kerml +0 -0
  110. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/ScalarValues.kerml +0 -0
  111. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/SequenceFunctions.kerml +0 -0
  112. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/SpatialFrames.kerml +0 -0
  113. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/StatePerformances.kerml +0 -0
  114. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/StringFunctions.kerml +0 -0
  115. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Transfers.kerml +0 -0
  116. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/TransitionPerformances.kerml +0 -0
  117. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/TrigFunctions.kerml +0 -0
  118. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/Triggers.kerml +0 -0
  119. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/VectorFunctions.kerml +0 -0
  120. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/kernel/VectorValues.kerml +0 -0
  121. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Actions.sysml +0 -0
  122. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Allocations.sysml +0 -0
  123. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/AnalysisCases.sysml +0 -0
  124. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Attributes.sysml +0 -0
  125. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Calculations.sysml +0 -0
  126. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Cases.sysml +0 -0
  127. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Connections.sysml +0 -0
  128. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Constraints.sysml +0 -0
  129. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Flows.sysml +0 -0
  130. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Interfaces.sysml +0 -0
  131. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Items.sysml +0 -0
  132. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Metadata.sysml +0 -0
  133. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Parts.sysml +0 -0
  134. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Ports.sysml +0 -0
  135. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Requirements.sysml +0 -0
  136. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/StandardViewDefinitions.sysml +0 -0
  137. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/States.sysml +0 -0
  138. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/SysML.sysml +0 -0
  139. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/UseCases.sysml +0 -0
  140. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/VerificationCases.sysml +0 -0
  141. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/library/systems/Views.sysml +0 -0
  142. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/navigate.py +0 -0
  143. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/plantuml.py +0 -0
  144. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/project.py +0 -0
  145. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/store.py +0 -0
  146. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/us_customary_units.txt +0 -0
  147. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/usage.py +0 -0
  148. {sysmlpy-0.58.0 → sysmlpy-0.60.0}/src/sysmlpy/validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sysmlpy
3
- Version: 0.58.0
3
+ Version: 0.60.0
4
4
  Summary:
5
5
  License-File: LICENSE
6
6
  Author: Jon R. Fox (mycr0ft)
@@ -6,7 +6,7 @@ build-backend = "poetry.core.masonry.api"
6
6
 
7
7
  [project]
8
8
  name = "sysmlpy"
9
- version = "0.58.0"
9
+ version = "0.60.0"
10
10
  description = ""
11
11
  authors = [{ name = "Jon R. Fox (mycr0ft)", email = "jon.fox@drfox.com" }]
12
12
  readme = "README.md"
@@ -25,7 +25,7 @@ __all__ = [
25
25
  "render_state_transition_view_svg", "boxes_view",
26
26
  ]
27
27
  __author__ = "Jon Fox"
28
- __version__ = "0.58.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": False,
7154
- "isNonunique": False,
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": False,
13604
- "isNonunique": False,
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
- if self.isOrdered and not self.isOrdered2:
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 where
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 False
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
- for segment in segments[1:]:
2667
- # Find `segment` among the current element's descendants,
2668
- # stopping at that element's own subtree boundary.
2669
- current_element = self._find_member(current_element, segment)
2670
- if current_element is None:
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
- else:
3187
- current_type = defining
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