sysmlpy 0.83.0__tar.gz → 0.85.0__tar.gz

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