sysmlpy 0.1.0__py3-none-any.whl
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/__init__.py +226 -0
- sysmlpy/__main__.py +75 -0
- sysmlpy/antlr/README.md +146 -0
- sysmlpy/antlr/SysMLv2Lexer.interp +695 -0
- sysmlpy/antlr/SysMLv2Lexer.py +1123 -0
- sysmlpy/antlr/SysMLv2Lexer.tokens +444 -0
- sysmlpy/antlr/SysMLv2Parser.interp +960 -0
- sysmlpy/antlr/SysMLv2Parser.py +40750 -0
- sysmlpy/antlr/SysMLv2Parser.tokens +444 -0
- sysmlpy/antlr/SysMLv2ParserListener.py +4485 -0
- sysmlpy/antlr/SysMLv2ParserVisitor.py +2498 -0
- sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +695 -0
- sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +1123 -0
- sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +444 -0
- sysmlpy/antlr_parser.py +185 -0
- sysmlpy/antlr_visitor.py +10864 -0
- sysmlpy/definition.py +1115 -0
- sysmlpy/examples/attribute_values.py +161 -0
- sysmlpy/examples/part_attributes.py +139 -0
- sysmlpy/examples/tuples_sequences.py +231 -0
- sysmlpy/formatting.py +47 -0
- sysmlpy/grammar/antlr4/README.md +30 -0
- sysmlpy/grammar/antlr4/SysMLv2Lexer.g4 +931 -0
- sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +695 -0
- sysmlpy/grammar/antlr4/SysMLv2Lexer.py +1123 -0
- sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +444 -0
- sysmlpy/grammar/antlr4/SysMLv2Parser.g4 +2432 -0
- sysmlpy/grammar/antlr4/SysMLv2Parser.interp +960 -0
- sysmlpy/grammar/antlr4/SysMLv2Parser.py +40750 -0
- sysmlpy/grammar/antlr4/SysMLv2Parser.tokens +444 -0
- sysmlpy/grammar/antlr4/SysMLv2ParserListener.py +4485 -0
- sysmlpy/grammar/antlr4/SysMLv2ParserVisitor.py +2498 -0
- sysmlpy/grammar/antlr4/desc.xml +7 -0
- sysmlpy/grammar/antlr4/examples/camera.sysml +14 -0
- sysmlpy/grammar/antlr4/examples/toaster-system.sysml +193 -0
- sysmlpy/grammar/antlr4/examples/vehicle-model.sysml +118 -0
- sysmlpy/grammar/antlr4/pom.xml +59 -0
- sysmlpy/grammar/classes.py +8610 -0
- sysmlpy/library/LICENSE +165 -0
- sysmlpy/library/README.md +52 -0
- sysmlpy/library/__init__.py +0 -0
- sysmlpy/library/domain/Analysis/AnalysisTooling.sysml +34 -0
- sysmlpy/library/domain/Analysis/SampledFunctions.sysml +119 -0
- sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml +143 -0
- sysmlpy/library/domain/Analysis/TradeStudies.sysml +171 -0
- sysmlpy/library/domain/Cause and Effect/CausationConnections.sysml +83 -0
- sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml +81 -0
- sysmlpy/library/domain/Geometry/ShapeItems.sysml +899 -0
- sysmlpy/library/domain/Geometry/SpatialItems.sysml +168 -0
- sysmlpy/library/domain/Metadata/ImageMetadata.sysml +78 -0
- sysmlpy/library/domain/Metadata/ModelingMetadata.sysml +143 -0
- sysmlpy/library/domain/Metadata/ParametersOfInterestMetadata.sysml +39 -0
- sysmlpy/library/domain/Metadata/RiskMetadata.sysml +100 -0
- sysmlpy/library/domain/Quantities and Units/ISQ.sysml +42 -0
- sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml +439 -0
- sysmlpy/library/domain/Quantities and Units/ISQAtomicNuclear.sysml +2726 -0
- sysmlpy/library/domain/Quantities and Units/ISQBase.sysml +206 -0
- sysmlpy/library/domain/Quantities and Units/ISQCharacteristicNumbers.sysml +1991 -0
- sysmlpy/library/domain/Quantities and Units/ISQChemistryMolecular.sysml +1353 -0
- sysmlpy/library/domain/Quantities and Units/ISQCondensedMatter.sysml +1223 -0
- sysmlpy/library/domain/Quantities and Units/ISQElectromagnetism.sysml +2333 -0
- sysmlpy/library/domain/Quantities and Units/ISQInformation.sysml +958 -0
- sysmlpy/library/domain/Quantities and Units/ISQLight.sysml +1537 -0
- sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml +1564 -0
- sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml +1169 -0
- sysmlpy/library/domain/Quantities and Units/ISQThermodynamics.sysml +1256 -0
- sysmlpy/library/domain/Quantities and Units/MeasurementRefCalculations.sysml +30 -0
- sysmlpy/library/domain/Quantities and Units/MeasurementReferences.sysml +526 -0
- sysmlpy/library/domain/Quantities and Units/Quantities.sysml +107 -0
- sysmlpy/library/domain/Quantities and Units/QuantityCalculations.sysml +70 -0
- sysmlpy/library/domain/Quantities and Units/SI.sysml +378 -0
- sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml +48 -0
- sysmlpy/library/domain/Quantities and Units/TensorCalculations.sysml +50 -0
- sysmlpy/library/domain/Quantities and Units/Time.sysml +274 -0
- sysmlpy/library/domain/Quantities and Units/USCustomaryUnits.sysml +260 -0
- sysmlpy/library/domain/Quantities and Units/VectorCalculations.sysml +62 -0
- sysmlpy/library/domain/Requirement Derivation/DerivationConnections.sysml +63 -0
- sysmlpy/library/domain/Requirement Derivation/RequirementDerivation.sysml +39 -0
- sysmlpy/library/kernel/Base.kerml +95 -0
- sysmlpy/library/kernel/BaseFunctions.kerml +80 -0
- sysmlpy/library/kernel/BooleanFunctions.kerml +22 -0
- sysmlpy/library/kernel/Clocks.kerml +156 -0
- sysmlpy/library/kernel/CollectionFunctions.kerml +68 -0
- sysmlpy/library/kernel/Collections.kerml +147 -0
- sysmlpy/library/kernel/ComplexFunctions.kerml +47 -0
- sysmlpy/library/kernel/ControlFunctions.kerml +117 -0
- sysmlpy/library/kernel/ControlPerformances.kerml +135 -0
- sysmlpy/library/kernel/DataFunctions.kerml +43 -0
- sysmlpy/library/kernel/FeatureReferencingPerformances.kerml +190 -0
- sysmlpy/library/kernel/IntegerFunctions.kerml +43 -0
- sysmlpy/library/kernel/KerML.kerml +483 -0
- sysmlpy/library/kernel/Links.kerml +67 -0
- sysmlpy/library/kernel/Metaobjects.kerml +58 -0
- sysmlpy/library/kernel/NaturalFunctions.kerml +27 -0
- sysmlpy/library/kernel/NumericalFunctions.kerml +43 -0
- sysmlpy/library/kernel/Objects.kerml +212 -0
- sysmlpy/library/kernel/Observation.kerml +161 -0
- sysmlpy/library/kernel/OccurrenceFunctions.kerml +154 -0
- sysmlpy/library/kernel/Occurrences.kerml +992 -0
- sysmlpy/library/kernel/Performances.kerml +293 -0
- sysmlpy/library/kernel/RationalFunctions.kerml +49 -0
- sysmlpy/library/kernel/RealFunctions.kerml +56 -0
- sysmlpy/library/kernel/ScalarFunctions.kerml +33 -0
- sysmlpy/library/kernel/ScalarValues.kerml +23 -0
- sysmlpy/library/kernel/SequenceFunctions.kerml +111 -0
- sysmlpy/library/kernel/SpatialFrames.kerml +197 -0
- sysmlpy/library/kernel/StatePerformances.kerml +145 -0
- sysmlpy/library/kernel/StringFunctions.kerml +25 -0
- sysmlpy/library/kernel/Transfers.kerml +281 -0
- sysmlpy/library/kernel/TransitionPerformances.kerml +66 -0
- sysmlpy/library/kernel/TrigFunctions.kerml +35 -0
- sysmlpy/library/kernel/Triggers.kerml +188 -0
- sysmlpy/library/kernel/VectorFunctions.kerml +273 -0
- sysmlpy/library/kernel/VectorValues.kerml +64 -0
- sysmlpy/library/systems/Actions.sysml +552 -0
- sysmlpy/library/systems/Allocations.sysml +29 -0
- sysmlpy/library/systems/AnalysisCases.sysml +38 -0
- sysmlpy/library/systems/Attributes.sysml +25 -0
- sysmlpy/library/systems/Calculations.sysml +37 -0
- sysmlpy/library/systems/Cases.sysml +71 -0
- sysmlpy/library/systems/Connections.sysml +60 -0
- sysmlpy/library/systems/Constraints.sysml +44 -0
- sysmlpy/library/systems/Flows.sysml +126 -0
- sysmlpy/library/systems/Interfaces.sysml +89 -0
- sysmlpy/library/systems/Items.sysml +153 -0
- sysmlpy/library/systems/Metadata.sysml +32 -0
- sysmlpy/library/systems/Parts.sysml +81 -0
- sysmlpy/library/systems/Ports.sysml +54 -0
- sysmlpy/library/systems/Requirements.sysml +194 -0
- sysmlpy/library/systems/StandardViewDefinitions.sysml +123 -0
- sysmlpy/library/systems/States.sysml +103 -0
- sysmlpy/library/systems/SysML.sysml +539 -0
- sysmlpy/library/systems/UseCases.sysml +57 -0
- sysmlpy/library/systems/VerificationCases.sysml +103 -0
- sysmlpy/library/systems/Views.sysml +164 -0
- sysmlpy/navigate.py +272 -0
- sysmlpy/store.py +547 -0
- sysmlpy/usage.py +2978 -0
- sysmlpy-0.1.0.dist-info/METADATA +230 -0
- sysmlpy-0.1.0.dist-info/RECORD +143 -0
- sysmlpy-0.1.0.dist-info/WHEEL +4 -0
- sysmlpy-0.1.0.dist-info/entry_points.txt +3 -0
- sysmlpy-0.1.0.dist-info/licenses/LICENSE +21 -0
sysmlpy/usage.py
ADDED
|
@@ -0,0 +1,2978 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Created on Fri Jun 30 23:23:31 2023
|
|
5
|
+
|
|
6
|
+
@author: christophercox
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# import os
|
|
11
|
+
|
|
12
|
+
# os.chdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
|
13
|
+
|
|
14
|
+
import uuid as uuidlib
|
|
15
|
+
|
|
16
|
+
import pint
|
|
17
|
+
|
|
18
|
+
ureg = pint.UnitRegistry()
|
|
19
|
+
|
|
20
|
+
from sysmlpy.formatting import classtree
|
|
21
|
+
from sysmlpy.navigate import Searchable
|
|
22
|
+
|
|
23
|
+
from sysmlpy.grammar.classes import (
|
|
24
|
+
Identification,
|
|
25
|
+
DefinitionBody,
|
|
26
|
+
DefinitionBodyItem,
|
|
27
|
+
FeatureSpecializationPart,
|
|
28
|
+
SubclassificationPart,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
from sysmlpy.grammar.classes import (
|
|
32
|
+
AttributeUsage,
|
|
33
|
+
AttributeDefinition,
|
|
34
|
+
ValuePart,
|
|
35
|
+
PartUsage,
|
|
36
|
+
PartDefinition,
|
|
37
|
+
ItemUsage,
|
|
38
|
+
ItemDefinition,
|
|
39
|
+
PortUsage,
|
|
40
|
+
PortDefinition,
|
|
41
|
+
DefaultReferenceUsage,
|
|
42
|
+
RefPrefix,
|
|
43
|
+
ActionUsage,
|
|
44
|
+
ActionDefinition,
|
|
45
|
+
RequirementDefinition,
|
|
46
|
+
UseCaseDefinition,
|
|
47
|
+
StateUsage,
|
|
48
|
+
StateDefinition,
|
|
49
|
+
ConstraintUsage,
|
|
50
|
+
ConstraintDefinition,
|
|
51
|
+
ConnectionUsage,
|
|
52
|
+
ConnectionDefinition,
|
|
53
|
+
FlowConnectionUsage,
|
|
54
|
+
FlowConnectionDefinition,
|
|
55
|
+
CalculationUsage,
|
|
56
|
+
CalculationDefinition,
|
|
57
|
+
EnumerationDefinition,
|
|
58
|
+
AllocationDefinition,
|
|
59
|
+
AllocationUsage,
|
|
60
|
+
MetadataDefinition,
|
|
61
|
+
MetadataUsage,
|
|
62
|
+
RenderingDefinition,
|
|
63
|
+
RenderingUsage,
|
|
64
|
+
IndividualDefinition,
|
|
65
|
+
IndividualUsageSimple,
|
|
66
|
+
FlowDefinition,
|
|
67
|
+
ViewDefinition,
|
|
68
|
+
ViewUsage,
|
|
69
|
+
ViewpointDefinition,
|
|
70
|
+
ViewpointUsage,
|
|
71
|
+
ConcernDefinition,
|
|
72
|
+
ConcernUsage,
|
|
73
|
+
CaseDefinition,
|
|
74
|
+
CaseUsage,
|
|
75
|
+
AnalysisCaseDefinition,
|
|
76
|
+
AnalysisCaseUsage,
|
|
77
|
+
VerificationCaseDefinition,
|
|
78
|
+
VerificationCaseUsage,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class Usage(Searchable):
|
|
83
|
+
"""Base class for all SysML v2 usage and definition wrapper objects."""
|
|
84
|
+
|
|
85
|
+
#: SysML type keyword for this element (overridden by each subclass).
|
|
86
|
+
sysml_type = None
|
|
87
|
+
|
|
88
|
+
def __init__(self):
|
|
89
|
+
self.name = str(uuidlib.uuid4())
|
|
90
|
+
self.children = []
|
|
91
|
+
self.typedby = None
|
|
92
|
+
self._is_definition = None # overridden via the setter below
|
|
93
|
+
self.parent = None
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def is_definition(self):
|
|
97
|
+
"""``True`` when this object wraps a *definition* (e.g. ``part def``)
|
|
98
|
+
rather than a usage (``part``).
|
|
99
|
+
|
|
100
|
+
Subclass ``__init__`` methods assign ``self.is_definition = True/False``
|
|
101
|
+
which is stored via the setter so we never mask existing instance
|
|
102
|
+
variable semantics.
|
|
103
|
+
"""
|
|
104
|
+
if self._is_definition is not None:
|
|
105
|
+
return self._is_definition
|
|
106
|
+
# Fallback: infer from the grammar class name
|
|
107
|
+
return type(getattr(self, "grammar", None)).__name__.endswith("Definition")
|
|
108
|
+
|
|
109
|
+
@is_definition.setter
|
|
110
|
+
def is_definition(self, value):
|
|
111
|
+
self._is_definition = bool(value)
|
|
112
|
+
|
|
113
|
+
def _ensure_body(self, subgrammar="usage"):
|
|
114
|
+
# Add children
|
|
115
|
+
body = []
|
|
116
|
+
for abc in self.children:
|
|
117
|
+
body.append(
|
|
118
|
+
DefinitionBodyItem(
|
|
119
|
+
abc._get_definition(child="DefinitionBody")
|
|
120
|
+
).get_definition()
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
if len(body) > 0:
|
|
124
|
+
target = getattr(self.grammar, subgrammar)
|
|
125
|
+
if hasattr(target, 'completion'):
|
|
126
|
+
target.completion.body.body = DefinitionBody(
|
|
127
|
+
{"name": "DefinitionBody", "ownedRelatedElement": body}
|
|
128
|
+
)
|
|
129
|
+
else:
|
|
130
|
+
target.body = DefinitionBody(
|
|
131
|
+
{"name": "DefinitionBody", "ownedRelatedElement": body}
|
|
132
|
+
)
|
|
133
|
+
return self
|
|
134
|
+
|
|
135
|
+
def usage_dump(self, child):
|
|
136
|
+
# This is a usage.
|
|
137
|
+
|
|
138
|
+
self._ensure_body("usage")
|
|
139
|
+
|
|
140
|
+
# Add packaging
|
|
141
|
+
package = {
|
|
142
|
+
"name": "StructureUsageElement",
|
|
143
|
+
"ownedRelatedElement": self.grammar.get_definition(),
|
|
144
|
+
}
|
|
145
|
+
package = {"name": "OccurrenceUsageElement", "ownedRelatedElement": package}
|
|
146
|
+
|
|
147
|
+
if child == "DefinitionBody":
|
|
148
|
+
package = {
|
|
149
|
+
"name": "OccurrenceUsageMember",
|
|
150
|
+
"prefix": None,
|
|
151
|
+
"ownedRelatedElement": [package],
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]}
|
|
155
|
+
elif "PackageBody":
|
|
156
|
+
package = {"name": "UsageElement", "ownedRelatedElement": package}
|
|
157
|
+
package = {
|
|
158
|
+
"name": "PackageMember",
|
|
159
|
+
"ownedRelatedElement": package,
|
|
160
|
+
"prefix": None,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return package
|
|
164
|
+
|
|
165
|
+
def definition_dump(self, child):
|
|
166
|
+
# This is a definition.
|
|
167
|
+
|
|
168
|
+
self._ensure_body("definition")
|
|
169
|
+
|
|
170
|
+
package = {
|
|
171
|
+
"name": "DefinitionElement",
|
|
172
|
+
"ownedRelatedElement": self.grammar.get_definition(),
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if child == "DefinitionBody":
|
|
176
|
+
package = {
|
|
177
|
+
"name": "DefinitionMember",
|
|
178
|
+
"prefix": None,
|
|
179
|
+
"ownedRelatedElement": [package],
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]}
|
|
183
|
+
|
|
184
|
+
elif child == "PackageBody" or child == None:
|
|
185
|
+
# Add these packets to make this dump without parents
|
|
186
|
+
|
|
187
|
+
package = {
|
|
188
|
+
"name": "PackageMember",
|
|
189
|
+
"ownedRelatedElement": package,
|
|
190
|
+
"prefix": None,
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return package
|
|
194
|
+
|
|
195
|
+
def _get_definition(self, child=None):
|
|
196
|
+
# Determine if this is a usage or definition based on grammar class name
|
|
197
|
+
grammar_cls_name = type(self.grammar).__name__
|
|
198
|
+
is_def = grammar_cls_name.endswith('Definition')
|
|
199
|
+
|
|
200
|
+
if is_def:
|
|
201
|
+
package = self.definition_dump(child)
|
|
202
|
+
else:
|
|
203
|
+
package = self.usage_dump(child)
|
|
204
|
+
|
|
205
|
+
if child is None:
|
|
206
|
+
package = {
|
|
207
|
+
"name": "PackageBodyElement",
|
|
208
|
+
"ownedRelationship": [package],
|
|
209
|
+
"prefix": None,
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
# Add the typed by definition to the package output
|
|
213
|
+
if self.typedby is not None:
|
|
214
|
+
if child is None:
|
|
215
|
+
package["ownedRelationship"].insert(
|
|
216
|
+
0, self.typedby._get_definition(child="PackageBody")
|
|
217
|
+
)
|
|
218
|
+
elif child == "PackageBody":
|
|
219
|
+
package = [self.typedby._get_definition(child="PackageBody"), package]
|
|
220
|
+
else:
|
|
221
|
+
package["ownedRelationship"].insert(
|
|
222
|
+
0, self.typedby._get_definition(child=child)["ownedRelationship"][0]
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
return package
|
|
226
|
+
|
|
227
|
+
def dump(self, child=None):
|
|
228
|
+
return classtree(self._get_definition(child)).dump()
|
|
229
|
+
|
|
230
|
+
def __repr__(self):
|
|
231
|
+
# Safely get name
|
|
232
|
+
try:
|
|
233
|
+
name = getattr(self, 'name', None)
|
|
234
|
+
if not name:
|
|
235
|
+
id_obj = getattr(self.grammar, 'usage', None)
|
|
236
|
+
if id_obj:
|
|
237
|
+
id_obj = getattr(id_obj.declaration, 'declaration', None)
|
|
238
|
+
if id_obj:
|
|
239
|
+
name = getattr(id_obj.identification, 'declaredName', None)
|
|
240
|
+
except (AttributeError, TypeError):
|
|
241
|
+
name = None
|
|
242
|
+
|
|
243
|
+
# Safely get shortname
|
|
244
|
+
try:
|
|
245
|
+
shortname = None
|
|
246
|
+
id_obj = getattr(self.grammar, 'usage', None)
|
|
247
|
+
if id_obj:
|
|
248
|
+
id_obj = getattr(id_obj.declaration, 'declaration', None)
|
|
249
|
+
if id_obj:
|
|
250
|
+
shortname = getattr(id_obj.identification, 'declaredShortName', None)
|
|
251
|
+
if shortname:
|
|
252
|
+
shortname = shortname.strip('<').strip('>')
|
|
253
|
+
except (AttributeError, TypeError):
|
|
254
|
+
shortname = None
|
|
255
|
+
|
|
256
|
+
is_def = hasattr(self.grammar, 'definition')
|
|
257
|
+
cls_name = self.__class__.__name__
|
|
258
|
+
|
|
259
|
+
if is_def:
|
|
260
|
+
if name and shortname:
|
|
261
|
+
return f"{cls_name}(definition=True, name={name!r}, shortname={shortname!r})"
|
|
262
|
+
elif name:
|
|
263
|
+
return f"{cls_name}(definition=True, name={name!r})"
|
|
264
|
+
else:
|
|
265
|
+
return f"{cls_name}(definition=True)"
|
|
266
|
+
else:
|
|
267
|
+
if name and shortname:
|
|
268
|
+
return f"{cls_name}(name={name!r}, shortname={shortname!r})"
|
|
269
|
+
elif name:
|
|
270
|
+
return f"{cls_name}(name={name!r})"
|
|
271
|
+
else:
|
|
272
|
+
return f"{cls_name}()"
|
|
273
|
+
|
|
274
|
+
def _set_name(self, name, short=False):
|
|
275
|
+
if hasattr(self.grammar, "usage"):
|
|
276
|
+
path = self.grammar.usage.declaration.declaration
|
|
277
|
+
elif hasattr(self.grammar, "definition"):
|
|
278
|
+
path = self.grammar.definition.declaration
|
|
279
|
+
else:
|
|
280
|
+
# Navigate recursively through .declaration chain to find identification
|
|
281
|
+
path = self.grammar.declaration
|
|
282
|
+
while hasattr(path, "declaration") and not hasattr(path, "identification"):
|
|
283
|
+
path = path.declaration
|
|
284
|
+
|
|
285
|
+
if path.identification is None:
|
|
286
|
+
path.identification = Identification()
|
|
287
|
+
|
|
288
|
+
if short:
|
|
289
|
+
path.identification.declaredShortName = "<" + name + ">"
|
|
290
|
+
else:
|
|
291
|
+
self.name = name
|
|
292
|
+
path.identification.declaredName = name
|
|
293
|
+
|
|
294
|
+
return self
|
|
295
|
+
|
|
296
|
+
def _get_name(self):
|
|
297
|
+
return self.grammar.usage.declaration.declaration.identification.declaredName
|
|
298
|
+
|
|
299
|
+
def _set_child(self, child):
|
|
300
|
+
self.children.append(child)
|
|
301
|
+
child.parent = self
|
|
302
|
+
return self
|
|
303
|
+
|
|
304
|
+
def _get_child(self, featurechain):
|
|
305
|
+
# 'x.y.z'
|
|
306
|
+
if isinstance(featurechain, str):
|
|
307
|
+
fc = featurechain.split(".")
|
|
308
|
+
else:
|
|
309
|
+
raise TypeError
|
|
310
|
+
|
|
311
|
+
if fc[0] == self.name:
|
|
312
|
+
# This first one must match self name, otherwise pass it all
|
|
313
|
+
featurechain = ".".join(fc[1:])
|
|
314
|
+
|
|
315
|
+
for child in self.children:
|
|
316
|
+
fcs = featurechain.split(".")
|
|
317
|
+
if child.name == fcs[0]:
|
|
318
|
+
if len(fcs) == 1:
|
|
319
|
+
return child
|
|
320
|
+
else:
|
|
321
|
+
return child._get_child(featurechain)
|
|
322
|
+
|
|
323
|
+
def _set_typed_by(self, typed):
|
|
324
|
+
# Only set if the pointed object is a definition
|
|
325
|
+
if "definition" in typed.grammar.__dict__:
|
|
326
|
+
self.typedby = typed
|
|
327
|
+
if "definition" in self.grammar.__dict__:
|
|
328
|
+
raise ValueError("A definition element cannot be defined.")
|
|
329
|
+
else:
|
|
330
|
+
if self.grammar.usage.declaration.declaration.specialization is None:
|
|
331
|
+
package = {
|
|
332
|
+
"name": "QualifiedName",
|
|
333
|
+
"names": [typed.name],
|
|
334
|
+
}
|
|
335
|
+
package = {
|
|
336
|
+
"name": "FeatureType",
|
|
337
|
+
"type": package,
|
|
338
|
+
"ownedRelatedElement": [],
|
|
339
|
+
}
|
|
340
|
+
package = {"name": "OwnedFeatureTyping", "type": package}
|
|
341
|
+
package = {"name": "FeatureTyping", "ownedRelationship": package}
|
|
342
|
+
package = {"name": "TypedBy", "ownedRelationship": [package]}
|
|
343
|
+
package = {
|
|
344
|
+
"name": "Typings",
|
|
345
|
+
"typedby": package,
|
|
346
|
+
"ownedRelationship": [],
|
|
347
|
+
}
|
|
348
|
+
package = {
|
|
349
|
+
"name": "FeatureSpecialization",
|
|
350
|
+
"ownedRelationship": package,
|
|
351
|
+
}
|
|
352
|
+
package = {
|
|
353
|
+
"name": "FeatureSpecializationPart",
|
|
354
|
+
"specialization": [package],
|
|
355
|
+
"multiplicity": None,
|
|
356
|
+
"specialization2": [],
|
|
357
|
+
"multiplicity2": None,
|
|
358
|
+
}
|
|
359
|
+
self.grammar.usage.declaration.declaration.specialization = (
|
|
360
|
+
FeatureSpecializationPart(package)
|
|
361
|
+
)
|
|
362
|
+
else:
|
|
363
|
+
raise ValueError("Typed by element was not a definition.")
|
|
364
|
+
return self
|
|
365
|
+
|
|
366
|
+
def _set_specializes(self, *parents):
|
|
367
|
+
"""Set specialization (`:>`) for definitions.
|
|
368
|
+
|
|
369
|
+
In SysML v2: `part def Car :> Vehicle;`
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
*parents: One or more definition elements to specialize.
|
|
373
|
+
"""
|
|
374
|
+
if "definition" not in self.grammar.__dict__:
|
|
375
|
+
raise ValueError(
|
|
376
|
+
"Only definition elements can use specializes. "
|
|
377
|
+
"Use _set_subsets() for usage elements."
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
names = [p.name for p in parents]
|
|
381
|
+
relationships = []
|
|
382
|
+
for name in names:
|
|
383
|
+
relationships.append({
|
|
384
|
+
"name": "OwnedSubclassification",
|
|
385
|
+
"superclassifier": {
|
|
386
|
+
"name": "QualifiedName",
|
|
387
|
+
"names": [name],
|
|
388
|
+
},
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
package = {
|
|
392
|
+
"name": "SubclassificationPart",
|
|
393
|
+
"ownedRelationship": relationships,
|
|
394
|
+
}
|
|
395
|
+
self.grammar.definition.declaration.subclassificationpart = (
|
|
396
|
+
SubclassificationPart(package)
|
|
397
|
+
)
|
|
398
|
+
return self
|
|
399
|
+
|
|
400
|
+
def _set_subsets(self, *parents):
|
|
401
|
+
"""Set subsetting (`:>`) for usage elements.
|
|
402
|
+
|
|
403
|
+
In SysML v2: `part myEng :> eng;`
|
|
404
|
+
|
|
405
|
+
Args:
|
|
406
|
+
*parents: One or more elements to subset.
|
|
407
|
+
"""
|
|
408
|
+
if "definition" in self.grammar.__dict__:
|
|
409
|
+
raise ValueError(
|
|
410
|
+
"Definition elements cannot use subsets. "
|
|
411
|
+
"Use _set_specializes() for definitions."
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
names = [p.name if hasattr(p, 'name') else str(p) for p in parents]
|
|
415
|
+
relationships = []
|
|
416
|
+
for name in names:
|
|
417
|
+
relationships.append({
|
|
418
|
+
"name": "OwnedSubsetting",
|
|
419
|
+
"subsettedFeature": {
|
|
420
|
+
"name": "QualifiedName",
|
|
421
|
+
"names": [name],
|
|
422
|
+
},
|
|
423
|
+
"ownedRelatedElement": [],
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
package = {
|
|
427
|
+
"name": "Subsettings",
|
|
428
|
+
"ownedRelationship": relationships,
|
|
429
|
+
}
|
|
430
|
+
package = {
|
|
431
|
+
"name": "FeatureSpecialization",
|
|
432
|
+
"ownedRelationship": package,
|
|
433
|
+
}
|
|
434
|
+
package = {
|
|
435
|
+
"name": "FeatureSpecializationPart",
|
|
436
|
+
"specialization": [package],
|
|
437
|
+
"multiplicity": None,
|
|
438
|
+
"specialization2": [],
|
|
439
|
+
"multiplicity2": None,
|
|
440
|
+
}
|
|
441
|
+
self.grammar.usage.declaration.declaration.specialization = (
|
|
442
|
+
FeatureSpecializationPart(package)
|
|
443
|
+
)
|
|
444
|
+
return self
|
|
445
|
+
|
|
446
|
+
def _set_redefines(self, parent):
|
|
447
|
+
"""Set redefinition (`:>>`) for usage elements.
|
|
448
|
+
|
|
449
|
+
In SysML v2: `attribute :>> mass = 100;`
|
|
450
|
+
|
|
451
|
+
Args:
|
|
452
|
+
parent: The element being redefined.
|
|
453
|
+
"""
|
|
454
|
+
if "definition" in self.grammar.__dict__:
|
|
455
|
+
raise ValueError("Definition elements cannot use redefines.")
|
|
456
|
+
|
|
457
|
+
name = parent.name if hasattr(parent, 'name') else str(parent)
|
|
458
|
+
|
|
459
|
+
package = {
|
|
460
|
+
"name": "OwnedRedefinition",
|
|
461
|
+
"redefinedFeature": {
|
|
462
|
+
"name": "QualifiedName",
|
|
463
|
+
"names": [name],
|
|
464
|
+
},
|
|
465
|
+
"ownedRelatedElement": [],
|
|
466
|
+
}
|
|
467
|
+
package = {
|
|
468
|
+
"name": "Redefinitions",
|
|
469
|
+
"ownedRelationship": [package],
|
|
470
|
+
}
|
|
471
|
+
package = {
|
|
472
|
+
"name": "FeatureSpecialization",
|
|
473
|
+
"ownedRelationship": package,
|
|
474
|
+
}
|
|
475
|
+
package = {
|
|
476
|
+
"name": "FeatureSpecializationPart",
|
|
477
|
+
"specialization": [package],
|
|
478
|
+
"multiplicity": None,
|
|
479
|
+
"specialization2": [],
|
|
480
|
+
"multiplicity2": None,
|
|
481
|
+
}
|
|
482
|
+
self.grammar.usage.declaration.declaration.specialization = (
|
|
483
|
+
FeatureSpecializationPart(package)
|
|
484
|
+
)
|
|
485
|
+
return self
|
|
486
|
+
|
|
487
|
+
def _get_grammar(self):
|
|
488
|
+
self._ensure_body()
|
|
489
|
+
return self.grammar
|
|
490
|
+
|
|
491
|
+
def load_from_grammar(self, grammar):
|
|
492
|
+
#!TODO Typed By
|
|
493
|
+
self.__init__()
|
|
494
|
+
self.grammar = grammar
|
|
495
|
+
children = []
|
|
496
|
+
|
|
497
|
+
# Check if this is a definition or usage
|
|
498
|
+
# Some definition types use 'definition' (PartDefinition, AttributeDefinition)
|
|
499
|
+
# Others use 'declaration' directly (RequirementDefinition, UseCaseDefinition)
|
|
500
|
+
# PartDefinition: has .definition which is a Definition object
|
|
501
|
+
# Usage: has .declaration directly
|
|
502
|
+
|
|
503
|
+
# First check if grammar has 'definition' (for definitions like PartDefinition)
|
|
504
|
+
defn = getattr(grammar, 'definition', None)
|
|
505
|
+
if defn:
|
|
506
|
+
# This type uses 'definition' (PartDefinition, etc.)
|
|
507
|
+
# Get name from definition.declaration.identification.declaredName
|
|
508
|
+
u_name = defn.declaration.identification.declaredName
|
|
509
|
+
|
|
510
|
+
# Get body from definition.body
|
|
511
|
+
body = defn.body if hasattr(defn, 'body') else None
|
|
512
|
+
|
|
513
|
+
# body is DefinitionBody with .children
|
|
514
|
+
if body and hasattr(body, 'children') and body.children:
|
|
515
|
+
children_list = []
|
|
516
|
+
for body_item in body.children:
|
|
517
|
+
if hasattr(body_item, 'children') and body_item.children:
|
|
518
|
+
member = body_item.children[0]
|
|
519
|
+
if hasattr(member, 'children') and member.children:
|
|
520
|
+
inner = member.children[0]
|
|
521
|
+
# Handle DefinitionElement wrapping
|
|
522
|
+
if inner.__class__.__name__ == 'DefinitionElement' and hasattr(inner, 'children') and inner.children:
|
|
523
|
+
inner = inner.children[0]
|
|
524
|
+
if hasattr(inner, 'children'):
|
|
525
|
+
children_list.append(inner)
|
|
526
|
+
else:
|
|
527
|
+
children_list.append(inner)
|
|
528
|
+
elif hasattr(body_item, 'ownedRelatedElement'):
|
|
529
|
+
children_list.append(body_item)
|
|
530
|
+
children = children_list
|
|
531
|
+
else:
|
|
532
|
+
children = []
|
|
533
|
+
elif hasattr(grammar, 'usage'):
|
|
534
|
+
# This is a usage (like PartUsage, ItemUsage)
|
|
535
|
+
# Get name from grammar.usage.declaration.declaration.identification.declaredName
|
|
536
|
+
usage = grammar.usage
|
|
537
|
+
if hasattr(usage, 'declaration') and hasattr(usage.declaration, 'declaration'):
|
|
538
|
+
decl = usage.declaration.declaration
|
|
539
|
+
if hasattr(decl, 'identification') and decl.identification:
|
|
540
|
+
u_name = decl.identification.declaredName
|
|
541
|
+
else:
|
|
542
|
+
u_name = None
|
|
543
|
+
else:
|
|
544
|
+
u_name = None
|
|
545
|
+
|
|
546
|
+
# Extract children from usage body: grammar.usage.completion.body.body.children
|
|
547
|
+
# This mirrors the PartDefinition path: grammar.definition.body.children
|
|
548
|
+
try:
|
|
549
|
+
body = usage.completion.body.body
|
|
550
|
+
if hasattr(body, 'children') and body.children:
|
|
551
|
+
children_list = []
|
|
552
|
+
for body_item in body.children:
|
|
553
|
+
if hasattr(body_item, 'children') and body_item.children:
|
|
554
|
+
member = body_item.children[0]
|
|
555
|
+
mc = member.children if isinstance(member.children, list) else [member.children]
|
|
556
|
+
for inner in mc:
|
|
557
|
+
if inner is None:
|
|
558
|
+
continue
|
|
559
|
+
# Handle DefinitionElement wrapping
|
|
560
|
+
if inner.__class__.__name__ == 'DefinitionElement' and hasattr(inner, 'children') and inner.children:
|
|
561
|
+
inner = inner.children[0]
|
|
562
|
+
children_list.append(inner)
|
|
563
|
+
children = children_list
|
|
564
|
+
else:
|
|
565
|
+
children = []
|
|
566
|
+
except AttributeError:
|
|
567
|
+
children = []
|
|
568
|
+
elif hasattr(grammar, 'declaration'):
|
|
569
|
+
# This type uses 'declaration' directly (RequirementDefinition, UseCaseDefinition, some usages)
|
|
570
|
+
decl = grammar.declaration
|
|
571
|
+
u_name = None
|
|
572
|
+
|
|
573
|
+
# Check nested declaration for Usage (UsageDeclaration -> FeatureDeclaration)
|
|
574
|
+
nested_decl = getattr(decl, 'declaration', None)
|
|
575
|
+
if nested_decl and hasattr(nested_decl, 'identification') and nested_decl.identification:
|
|
576
|
+
u_name = nested_decl.identification.declaredName
|
|
577
|
+
# Check direct identification (for RequirementDefinition, UseCaseDefinition)
|
|
578
|
+
elif hasattr(decl, 'identification') and decl.identification:
|
|
579
|
+
u_name = decl.identification.declaredName
|
|
580
|
+
children = []
|
|
581
|
+
else:
|
|
582
|
+
u_name = None
|
|
583
|
+
children = []
|
|
584
|
+
|
|
585
|
+
if u_name is not None:
|
|
586
|
+
self.name = u_name
|
|
587
|
+
|
|
588
|
+
for child in children:
|
|
589
|
+
# Handle different child types
|
|
590
|
+
if hasattr(child, 'definition') and hasattr(child, 'body'):
|
|
591
|
+
# It's a Definition (PartDefinition, ItemDefinition, etc.)
|
|
592
|
+
sc = child
|
|
593
|
+
elif hasattr(child, 'children'):
|
|
594
|
+
# It's a StructureUsageElement or similar
|
|
595
|
+
sc = child.children if hasattr(child, 'children') else child
|
|
596
|
+
else:
|
|
597
|
+
continue
|
|
598
|
+
|
|
599
|
+
# Process the child
|
|
600
|
+
class_name = sc.__class__.__name__ if not hasattr(sc, '__class__') else sc.__class__.__name__
|
|
601
|
+
|
|
602
|
+
if class_name == "PartDefinition":
|
|
603
|
+
c = Part(definition=True).load_from_grammar(sc)
|
|
604
|
+
c.parent = self
|
|
605
|
+
self.children.append(c)
|
|
606
|
+
elif class_name == "ItemDefinition":
|
|
607
|
+
c = Item(definition=True).load_from_grammar(sc)
|
|
608
|
+
c.parent = self
|
|
609
|
+
self.children.append(c)
|
|
610
|
+
elif class_name == "PartUsage":
|
|
611
|
+
c = Part().load_from_grammar(sc)
|
|
612
|
+
c.parent = self
|
|
613
|
+
self.children.append(c)
|
|
614
|
+
elif class_name == "ItemUsage":
|
|
615
|
+
c = Item().load_from_grammar(sc)
|
|
616
|
+
c.parent = self
|
|
617
|
+
self.children.append(c)
|
|
618
|
+
elif class_name == "AttributeUsage":
|
|
619
|
+
c = Attribute().load_from_grammar(sc)
|
|
620
|
+
c.parent = self
|
|
621
|
+
self.children.append(c)
|
|
622
|
+
elif class_name == "AttributeDefinition":
|
|
623
|
+
c = Attribute(definition=True).load_from_grammar(sc)
|
|
624
|
+
c.parent = self
|
|
625
|
+
self.children.append(c)
|
|
626
|
+
elif class_name == "StructureUsageElement":
|
|
627
|
+
if hasattr(sc, 'children'):
|
|
628
|
+
inner = sc.children
|
|
629
|
+
if inner.__class__.__name__ == "PartUsage":
|
|
630
|
+
c = Part().load_from_grammar(inner)
|
|
631
|
+
c.parent = self
|
|
632
|
+
self.children.append(c)
|
|
633
|
+
elif inner.__class__.__name__ == "ItemUsage":
|
|
634
|
+
c = Item().load_from_grammar(inner)
|
|
635
|
+
c.parent = self
|
|
636
|
+
self.children.append(c)
|
|
637
|
+
elif class_name == "Definition":
|
|
638
|
+
# Unwrap Definition to get the inner type
|
|
639
|
+
if hasattr(sc, 'body') and hasattr(sc.body, 'children') and sc.body.children:
|
|
640
|
+
for body_item in sc.body.children:
|
|
641
|
+
if hasattr(body_item, 'children') and body_item.children:
|
|
642
|
+
inner = body_item.children[0]
|
|
643
|
+
if hasattr(inner, 'children'):
|
|
644
|
+
inner = inner.children
|
|
645
|
+
if inner.__class__.__name__ == 'PartDefinition':
|
|
646
|
+
c = Part(definition=True).load_from_grammar(inner)
|
|
647
|
+
else:
|
|
648
|
+
c = Item(definition=True).load_from_grammar(inner)
|
|
649
|
+
c.parent = self
|
|
650
|
+
self.children.append(c)
|
|
651
|
+
|
|
652
|
+
return self
|
|
653
|
+
|
|
654
|
+
def add_directed_feature(self, direction, name=str(uuidlib.uuid4())):
|
|
655
|
+
self._set_child(DefaultReference()._set_name(name).set_direction(direction))
|
|
656
|
+
return self
|
|
657
|
+
|
|
658
|
+
# def modify_directed_feature(self, direction, name):
|
|
659
|
+
# child = self._get_child(name)
|
|
660
|
+
# if child is not None:
|
|
661
|
+
# pass
|
|
662
|
+
# else:
|
|
663
|
+
# raise AttributeError("Invalid Feature Name or Chain")
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
class Attribute(Usage):
|
|
667
|
+
sysml_type = 'attribute'
|
|
668
|
+
def __init__(self, definition=False, name=None):
|
|
669
|
+
Usage.__init__(self)
|
|
670
|
+
|
|
671
|
+
if definition:
|
|
672
|
+
self.grammar = AttributeDefinition()
|
|
673
|
+
else:
|
|
674
|
+
self.grammar = AttributeUsage()
|
|
675
|
+
|
|
676
|
+
if name is not None:
|
|
677
|
+
self._set_name(name)
|
|
678
|
+
|
|
679
|
+
def usage_dump(self, child):
|
|
680
|
+
# Override - base output
|
|
681
|
+
|
|
682
|
+
# Add children
|
|
683
|
+
body = []
|
|
684
|
+
for abc in self.children:
|
|
685
|
+
body.append(DefinitionBodyItem(abc.dump(child=True)).get_definition())
|
|
686
|
+
if len(body) > 0:
|
|
687
|
+
self.grammar.usage.completion.body.body = DefinitionBody(
|
|
688
|
+
{"name": "DefinitionBody", "ownedRelatedElement": body}
|
|
689
|
+
)
|
|
690
|
+
|
|
691
|
+
# Add packaging
|
|
692
|
+
package = {
|
|
693
|
+
"name": "NonOccurrenceUsageElement",
|
|
694
|
+
"ownedRelatedElement": self.grammar.get_definition(),
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
if child == "DefinitionBody":
|
|
698
|
+
package = {
|
|
699
|
+
"name": "NonOccurrenceUsageMember",
|
|
700
|
+
"prefix": None,
|
|
701
|
+
"ownedRelatedElement": [package],
|
|
702
|
+
}
|
|
703
|
+
package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]}
|
|
704
|
+
else:
|
|
705
|
+
# Add these packets to make this dump without parents
|
|
706
|
+
package = {"name": "UsageElement", "ownedRelatedElement": package}
|
|
707
|
+
package = {
|
|
708
|
+
"name": "PackageMember",
|
|
709
|
+
"ownedRelatedElement": package,
|
|
710
|
+
"prefix": None,
|
|
711
|
+
}
|
|
712
|
+
return package
|
|
713
|
+
|
|
714
|
+
def set_value(self, value):
|
|
715
|
+
if not isinstance(value, pint.Quantity):
|
|
716
|
+
value = value * ureg.dimensionless
|
|
717
|
+
if isinstance(value, pint.Quantity):
|
|
718
|
+
# Only add units if not dimensionless
|
|
719
|
+
if not value.units.dimensionless:
|
|
720
|
+
package_units = {
|
|
721
|
+
"name": "QualifiedName",
|
|
722
|
+
"names": [str(value.units)],
|
|
723
|
+
}
|
|
724
|
+
package_units = {
|
|
725
|
+
"name": "FeatureReferenceMember",
|
|
726
|
+
"memberElement": package_units,
|
|
727
|
+
}
|
|
728
|
+
package_units = {
|
|
729
|
+
"name": "FeatureReferenceExpression",
|
|
730
|
+
"ownedRelationship": [package_units],
|
|
731
|
+
}
|
|
732
|
+
package_units = {
|
|
733
|
+
"name": "BaseExpression",
|
|
734
|
+
"ownedRelationship": package_units,
|
|
735
|
+
}
|
|
736
|
+
package_units = {
|
|
737
|
+
"name": "PrimaryExpression",
|
|
738
|
+
"operand": [],
|
|
739
|
+
"base": package_units,
|
|
740
|
+
"operator": [],
|
|
741
|
+
"ownedRelationship1": [],
|
|
742
|
+
"ownedRelationship2": [],
|
|
743
|
+
}
|
|
744
|
+
package_units = {
|
|
745
|
+
"name": "ExtentExpression",
|
|
746
|
+
"operator": "",
|
|
747
|
+
"ownedRelationship": [],
|
|
748
|
+
"primary": package_units,
|
|
749
|
+
}
|
|
750
|
+
package_units = {
|
|
751
|
+
"name": "UnaryExpression",
|
|
752
|
+
"operand": [],
|
|
753
|
+
"operator": None,
|
|
754
|
+
"extent": package_units,
|
|
755
|
+
}
|
|
756
|
+
package_units = {
|
|
757
|
+
"name": "ExponentiationExpression",
|
|
758
|
+
"operand": [],
|
|
759
|
+
"operator": [],
|
|
760
|
+
"unary": package_units,
|
|
761
|
+
}
|
|
762
|
+
package_units = {
|
|
763
|
+
"name": "MultiplicativeExpression",
|
|
764
|
+
"operation": [],
|
|
765
|
+
"exponential": package_units,
|
|
766
|
+
}
|
|
767
|
+
package_units = {
|
|
768
|
+
"name": "AdditiveExpression",
|
|
769
|
+
"operation": [],
|
|
770
|
+
"multiplicitive": package_units,
|
|
771
|
+
}
|
|
772
|
+
package_units = {
|
|
773
|
+
"name": "RangeExpression",
|
|
774
|
+
"operand": None,
|
|
775
|
+
"additive": package_units,
|
|
776
|
+
}
|
|
777
|
+
package_units = {
|
|
778
|
+
"name": "RelationalExpression",
|
|
779
|
+
"operation": [],
|
|
780
|
+
"range": package_units,
|
|
781
|
+
}
|
|
782
|
+
package_units = {
|
|
783
|
+
"name": "ClassificationExpression",
|
|
784
|
+
"operand": [],
|
|
785
|
+
"operator": None,
|
|
786
|
+
"ownedRelationship": [],
|
|
787
|
+
"relational": package_units,
|
|
788
|
+
}
|
|
789
|
+
package_units = {
|
|
790
|
+
"name": "EqualityExpression",
|
|
791
|
+
"operation": [],
|
|
792
|
+
"classification": package_units,
|
|
793
|
+
}
|
|
794
|
+
package_units = {
|
|
795
|
+
"name": "AndExpression",
|
|
796
|
+
"operation": [],
|
|
797
|
+
"equality": package_units,
|
|
798
|
+
}
|
|
799
|
+
package_units = {
|
|
800
|
+
"name": "XorExpression",
|
|
801
|
+
"operand": [],
|
|
802
|
+
"operator": [],
|
|
803
|
+
"and": package_units,
|
|
804
|
+
}
|
|
805
|
+
package_units = {
|
|
806
|
+
"name": "OrExpression",
|
|
807
|
+
"xor": package_units,
|
|
808
|
+
"operand": [],
|
|
809
|
+
"operator": [],
|
|
810
|
+
}
|
|
811
|
+
package_units = {
|
|
812
|
+
"name": "ImpliesExpression",
|
|
813
|
+
"operand": [],
|
|
814
|
+
"operator": [],
|
|
815
|
+
"or": package_units,
|
|
816
|
+
}
|
|
817
|
+
package_units = {
|
|
818
|
+
"name": "NullCoalescingExpression",
|
|
819
|
+
"implies": package_units,
|
|
820
|
+
"operator": [],
|
|
821
|
+
"operand": [],
|
|
822
|
+
}
|
|
823
|
+
package_units = {
|
|
824
|
+
"name": "ConditionalExpression",
|
|
825
|
+
"operator": None,
|
|
826
|
+
"operand": [package_units],
|
|
827
|
+
}
|
|
828
|
+
package_units = {"name": "OwnedExpression", "expression": package_units}
|
|
829
|
+
package_units = {
|
|
830
|
+
"name": "SequenceExpression",
|
|
831
|
+
"operation": [],
|
|
832
|
+
"ownedRelationship": package_units,
|
|
833
|
+
}
|
|
834
|
+
package_units = [package_units]
|
|
835
|
+
operator = ["["]
|
|
836
|
+
else:
|
|
837
|
+
package_units = []
|
|
838
|
+
operator = []
|
|
839
|
+
|
|
840
|
+
package = {
|
|
841
|
+
"name": "BaseExpression",
|
|
842
|
+
"ownedRelationship": {
|
|
843
|
+
"name": "LiteralInteger",
|
|
844
|
+
"value": str(value.magnitude),
|
|
845
|
+
},
|
|
846
|
+
}
|
|
847
|
+
package = {
|
|
848
|
+
"name": "PrimaryExpression",
|
|
849
|
+
"operand": package_units,
|
|
850
|
+
"base": package,
|
|
851
|
+
"operator": operator,
|
|
852
|
+
"ownedRelationship1": [],
|
|
853
|
+
"ownedRelationship2": [],
|
|
854
|
+
}
|
|
855
|
+
package = {
|
|
856
|
+
"name": "ExtentExpression",
|
|
857
|
+
"operator": "",
|
|
858
|
+
"ownedRelationship": [],
|
|
859
|
+
"primary": package,
|
|
860
|
+
}
|
|
861
|
+
package = {
|
|
862
|
+
"name": "UnaryExpression",
|
|
863
|
+
"operand": [],
|
|
864
|
+
"operator": None,
|
|
865
|
+
"extent": package,
|
|
866
|
+
}
|
|
867
|
+
package = {
|
|
868
|
+
"name": "ExponentiationExpression",
|
|
869
|
+
"operand": [],
|
|
870
|
+
"operator": [],
|
|
871
|
+
"unary": package,
|
|
872
|
+
}
|
|
873
|
+
package = {
|
|
874
|
+
"name": "MultiplicativeExpression",
|
|
875
|
+
"operation": [],
|
|
876
|
+
"exponential": package,
|
|
877
|
+
}
|
|
878
|
+
package = {
|
|
879
|
+
"name": "AdditiveExpression",
|
|
880
|
+
"operation": [],
|
|
881
|
+
"multiplicitive": package,
|
|
882
|
+
}
|
|
883
|
+
package = {
|
|
884
|
+
"name": "RangeExpression",
|
|
885
|
+
"operand": None,
|
|
886
|
+
"additive": package,
|
|
887
|
+
}
|
|
888
|
+
package = {
|
|
889
|
+
"name": "RelationalExpression",
|
|
890
|
+
"operation": [],
|
|
891
|
+
"range": package,
|
|
892
|
+
}
|
|
893
|
+
package = {
|
|
894
|
+
"name": "ClassificationExpression",
|
|
895
|
+
"operand": [],
|
|
896
|
+
"operator": None,
|
|
897
|
+
"ownedRelationship": [],
|
|
898
|
+
"relational": package,
|
|
899
|
+
}
|
|
900
|
+
package = {
|
|
901
|
+
"name": "EqualityExpression",
|
|
902
|
+
"operation": [],
|
|
903
|
+
"classification": package,
|
|
904
|
+
}
|
|
905
|
+
package = {
|
|
906
|
+
"name": "AndExpression",
|
|
907
|
+
"operation": [],
|
|
908
|
+
"equality": package,
|
|
909
|
+
}
|
|
910
|
+
package = {
|
|
911
|
+
"name": "XorExpression",
|
|
912
|
+
"operand": [],
|
|
913
|
+
"operator": [],
|
|
914
|
+
"and": package,
|
|
915
|
+
}
|
|
916
|
+
package = {
|
|
917
|
+
"name": "OrExpression",
|
|
918
|
+
"xor": package,
|
|
919
|
+
"operand": [],
|
|
920
|
+
"operator": [],
|
|
921
|
+
}
|
|
922
|
+
package = {
|
|
923
|
+
"name": "ImpliesExpression",
|
|
924
|
+
"operand": [],
|
|
925
|
+
"operator": [],
|
|
926
|
+
"or": package,
|
|
927
|
+
}
|
|
928
|
+
package = {
|
|
929
|
+
"name": "NullCoalescingExpression",
|
|
930
|
+
"implies": package,
|
|
931
|
+
"operator": [],
|
|
932
|
+
"operand": [],
|
|
933
|
+
}
|
|
934
|
+
package = {
|
|
935
|
+
"name": "ConditionalExpression",
|
|
936
|
+
"operator": None,
|
|
937
|
+
"operand": [package],
|
|
938
|
+
}
|
|
939
|
+
package = {"name": "OwnedExpression", "expression": package}
|
|
940
|
+
package = {
|
|
941
|
+
"name": "FeatureValue",
|
|
942
|
+
"isDefault": False,
|
|
943
|
+
"isEqual": False,
|
|
944
|
+
"isInitial": False,
|
|
945
|
+
"ownedRelatedElement": package,
|
|
946
|
+
}
|
|
947
|
+
package = {"name": "ValuePart", "ownedRelationship": [package]}
|
|
948
|
+
self.grammar.usage.completion.valuepart = ValuePart(package)
|
|
949
|
+
# value.unit
|
|
950
|
+
|
|
951
|
+
return self
|
|
952
|
+
|
|
953
|
+
def get_value(self):
|
|
954
|
+
valuepart = self.grammar.usage.completion.valuepart
|
|
955
|
+
if valuepart is None:
|
|
956
|
+
raise AttributeError("No valuepart found in grammar")
|
|
957
|
+
|
|
958
|
+
feature_value = valuepart.relationships[0]
|
|
959
|
+
primary = (
|
|
960
|
+
feature_value.element.expression.operands[0]
|
|
961
|
+
.implies.orexpression.xor.andexpression.equality.classification.relational.range.additive.left_hand.exponential.unary.extent.primary
|
|
962
|
+
)
|
|
963
|
+
|
|
964
|
+
base = primary.base.relationship
|
|
965
|
+
base_name = base.__class__.__name__
|
|
966
|
+
|
|
967
|
+
has_unit = hasattr(primary, 'operand') and primary.operand and len(primary.operand) > 0
|
|
968
|
+
|
|
969
|
+
if has_unit:
|
|
970
|
+
unit = primary.operand[0]
|
|
971
|
+
unit_name = None
|
|
972
|
+
if hasattr(unit, 'relationship'):
|
|
973
|
+
unit_expr = unit.relationship.expression
|
|
974
|
+
if hasattr(unit_expr, 'operands') and unit_expr.operands:
|
|
975
|
+
primary2 = unit_expr.operands[0]
|
|
976
|
+
if hasattr(primary2, 'implies'):
|
|
977
|
+
primary2 = primary2.implies.orexpression.xor.andexpression.equality.classification.relational.range.additive.left_hand.exponential.unary.extent.primary
|
|
978
|
+
if hasattr(primary2, 'base'):
|
|
979
|
+
unit_rel = primary2.base.relationship
|
|
980
|
+
if hasattr(unit_rel, 'children') and unit_rel.children:
|
|
981
|
+
unit_name = unit_rel.children[0].memberElement.dump()
|
|
982
|
+
elif hasattr(unit_rel, 'dump'):
|
|
983
|
+
unit_name = unit_rel.dump()
|
|
984
|
+
if unit_name:
|
|
985
|
+
if base_name == "LiteralInteger":
|
|
986
|
+
return int(base.dump()) * ureg(unit_name)
|
|
987
|
+
elif base_name == "LiteralReal":
|
|
988
|
+
return float(base.dump()) * ureg(unit_name)
|
|
989
|
+
|
|
990
|
+
base_dump = base.dump()
|
|
991
|
+
|
|
992
|
+
if base_name == "LiteralString":
|
|
993
|
+
return base_dump.strip('"')
|
|
994
|
+
elif base_name == "LiteralInteger":
|
|
995
|
+
return int(base_dump)
|
|
996
|
+
elif base_name == "LiteralReal":
|
|
997
|
+
return float(base_dump)
|
|
998
|
+
elif base_name in ("LiteralTrue", "LiteralFalse"):
|
|
999
|
+
return base_name == "LiteralTrue"
|
|
1000
|
+
elif base_name == "LiteralNull":
|
|
1001
|
+
return None
|
|
1002
|
+
elif base_name == "FeatureReferenceExpression":
|
|
1003
|
+
return base_dump
|
|
1004
|
+
else:
|
|
1005
|
+
return base_dump
|
|
1006
|
+
|
|
1007
|
+
|
|
1008
|
+
class Part(Usage):
|
|
1009
|
+
sysml_type = 'part'
|
|
1010
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
1011
|
+
Usage.__init__(self)
|
|
1012
|
+
if definition:
|
|
1013
|
+
self.grammar = PartDefinition()
|
|
1014
|
+
else:
|
|
1015
|
+
self.grammar = PartUsage()
|
|
1016
|
+
|
|
1017
|
+
if name is not None:
|
|
1018
|
+
self._set_name(name)
|
|
1019
|
+
if shortname is not None:
|
|
1020
|
+
self._set_name(shortname, short=True)
|
|
1021
|
+
|
|
1022
|
+
|
|
1023
|
+
class Item(Usage):
|
|
1024
|
+
sysml_type = 'item'
|
|
1025
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
1026
|
+
Usage.__init__(self)
|
|
1027
|
+
if definition:
|
|
1028
|
+
self.grammar = ItemDefinition()
|
|
1029
|
+
else:
|
|
1030
|
+
self.grammar = ItemUsage()
|
|
1031
|
+
|
|
1032
|
+
if name is not None:
|
|
1033
|
+
self._set_name(name)
|
|
1034
|
+
if shortname is not None:
|
|
1035
|
+
self._set_name(shortname, short=True)
|
|
1036
|
+
|
|
1037
|
+
|
|
1038
|
+
class Port(Usage):
|
|
1039
|
+
sysml_type = 'port'
|
|
1040
|
+
def __init__(self, definition=False, name=None, shortname=None, conjugated=False):
|
|
1041
|
+
Usage.__init__(self)
|
|
1042
|
+
if definition:
|
|
1043
|
+
self.grammar = PortDefinition()
|
|
1044
|
+
else:
|
|
1045
|
+
self.grammar = PortUsage()
|
|
1046
|
+
|
|
1047
|
+
self.is_definition = definition
|
|
1048
|
+
self.conjugated = conjugated
|
|
1049
|
+
self.port_attributes = [] # list of (name, type_name)
|
|
1050
|
+
self.port_in_items = [] # list of (name, type_name)
|
|
1051
|
+
self.port_out_items = [] # list of (name, type_name)
|
|
1052
|
+
self.port_inout_items = [] # list of (name, type_name)
|
|
1053
|
+
|
|
1054
|
+
if name is not None:
|
|
1055
|
+
self._set_name(name)
|
|
1056
|
+
if shortname is not None:
|
|
1057
|
+
self._set_name(shortname, short=True)
|
|
1058
|
+
|
|
1059
|
+
def add_attribute(self, name, type_name=None):
|
|
1060
|
+
"""Add an attribute to the port definition.
|
|
1061
|
+
|
|
1062
|
+
Args:
|
|
1063
|
+
name: Attribute name
|
|
1064
|
+
type_name: Optional type
|
|
1065
|
+
"""
|
|
1066
|
+
self.port_attributes.append((name, type_name))
|
|
1067
|
+
return self
|
|
1068
|
+
|
|
1069
|
+
def add_in_item(self, name, type_name=None):
|
|
1070
|
+
"""Add an input item to the port definition.
|
|
1071
|
+
|
|
1072
|
+
Args:
|
|
1073
|
+
name: Item name
|
|
1074
|
+
type_name: Optional type
|
|
1075
|
+
"""
|
|
1076
|
+
self.port_in_items.append((name, type_name))
|
|
1077
|
+
return self
|
|
1078
|
+
|
|
1079
|
+
def add_out_item(self, name, type_name=None):
|
|
1080
|
+
"""Add an output item to the port definition.
|
|
1081
|
+
|
|
1082
|
+
Args:
|
|
1083
|
+
name: Item name
|
|
1084
|
+
type_name: Optional type
|
|
1085
|
+
"""
|
|
1086
|
+
self.port_out_items.append((name, type_name))
|
|
1087
|
+
return self
|
|
1088
|
+
|
|
1089
|
+
def add_inout_item(self, name, type_name=None):
|
|
1090
|
+
"""Add an inout item to the port definition.
|
|
1091
|
+
|
|
1092
|
+
Args:
|
|
1093
|
+
name: Item name
|
|
1094
|
+
type_name: Optional type
|
|
1095
|
+
"""
|
|
1096
|
+
self.port_inout_items.append((name, type_name))
|
|
1097
|
+
return self
|
|
1098
|
+
|
|
1099
|
+
def dump(self, child=None):
|
|
1100
|
+
# Check if we have enhanced features
|
|
1101
|
+
has_port_features = (
|
|
1102
|
+
self.port_attributes or self.port_in_items
|
|
1103
|
+
or self.port_out_items or self.port_inout_items
|
|
1104
|
+
)
|
|
1105
|
+
|
|
1106
|
+
if not has_port_features:
|
|
1107
|
+
# Use standard grammar dump for basic ports
|
|
1108
|
+
return classtree(self._get_definition(child)).dump()
|
|
1109
|
+
|
|
1110
|
+
# Enhanced dump with in/out items
|
|
1111
|
+
keyword = "port def" if self.is_definition else "port"
|
|
1112
|
+
name_str = getattr(self, 'name', "") or ""
|
|
1113
|
+
|
|
1114
|
+
body_items = []
|
|
1115
|
+
for attr_name, attr_type in self.port_attributes:
|
|
1116
|
+
if attr_type:
|
|
1117
|
+
body_items.append(f"attribute {attr_name} : {attr_type}")
|
|
1118
|
+
else:
|
|
1119
|
+
body_items.append(f"attribute {attr_name}")
|
|
1120
|
+
|
|
1121
|
+
for item_name, item_type in self.port_out_items:
|
|
1122
|
+
if item_type:
|
|
1123
|
+
body_items.append(f"out item {item_name} : {item_type}")
|
|
1124
|
+
else:
|
|
1125
|
+
body_items.append(f"out item {item_name}")
|
|
1126
|
+
|
|
1127
|
+
for item_name, item_type in self.port_in_items:
|
|
1128
|
+
if item_type:
|
|
1129
|
+
body_items.append(f"in item {item_name} : {item_type}")
|
|
1130
|
+
else:
|
|
1131
|
+
body_items.append(f"in item {item_name}")
|
|
1132
|
+
|
|
1133
|
+
for item_name, item_type in self.port_inout_items:
|
|
1134
|
+
if item_type:
|
|
1135
|
+
body_items.append(f"inout item {item_name} : {item_type}")
|
|
1136
|
+
else:
|
|
1137
|
+
body_items.append(f"inout item {item_name}")
|
|
1138
|
+
|
|
1139
|
+
return f"{keyword} {name_str} {{\n " + ";\n ".join(body_items) + ";\n}"
|
|
1140
|
+
|
|
1141
|
+
|
|
1142
|
+
class Interface(Usage):
|
|
1143
|
+
sysml_type = 'interface'
|
|
1144
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
1145
|
+
self.is_definition = definition
|
|
1146
|
+
self.name = name if name else str(uuidlib.uuid4())
|
|
1147
|
+
self.children = []
|
|
1148
|
+
self.typedby = None
|
|
1149
|
+
self.parent = None
|
|
1150
|
+
self.grammar = True
|
|
1151
|
+
self.iface_shortname = shortname
|
|
1152
|
+
self.ends = [] # list of (name, type_name, multiplicity, children)
|
|
1153
|
+
self.connections = [] # list of (from_path, to_path)
|
|
1154
|
+
|
|
1155
|
+
if definition:
|
|
1156
|
+
self.keyword = "interface def"
|
|
1157
|
+
else:
|
|
1158
|
+
self.keyword = "interface"
|
|
1159
|
+
|
|
1160
|
+
def add_end(self, name, type_name=None, multiplicity=None):
|
|
1161
|
+
"""Add an end to the interface definition.
|
|
1162
|
+
|
|
1163
|
+
Args:
|
|
1164
|
+
name: End name
|
|
1165
|
+
type_name: Optional type (e.g., 'FuelOutPort')
|
|
1166
|
+
multiplicity: Optional multiplicity (e.g., '1', '1..*')
|
|
1167
|
+
"""
|
|
1168
|
+
self.ends.append((name, type_name, multiplicity))
|
|
1169
|
+
return self
|
|
1170
|
+
|
|
1171
|
+
def add_connection(self, from_path, to_path):
|
|
1172
|
+
"""Add a connection between ends.
|
|
1173
|
+
|
|
1174
|
+
Args:
|
|
1175
|
+
from_path: Source path (e.g., 'suppliedBy.hot')
|
|
1176
|
+
to_path: Target path (e.g., 'deliveredTo.hot')
|
|
1177
|
+
"""
|
|
1178
|
+
self.connections.append((from_path, to_path))
|
|
1179
|
+
return self
|
|
1180
|
+
|
|
1181
|
+
def _set_typed_by(self, typed):
|
|
1182
|
+
"""Set typing (`:`) for interface usage."""
|
|
1183
|
+
self._typed_by_name = typed.name if hasattr(typed, 'name') else str(typed)
|
|
1184
|
+
return self
|
|
1185
|
+
|
|
1186
|
+
def _set_specializes(self, *parents):
|
|
1187
|
+
"""Set specialization (`:>`) for interface definitions."""
|
|
1188
|
+
self._specializes_names = [
|
|
1189
|
+
p.name if hasattr(p, 'name') else str(p) for p in parents
|
|
1190
|
+
]
|
|
1191
|
+
return self
|
|
1192
|
+
|
|
1193
|
+
def dump(self):
|
|
1194
|
+
name_str = getattr(self, 'name', "") or ""
|
|
1195
|
+
keyword = getattr(self, 'keyword', 'interface')
|
|
1196
|
+
|
|
1197
|
+
# Build type/specialization suffix
|
|
1198
|
+
type_suffix = ""
|
|
1199
|
+
if hasattr(self, '_typed_by_name') and self._typed_by_name:
|
|
1200
|
+
type_suffix = f" : {self._typed_by_name}"
|
|
1201
|
+
elif hasattr(self, '_specializes_names') and self._specializes_names:
|
|
1202
|
+
type_suffix = " :> " + ", ".join(self._specializes_names)
|
|
1203
|
+
|
|
1204
|
+
body_items = []
|
|
1205
|
+
|
|
1206
|
+
for end_name, end_type, end_mult in self.ends:
|
|
1207
|
+
mult_str = f"[{end_mult}]" if end_mult else ""
|
|
1208
|
+
if end_type:
|
|
1209
|
+
body_items.append(f"end {end_name} : {end_type}{mult_str};")
|
|
1210
|
+
else:
|
|
1211
|
+
body_items.append(f"end {end_name}{mult_str};")
|
|
1212
|
+
|
|
1213
|
+
for from_path, to_path in self.connections:
|
|
1214
|
+
body_items.append(f"connect {from_path} to {to_path};")
|
|
1215
|
+
|
|
1216
|
+
if body_items:
|
|
1217
|
+
body = " {\n " + "\n ".join(body_items) + "\n}"
|
|
1218
|
+
return f"{keyword} {name_str}{type_suffix}{body}"
|
|
1219
|
+
else:
|
|
1220
|
+
return f"{keyword} {name_str}{type_suffix};"
|
|
1221
|
+
|
|
1222
|
+
|
|
1223
|
+
class Action(Usage):
|
|
1224
|
+
sysml_type = 'action'
|
|
1225
|
+
def __init__(self, definition=False, name=None, shortname=None, grammar=None):
|
|
1226
|
+
# If grammar is provided (from load_from_grammar), use it
|
|
1227
|
+
if grammar is not None:
|
|
1228
|
+
self.grammar = grammar
|
|
1229
|
+
else:
|
|
1230
|
+
# Initialize grammar properly (like Part does)
|
|
1231
|
+
if definition:
|
|
1232
|
+
self.grammar = ActionDefinition()
|
|
1233
|
+
self.grammar.declaration.identification.declaredName = name if name else None
|
|
1234
|
+
else:
|
|
1235
|
+
self.grammar = ActionUsage(None)
|
|
1236
|
+
if self.grammar.declaration and hasattr(self.grammar.declaration, 'declaration') and self.grammar.declaration.declaration:
|
|
1237
|
+
if hasattr(self.grammar.declaration.declaration, 'identification') and self.grammar.declaration.declaration.identification:
|
|
1238
|
+
self.grammar.declaration.declaration.identification.declaredName = name if name else None
|
|
1239
|
+
|
|
1240
|
+
self.is_definition = definition
|
|
1241
|
+
self.action_shortname = shortname
|
|
1242
|
+
self.name = name if name else str(uuidlib.uuid4())
|
|
1243
|
+
self.children = []
|
|
1244
|
+
self.typedby = None
|
|
1245
|
+
self.parent = None
|
|
1246
|
+
self.action_inputs = [] # List of (name, type_name)
|
|
1247
|
+
self.action_outputs = []
|
|
1248
|
+
|
|
1249
|
+
if definition:
|
|
1250
|
+
self.keyword = "action def"
|
|
1251
|
+
else:
|
|
1252
|
+
self.keyword = "action"
|
|
1253
|
+
|
|
1254
|
+
def add_input(self, name, type_name=None):
|
|
1255
|
+
"""Add an input parameter (in) to the action.
|
|
1256
|
+
|
|
1257
|
+
Args:
|
|
1258
|
+
name: Name of the input
|
|
1259
|
+
type_name: Optional type (e.g., 'Scene')
|
|
1260
|
+
"""
|
|
1261
|
+
self.action_inputs.append((name, type_name))
|
|
1262
|
+
return self
|
|
1263
|
+
|
|
1264
|
+
def add_output(self, name, type_name=None):
|
|
1265
|
+
"""Add an output parameter (out) to the action.
|
|
1266
|
+
|
|
1267
|
+
Args:
|
|
1268
|
+
name: Name of the output
|
|
1269
|
+
type_name: Optional type (e.g., 'Image')
|
|
1270
|
+
"""
|
|
1271
|
+
self.action_outputs.append((name, type_name))
|
|
1272
|
+
return self
|
|
1273
|
+
|
|
1274
|
+
def _get_definition(self, child=None):
|
|
1275
|
+
if self.is_definition:
|
|
1276
|
+
keyword = "action def"
|
|
1277
|
+
else:
|
|
1278
|
+
keyword = "action"
|
|
1279
|
+
|
|
1280
|
+
decl = {
|
|
1281
|
+
"name": "UsageDeclaration",
|
|
1282
|
+
"identification": {
|
|
1283
|
+
"name": "Identification",
|
|
1284
|
+
"declaredName": self.name if self.name else "",
|
|
1285
|
+
"declaredShortName": None
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
# Build action body with in/out parameters
|
|
1290
|
+
body_items = []
|
|
1291
|
+
|
|
1292
|
+
# Add inputs
|
|
1293
|
+
for inp_name, inp_type in self.action_inputs:
|
|
1294
|
+
if inp_type:
|
|
1295
|
+
item = f"in {inp_name} : {inp_type};"
|
|
1296
|
+
else:
|
|
1297
|
+
item = f"in {inp_name};"
|
|
1298
|
+
body_items.append(item)
|
|
1299
|
+
|
|
1300
|
+
# Add outputs
|
|
1301
|
+
for out_name, out_type in self.action_outputs:
|
|
1302
|
+
if out_type:
|
|
1303
|
+
item = f"out {out_name} : {out_type};"
|
|
1304
|
+
else:
|
|
1305
|
+
item = f"out {out_name};"
|
|
1306
|
+
body_items.append(item)
|
|
1307
|
+
|
|
1308
|
+
body = {"name": "ActionBody", "items": body_items}
|
|
1309
|
+
|
|
1310
|
+
if self.is_definition:
|
|
1311
|
+
grammar_type = "ActionDefinition"
|
|
1312
|
+
else:
|
|
1313
|
+
grammar_type = "ActionUsage"
|
|
1314
|
+
|
|
1315
|
+
return {
|
|
1316
|
+
"name": grammar_type,
|
|
1317
|
+
"declaration": decl,
|
|
1318
|
+
"body": body
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
def load_from_grammar(self, grammar):
|
|
1322
|
+
# Set the grammar
|
|
1323
|
+
self.grammar = grammar
|
|
1324
|
+
|
|
1325
|
+
self.is_definition = False
|
|
1326
|
+
self.action_inputs = []
|
|
1327
|
+
self.action_outputs = []
|
|
1328
|
+
self._nested_actions = []
|
|
1329
|
+
|
|
1330
|
+
# Check for 'declaration' directly (for definitions like ActionDefinition, RequirementDefinition)
|
|
1331
|
+
decl = getattr(grammar, 'declaration', None)
|
|
1332
|
+
if decl and hasattr(decl, 'identification') and decl.identification:
|
|
1333
|
+
self.name = decl.identification.declaredName
|
|
1334
|
+
self.is_definition = True
|
|
1335
|
+
self.keyword = "action def"
|
|
1336
|
+
elif hasattr(grammar, 'declaration') and grammar.declaration:
|
|
1337
|
+
# Handle nested declaration structure (ActionUsageDeclaration -> UsageDeclaration -> FeatureDeclaration)
|
|
1338
|
+
decl = getattr(grammar.declaration, 'declaration', None)
|
|
1339
|
+
if decl:
|
|
1340
|
+
# Try nested: declaration.declaration.declaration.identification (for ANTLR)
|
|
1341
|
+
nested_decl = getattr(decl, 'declaration', None)
|
|
1342
|
+
if nested_decl and hasattr(nested_decl, 'identification') and nested_decl.identification:
|
|
1343
|
+
self.name = nested_decl.identification.declaredName
|
|
1344
|
+
self.is_definition = False
|
|
1345
|
+
self.keyword = "action"
|
|
1346
|
+
elif hasattr(decl, 'identification') and decl.identification:
|
|
1347
|
+
self.name = decl.identification.declaredName
|
|
1348
|
+
self.is_definition = False
|
|
1349
|
+
self.keyword = "action"
|
|
1350
|
+
|
|
1351
|
+
# Extract parameters and nested actions from body
|
|
1352
|
+
body = getattr(grammar, 'body', None)
|
|
1353
|
+
if body and hasattr(body, 'children'):
|
|
1354
|
+
for item in body.children:
|
|
1355
|
+
if hasattr(item, 'children'):
|
|
1356
|
+
for child in item.children:
|
|
1357
|
+
child_name = child.__class__.__name__
|
|
1358
|
+
# Extract in/out parameters from NonOccurrenceUsageMember -> DefaultReferenceUsage
|
|
1359
|
+
if child_name == "NonOccurrenceUsageMember":
|
|
1360
|
+
self._extract_parameter_from_non_occurrence(child)
|
|
1361
|
+
elif child_name == "BehaviorUsageMember":
|
|
1362
|
+
self._extract_behavior_usage(child)
|
|
1363
|
+
elif child_name == "ActionNodeMember":
|
|
1364
|
+
self._extract_nested_action(child)
|
|
1365
|
+
|
|
1366
|
+
return self
|
|
1367
|
+
|
|
1368
|
+
def _extract_parameter_from_non_occurrence(self, non_occ_member):
|
|
1369
|
+
"""Extract in/out parameter from NonOccurrenceUsageMember -> NonOccurrenceUsageElement -> DefaultReferenceUsage."""
|
|
1370
|
+
if hasattr(non_occ_member, 'children'):
|
|
1371
|
+
children = non_occ_member.children
|
|
1372
|
+
if not isinstance(children, list):
|
|
1373
|
+
children = [children]
|
|
1374
|
+
for elem in children:
|
|
1375
|
+
# elem is NonOccurrenceUsageElement
|
|
1376
|
+
if hasattr(elem, 'children'):
|
|
1377
|
+
# elem.children is DefaultReferenceUsage (not a list)
|
|
1378
|
+
usage = elem.children
|
|
1379
|
+
if isinstance(usage, list):
|
|
1380
|
+
usage = usage[0] if usage else None
|
|
1381
|
+
if usage and hasattr(usage, 'declaration') and usage.declaration:
|
|
1382
|
+
# UsageDeclaration has a 'declaration' attribute which is FeatureDeclaration
|
|
1383
|
+
usage_decl = usage.declaration
|
|
1384
|
+
if hasattr(usage_decl, 'declaration') and usage_decl.declaration:
|
|
1385
|
+
feat_decl = usage_decl.declaration
|
|
1386
|
+
if hasattr(feat_decl, 'identification') and feat_decl.identification:
|
|
1387
|
+
name = feat_decl.identification.declaredName
|
|
1388
|
+
# Extract direction from prefix (RefPrefix has direction directly)
|
|
1389
|
+
direction = None
|
|
1390
|
+
if hasattr(usage, 'prefix') and usage.prefix:
|
|
1391
|
+
prefix = usage.prefix
|
|
1392
|
+
# RefPrefix has direction directly
|
|
1393
|
+
if hasattr(prefix, 'direction') and prefix.direction:
|
|
1394
|
+
dir_obj = prefix.direction
|
|
1395
|
+
if hasattr(dir_obj, 'isIn') and dir_obj.isIn:
|
|
1396
|
+
direction = 'in'
|
|
1397
|
+
elif hasattr(dir_obj, 'isOut') and dir_obj.isOut:
|
|
1398
|
+
direction = 'out'
|
|
1399
|
+
# OccurrenceUsagePrefix has nested prefix
|
|
1400
|
+
elif hasattr(prefix, 'prefix') and prefix.prefix:
|
|
1401
|
+
inner_prefix = prefix.prefix
|
|
1402
|
+
if hasattr(inner_prefix, 'direction') and inner_prefix.direction:
|
|
1403
|
+
dir_obj = inner_prefix.direction
|
|
1404
|
+
if hasattr(dir_obj, 'isIn') and dir_obj.isIn:
|
|
1405
|
+
direction = 'in'
|
|
1406
|
+
elif hasattr(dir_obj, 'isOut') and dir_obj.isOut:
|
|
1407
|
+
direction = 'out'
|
|
1408
|
+
# Extract type from specialization
|
|
1409
|
+
type_name = None
|
|
1410
|
+
if hasattr(feat_decl, 'specialization') and feat_decl.specialization:
|
|
1411
|
+
for spec in feat_decl.specialization.specializations:
|
|
1412
|
+
if hasattr(spec, 'relationship') and spec.relationship:
|
|
1413
|
+
rel = spec.relationship
|
|
1414
|
+
type_name = self._extract_type_from_typings(rel)
|
|
1415
|
+
if direction == 'in' and name:
|
|
1416
|
+
self.action_inputs.append((name, type_name))
|
|
1417
|
+
elif direction == 'out' and name:
|
|
1418
|
+
self.action_outputs.append((name, type_name))
|
|
1419
|
+
|
|
1420
|
+
def _extract_type_from_typings(self, rel):
|
|
1421
|
+
"""Extract type name from a Typings relationship."""
|
|
1422
|
+
if not hasattr(rel, 'typing') or not rel.typing:
|
|
1423
|
+
return None
|
|
1424
|
+
|
|
1425
|
+
typing = rel.typing
|
|
1426
|
+
|
|
1427
|
+
# Direct type attribute (simple case)
|
|
1428
|
+
if hasattr(typing, 'type') and typing.type:
|
|
1429
|
+
return typing.type.dump()
|
|
1430
|
+
|
|
1431
|
+
# TypedBy case: typing.relationships -> FeatureTyping -> relationship -> OwnedFeatureTyping -> type
|
|
1432
|
+
if hasattr(typing, 'relationships') and typing.relationships:
|
|
1433
|
+
for ft in typing.relationships:
|
|
1434
|
+
if hasattr(ft, 'relationship') and ft.relationship:
|
|
1435
|
+
owned = ft.relationship
|
|
1436
|
+
if hasattr(owned, 'type') and owned.type:
|
|
1437
|
+
return owned.type.dump()
|
|
1438
|
+
|
|
1439
|
+
return None
|
|
1440
|
+
|
|
1441
|
+
def _extract_nested_action(self, action_node_member):
|
|
1442
|
+
"""Extract nested action from ActionNodeMember."""
|
|
1443
|
+
if hasattr(action_node_member, 'children'):
|
|
1444
|
+
node = action_node_member.children
|
|
1445
|
+
if hasattr(node, 'children'):
|
|
1446
|
+
action_node = node.children
|
|
1447
|
+
if hasattr(action_node, 'declaration'):
|
|
1448
|
+
decl = action_node.declaration
|
|
1449
|
+
if hasattr(decl, 'identification') and decl.identification:
|
|
1450
|
+
name = decl.identification.declaredName
|
|
1451
|
+
if name:
|
|
1452
|
+
nested_action = Action(name=name)
|
|
1453
|
+
nested_action.load_from_grammar(action_node)
|
|
1454
|
+
self._nested_actions.append(nested_action)
|
|
1455
|
+
self.children.append(nested_action)
|
|
1456
|
+
|
|
1457
|
+
def _extract_behavior_usage(self, behavior_usage_member):
|
|
1458
|
+
"""Extract behavior usage (nested action/state) from BehaviorUsageMember."""
|
|
1459
|
+
if hasattr(behavior_usage_member, 'children'):
|
|
1460
|
+
for child in behavior_usage_member.children:
|
|
1461
|
+
if hasattr(child, 'children'):
|
|
1462
|
+
# child is BehaviorUsageElement, its children contain the actual usage
|
|
1463
|
+
behavior_element = child.children
|
|
1464
|
+
if isinstance(behavior_element, list):
|
|
1465
|
+
usage_list = behavior_element
|
|
1466
|
+
else:
|
|
1467
|
+
usage_list = [behavior_element]
|
|
1468
|
+
for usage in usage_list:
|
|
1469
|
+
if not usage:
|
|
1470
|
+
continue
|
|
1471
|
+
# Check if BehaviorUsageElement has children with the actual usage
|
|
1472
|
+
if hasattr(usage, 'children') and usage.children:
|
|
1473
|
+
inner = usage.children
|
|
1474
|
+
if isinstance(inner, list):
|
|
1475
|
+
inner_list = inner
|
|
1476
|
+
else:
|
|
1477
|
+
inner_list = [inner]
|
|
1478
|
+
for actual_usage in inner_list:
|
|
1479
|
+
if not actual_usage:
|
|
1480
|
+
continue
|
|
1481
|
+
self._process_nested_usage(actual_usage)
|
|
1482
|
+
elif hasattr(usage, 'declaration'):
|
|
1483
|
+
self._process_nested_usage(usage)
|
|
1484
|
+
|
|
1485
|
+
def _process_nested_usage(self, usage):
|
|
1486
|
+
"""Process a nested usage element (ActionUsage, StateUsage, etc.)."""
|
|
1487
|
+
usage_type = usage.__class__.__name__
|
|
1488
|
+
|
|
1489
|
+
# Get name from declaration
|
|
1490
|
+
name = None
|
|
1491
|
+
if hasattr(usage, 'declaration') and usage.declaration:
|
|
1492
|
+
decl = usage.declaration
|
|
1493
|
+
# Handle nested declaration structure
|
|
1494
|
+
while hasattr(decl, 'declaration') and not hasattr(decl, 'identification'):
|
|
1495
|
+
decl = decl.declaration
|
|
1496
|
+
if hasattr(decl, 'identification') and decl.identification:
|
|
1497
|
+
name = decl.identification.declaredName
|
|
1498
|
+
|
|
1499
|
+
if not name:
|
|
1500
|
+
return
|
|
1501
|
+
|
|
1502
|
+
if 'Action' in usage_type:
|
|
1503
|
+
nested_action = Action(name=name)
|
|
1504
|
+
nested_action.parent = self
|
|
1505
|
+
nested_action.load_from_grammar(usage)
|
|
1506
|
+
self._nested_actions.append(nested_action)
|
|
1507
|
+
self.children.append(nested_action)
|
|
1508
|
+
|
|
1509
|
+
def _get_definition(self, child=None):
|
|
1510
|
+
# Sync self.name to grammar before getting definition
|
|
1511
|
+
if hasattr(self.grammar, 'declaration') and hasattr(self.grammar.declaration, 'identification'):
|
|
1512
|
+
self.grammar.declaration.identification.declaredName = self.name
|
|
1513
|
+
|
|
1514
|
+
# Get the grammar's get_definition output
|
|
1515
|
+
if hasattr(self.grammar, 'get_definition'):
|
|
1516
|
+
grammar_def = self.grammar.get_definition()
|
|
1517
|
+
else:
|
|
1518
|
+
# Fallback - shouldn't happen now
|
|
1519
|
+
grammar_def = {"name": "ActionDefinition", "declaration": {}, "body": {}}
|
|
1520
|
+
|
|
1521
|
+
if self.is_definition:
|
|
1522
|
+
package = {
|
|
1523
|
+
"name": "DefinitionElement",
|
|
1524
|
+
"ownedRelatedElement": grammar_def,
|
|
1525
|
+
}
|
|
1526
|
+
else:
|
|
1527
|
+
package = {
|
|
1528
|
+
"name": "BehaviorUsageElement",
|
|
1529
|
+
"ownedRelationship": grammar_def,
|
|
1530
|
+
}
|
|
1531
|
+
package = {"name": "OccurrenceUsageElement", "ownedRelatedElement": package}
|
|
1532
|
+
|
|
1533
|
+
if child == "DefinitionBody":
|
|
1534
|
+
if self.is_definition:
|
|
1535
|
+
package = {
|
|
1536
|
+
"name": "DefinitionMember",
|
|
1537
|
+
"prefix": None,
|
|
1538
|
+
"ownedRelatedElement": [package],
|
|
1539
|
+
}
|
|
1540
|
+
else:
|
|
1541
|
+
package = {
|
|
1542
|
+
"name": "OccurrenceUsageMember",
|
|
1543
|
+
"prefix": None,
|
|
1544
|
+
"ownedRelatedElement": [package],
|
|
1545
|
+
}
|
|
1546
|
+
package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]}
|
|
1547
|
+
elif child == "PackageBody" or child == None:
|
|
1548
|
+
if self.is_definition:
|
|
1549
|
+
package = {
|
|
1550
|
+
"name": "PackageMember",
|
|
1551
|
+
"ownedRelatedElement": package,
|
|
1552
|
+
"prefix": None,
|
|
1553
|
+
}
|
|
1554
|
+
else:
|
|
1555
|
+
package = {"name": "UsageElement", "ownedRelatedElement": package}
|
|
1556
|
+
package = {
|
|
1557
|
+
"name": "PackageMember",
|
|
1558
|
+
"ownedRelatedElement": package,
|
|
1559
|
+
"prefix": None,
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
return package
|
|
1563
|
+
|
|
1564
|
+
def dump(self):
|
|
1565
|
+
name_str = getattr(self, 'name', "") or ""
|
|
1566
|
+
keyword = getattr(self, 'keyword', 'action')
|
|
1567
|
+
|
|
1568
|
+
# Build output with in/out parameters
|
|
1569
|
+
parts = [keyword, name_str]
|
|
1570
|
+
|
|
1571
|
+
# Add in/out parameters
|
|
1572
|
+
params = []
|
|
1573
|
+
for inp_name, inp_type in self.action_inputs:
|
|
1574
|
+
if inp_type:
|
|
1575
|
+
params.append(f"in {inp_name} : {inp_type}")
|
|
1576
|
+
else:
|
|
1577
|
+
params.append(f"in {inp_name}")
|
|
1578
|
+
|
|
1579
|
+
for out_name, out_type in self.action_outputs:
|
|
1580
|
+
if out_type:
|
|
1581
|
+
params.append(f"out {out_name} : {out_type}")
|
|
1582
|
+
else:
|
|
1583
|
+
params.append(f"out {out_name}")
|
|
1584
|
+
|
|
1585
|
+
# Build type/specialization suffix
|
|
1586
|
+
type_suffix = ""
|
|
1587
|
+
if hasattr(self, '_typed_by_name') and self._typed_by_name:
|
|
1588
|
+
type_suffix = f" : {self._typed_by_name}"
|
|
1589
|
+
elif hasattr(self, '_specializes_names') and self._specializes_names:
|
|
1590
|
+
type_suffix = " :> " + ", ".join(self._specializes_names)
|
|
1591
|
+
|
|
1592
|
+
if params:
|
|
1593
|
+
return f"{keyword} {name_str}{type_suffix} {{ " + "; ".join(params) + "; }"
|
|
1594
|
+
else:
|
|
1595
|
+
return f"{keyword} {name_str}{type_suffix};"
|
|
1596
|
+
|
|
1597
|
+
def _set_typed_by(self, typed):
|
|
1598
|
+
"""Set typing (`:`) for action usage typed by action definition."""
|
|
1599
|
+
self._typed_by_name = typed.name if hasattr(typed, 'name') else str(typed)
|
|
1600
|
+
return self
|
|
1601
|
+
|
|
1602
|
+
def _set_specializes(self, *parents):
|
|
1603
|
+
"""Set specialization (`:>`) for action definitions."""
|
|
1604
|
+
self._specializes_names = [
|
|
1605
|
+
p.name if hasattr(p, 'name') else str(p) for p in parents
|
|
1606
|
+
]
|
|
1607
|
+
return self
|
|
1608
|
+
|
|
1609
|
+
|
|
1610
|
+
class UseCase(Usage):
|
|
1611
|
+
sysml_type = 'use_case'
|
|
1612
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
1613
|
+
if definition:
|
|
1614
|
+
self.grammar = UseCaseDefinition()
|
|
1615
|
+
self.grammar.declaration.identification.declaredName = name if name else None
|
|
1616
|
+
else:
|
|
1617
|
+
self.grammar = True
|
|
1618
|
+
|
|
1619
|
+
self.is_definition = definition
|
|
1620
|
+
self.name = name if name else str(uuidlib.uuid4())
|
|
1621
|
+
self.children = []
|
|
1622
|
+
self.typedby = None
|
|
1623
|
+
self.parent = None
|
|
1624
|
+
self.subject = None # (name, type_name)
|
|
1625
|
+
self.actors = [] # list of (name, type_name)
|
|
1626
|
+
self.includes = [] # list of use case names
|
|
1627
|
+
|
|
1628
|
+
if definition:
|
|
1629
|
+
self.keyword = "use case def"
|
|
1630
|
+
else:
|
|
1631
|
+
self.keyword = "use case"
|
|
1632
|
+
|
|
1633
|
+
def _get_definition(self, child=None):
|
|
1634
|
+
# Sync name to grammar
|
|
1635
|
+
if hasattr(self.grammar, 'declaration') and hasattr(self.grammar.declaration, 'identification'):
|
|
1636
|
+
self.grammar.declaration.identification.declaredName = self.name
|
|
1637
|
+
|
|
1638
|
+
if hasattr(self.grammar, 'get_definition'):
|
|
1639
|
+
grammar_def = self.grammar.get_definition()
|
|
1640
|
+
else:
|
|
1641
|
+
grammar_def = {"name": "UseCaseDefinition", "declaration": {}, "body": {}}
|
|
1642
|
+
|
|
1643
|
+
package = {
|
|
1644
|
+
"name": "DefinitionElement",
|
|
1645
|
+
"ownedRelatedElement": grammar_def,
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
if child == "DefinitionBody":
|
|
1649
|
+
package = {
|
|
1650
|
+
"name": "DefinitionMember",
|
|
1651
|
+
"prefix": None,
|
|
1652
|
+
"ownedRelatedElement": [package],
|
|
1653
|
+
}
|
|
1654
|
+
package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]}
|
|
1655
|
+
elif child == "PackageBody" or child == None:
|
|
1656
|
+
package = {
|
|
1657
|
+
"name": "PackageMember",
|
|
1658
|
+
"ownedRelatedElement": package,
|
|
1659
|
+
"prefix": None,
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
return package
|
|
1663
|
+
|
|
1664
|
+
def set_subject(self, name, type_name=None):
|
|
1665
|
+
"""Set the subject of the use case.
|
|
1666
|
+
|
|
1667
|
+
Args:
|
|
1668
|
+
name: Name of the subject
|
|
1669
|
+
type_name: Optional type (e.g., 'Vehicle')
|
|
1670
|
+
"""
|
|
1671
|
+
self.subject = (name, type_name)
|
|
1672
|
+
return self
|
|
1673
|
+
|
|
1674
|
+
def add_actor(self, name, type_name=None):
|
|
1675
|
+
"""Add an actor to the use case.
|
|
1676
|
+
|
|
1677
|
+
Args:
|
|
1678
|
+
name: Name of the actor
|
|
1679
|
+
type_name: Optional type (e.g., 'Driver')
|
|
1680
|
+
"""
|
|
1681
|
+
self.actors.append((name, type_name))
|
|
1682
|
+
return self
|
|
1683
|
+
|
|
1684
|
+
def add_include(self, use_case):
|
|
1685
|
+
"""Add an included use case.
|
|
1686
|
+
|
|
1687
|
+
Args:
|
|
1688
|
+
use_case: UseCase object or name string to include
|
|
1689
|
+
"""
|
|
1690
|
+
name = use_case.name if hasattr(use_case, 'name') else str(use_case)
|
|
1691
|
+
self.includes.append(name)
|
|
1692
|
+
return self
|
|
1693
|
+
|
|
1694
|
+
def _set_typed_by(self, typed):
|
|
1695
|
+
"""Set typing (`:`) for use case usage."""
|
|
1696
|
+
self._typed_by_name = typed.name if hasattr(typed, 'name') else str(typed)
|
|
1697
|
+
return self
|
|
1698
|
+
|
|
1699
|
+
def _set_specializes(self, *parents):
|
|
1700
|
+
"""Set specialization (`:>`) for use case definitions."""
|
|
1701
|
+
self._specializes_names = [
|
|
1702
|
+
p.name if hasattr(p, 'name') else str(p) for p in parents
|
|
1703
|
+
]
|
|
1704
|
+
return self
|
|
1705
|
+
|
|
1706
|
+
def dump(self):
|
|
1707
|
+
name_str = getattr(self, 'name', "") or ""
|
|
1708
|
+
keyword = getattr(self, 'keyword', 'use case')
|
|
1709
|
+
|
|
1710
|
+
# Build type/specialization suffix
|
|
1711
|
+
type_suffix = ""
|
|
1712
|
+
if hasattr(self, '_typed_by_name') and self._typed_by_name:
|
|
1713
|
+
type_suffix = f" : {self._typed_by_name}"
|
|
1714
|
+
elif hasattr(self, '_specializes_names') and self._specializes_names:
|
|
1715
|
+
type_suffix = " :> " + ", ".join(self._specializes_names)
|
|
1716
|
+
|
|
1717
|
+
# Build body members
|
|
1718
|
+
body_items = []
|
|
1719
|
+
|
|
1720
|
+
if self.subject:
|
|
1721
|
+
subj_name, subj_type = self.subject
|
|
1722
|
+
if subj_type:
|
|
1723
|
+
body_items.append(f"subject {subj_name} : {subj_type};")
|
|
1724
|
+
else:
|
|
1725
|
+
body_items.append(f"subject {subj_name};")
|
|
1726
|
+
|
|
1727
|
+
for actor_name, actor_type in self.actors:
|
|
1728
|
+
if actor_type:
|
|
1729
|
+
body_items.append(f"actor {actor_name} : {actor_type};")
|
|
1730
|
+
else:
|
|
1731
|
+
body_items.append(f"actor {actor_name};")
|
|
1732
|
+
|
|
1733
|
+
for inc in self.includes:
|
|
1734
|
+
body_items.append(f"include use case {inc};")
|
|
1735
|
+
|
|
1736
|
+
if body_items:
|
|
1737
|
+
body = " {\n " + "\n ".join(body_items) + "\n}"
|
|
1738
|
+
return f"{keyword} {name_str}{type_suffix}{body}"
|
|
1739
|
+
else:
|
|
1740
|
+
return f"{keyword} {name_str}{type_suffix};"
|
|
1741
|
+
|
|
1742
|
+
|
|
1743
|
+
class Requirement(Usage):
|
|
1744
|
+
sysml_type = 'requirement'
|
|
1745
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
1746
|
+
if definition:
|
|
1747
|
+
self.grammar = RequirementDefinition(None)
|
|
1748
|
+
if self.grammar.declaration is not None and hasattr(self.grammar.declaration, 'identification'):
|
|
1749
|
+
self.grammar.declaration.identification.declaredName = name if name else None
|
|
1750
|
+
else:
|
|
1751
|
+
self.grammar = True
|
|
1752
|
+
|
|
1753
|
+
self.is_definition = definition
|
|
1754
|
+
self.name = name if name else str(uuidlib.uuid4())
|
|
1755
|
+
self.children = []
|
|
1756
|
+
self.typedby = None
|
|
1757
|
+
self.parent = None
|
|
1758
|
+
self.req_shortname = shortname
|
|
1759
|
+
self.subject = None
|
|
1760
|
+
self.actors = []
|
|
1761
|
+
self.doc = None
|
|
1762
|
+
self.req_attributes = []
|
|
1763
|
+
self.req_constraints = []
|
|
1764
|
+
self.assume_constraints = []
|
|
1765
|
+
|
|
1766
|
+
if definition:
|
|
1767
|
+
self.keyword = "requirement def"
|
|
1768
|
+
else:
|
|
1769
|
+
self.keyword = "requirement"
|
|
1770
|
+
|
|
1771
|
+
def _get_definition(self, child=None):
|
|
1772
|
+
# Sync name to grammar
|
|
1773
|
+
if hasattr(self.grammar, 'declaration') and hasattr(self.grammar.declaration, 'identification'):
|
|
1774
|
+
self.grammar.declaration.identification.declaredName = self.name
|
|
1775
|
+
|
|
1776
|
+
if hasattr(self.grammar, 'get_definition'):
|
|
1777
|
+
grammar_def = self.grammar.get_definition()
|
|
1778
|
+
else:
|
|
1779
|
+
grammar_def = {"name": "RequirementDefinition", "declaration": {}, "body": {}}
|
|
1780
|
+
|
|
1781
|
+
package = {
|
|
1782
|
+
"name": "DefinitionElement",
|
|
1783
|
+
"ownedRelatedElement": grammar_def,
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
if child == "DefinitionBody":
|
|
1787
|
+
package = {
|
|
1788
|
+
"name": "DefinitionMember",
|
|
1789
|
+
"prefix": None,
|
|
1790
|
+
"ownedRelatedElement": [package],
|
|
1791
|
+
}
|
|
1792
|
+
package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]}
|
|
1793
|
+
elif child == "PackageBody" or child == None:
|
|
1794
|
+
package = {
|
|
1795
|
+
"name": "PackageMember",
|
|
1796
|
+
"ownedRelatedElement": package,
|
|
1797
|
+
"prefix": None,
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
return package
|
|
1801
|
+
|
|
1802
|
+
def set_subject(self, name, type_name=None):
|
|
1803
|
+
"""Set the subject of the requirement.
|
|
1804
|
+
|
|
1805
|
+
Args:
|
|
1806
|
+
name: Name of the subject
|
|
1807
|
+
type_name: Optional type (e.g., 'Vehicle')
|
|
1808
|
+
"""
|
|
1809
|
+
self.subject = (name, type_name)
|
|
1810
|
+
return self
|
|
1811
|
+
|
|
1812
|
+
def add_actor(self, name, type_name=None):
|
|
1813
|
+
"""Add an actor to the requirement.
|
|
1814
|
+
|
|
1815
|
+
Args:
|
|
1816
|
+
name: Name of the actor
|
|
1817
|
+
type_name: Optional type
|
|
1818
|
+
"""
|
|
1819
|
+
self.actors.append((name, type_name))
|
|
1820
|
+
return self
|
|
1821
|
+
|
|
1822
|
+
def set_doc(self, text):
|
|
1823
|
+
"""Set the documentation string.
|
|
1824
|
+
|
|
1825
|
+
Args:
|
|
1826
|
+
text: Documentation text
|
|
1827
|
+
"""
|
|
1828
|
+
self.doc = text
|
|
1829
|
+
return self
|
|
1830
|
+
|
|
1831
|
+
def add_attribute(self, name, type_name=None):
|
|
1832
|
+
"""Add an attribute to the requirement.
|
|
1833
|
+
|
|
1834
|
+
Args:
|
|
1835
|
+
name: Attribute name
|
|
1836
|
+
type_name: Optional type
|
|
1837
|
+
"""
|
|
1838
|
+
self.req_attributes.append((name, type_name))
|
|
1839
|
+
return self
|
|
1840
|
+
|
|
1841
|
+
def add_constraint(self, expr):
|
|
1842
|
+
"""Add a require constraint expression.
|
|
1843
|
+
|
|
1844
|
+
Args:
|
|
1845
|
+
expr: Constraint expression string (e.g., 'massActual <= massReqd')
|
|
1846
|
+
"""
|
|
1847
|
+
self.req_constraints.append(expr)
|
|
1848
|
+
return self
|
|
1849
|
+
|
|
1850
|
+
def add_assume_constraint(self, expr):
|
|
1851
|
+
"""Add an assume constraint expression.
|
|
1852
|
+
|
|
1853
|
+
Args:
|
|
1854
|
+
expr: Assume constraint expression string
|
|
1855
|
+
"""
|
|
1856
|
+
self.assume_constraints.append(expr)
|
|
1857
|
+
return self
|
|
1858
|
+
|
|
1859
|
+
def _set_typed_by(self, typed):
|
|
1860
|
+
"""Set typing (`:`) for requirement usage."""
|
|
1861
|
+
self._typed_by_name = typed.name if hasattr(typed, 'name') else str(typed)
|
|
1862
|
+
return self
|
|
1863
|
+
|
|
1864
|
+
def _set_specializes(self, *parents):
|
|
1865
|
+
"""Set specialization (`:>`) for requirement definitions."""
|
|
1866
|
+
self._specializes_names = [
|
|
1867
|
+
p.name if hasattr(p, 'name') else str(p) for p in parents
|
|
1868
|
+
]
|
|
1869
|
+
return self
|
|
1870
|
+
|
|
1871
|
+
def dump(self):
|
|
1872
|
+
name_str = getattr(self, 'name', "") or ""
|
|
1873
|
+
keyword = getattr(self, 'keyword', 'requirement')
|
|
1874
|
+
|
|
1875
|
+
# Add shortname
|
|
1876
|
+
shortname_str = ""
|
|
1877
|
+
if self.req_shortname:
|
|
1878
|
+
shortname_str = f" <{self.req_shortname}>"
|
|
1879
|
+
|
|
1880
|
+
# Build type/specialization suffix
|
|
1881
|
+
type_suffix = ""
|
|
1882
|
+
if hasattr(self, '_typed_by_name') and self._typed_by_name:
|
|
1883
|
+
type_suffix = f" : {self._typed_by_name}"
|
|
1884
|
+
elif hasattr(self, '_specializes_names') and self._specializes_names:
|
|
1885
|
+
type_suffix = " :> " + ", ".join(self._specializes_names)
|
|
1886
|
+
|
|
1887
|
+
# Build body members
|
|
1888
|
+
body_items = []
|
|
1889
|
+
|
|
1890
|
+
if self.doc:
|
|
1891
|
+
body_items.append(f"doc /* {self.doc} */")
|
|
1892
|
+
|
|
1893
|
+
if self.subject:
|
|
1894
|
+
subj_name, subj_type = self.subject
|
|
1895
|
+
if subj_type:
|
|
1896
|
+
body_items.append(f"subject {subj_name} : {subj_type};")
|
|
1897
|
+
else:
|
|
1898
|
+
body_items.append(f"subject {subj_name};")
|
|
1899
|
+
|
|
1900
|
+
for actor_name, actor_type in self.actors:
|
|
1901
|
+
if actor_type:
|
|
1902
|
+
body_items.append(f"actor {actor_name} : {actor_type};")
|
|
1903
|
+
else:
|
|
1904
|
+
body_items.append(f"actor {actor_name};")
|
|
1905
|
+
|
|
1906
|
+
for attr_name, attr_type in self.req_attributes:
|
|
1907
|
+
if attr_type:
|
|
1908
|
+
body_items.append(f"attribute {attr_name} : {attr_type};")
|
|
1909
|
+
else:
|
|
1910
|
+
body_items.append(f"attribute {attr_name};")
|
|
1911
|
+
|
|
1912
|
+
for expr in self.req_constraints:
|
|
1913
|
+
body_items.append(f"require constraint {{ {expr} }}")
|
|
1914
|
+
|
|
1915
|
+
for expr in self.assume_constraints:
|
|
1916
|
+
body_items.append(f"assume constraint {{ {expr} }}")
|
|
1917
|
+
|
|
1918
|
+
if body_items:
|
|
1919
|
+
body = " {\n " + "\n ".join(body_items) + "\n}"
|
|
1920
|
+
return f"{keyword}{shortname_str} {name_str}{type_suffix}{body}"
|
|
1921
|
+
else:
|
|
1922
|
+
return f"{keyword}{shortname_str} {name_str}{type_suffix};"
|
|
1923
|
+
|
|
1924
|
+
|
|
1925
|
+
class Message(Usage):
|
|
1926
|
+
sysml_type = 'message'
|
|
1927
|
+
def __init__(self, name=None, from_port=None, to_port=None, of_type=None):
|
|
1928
|
+
"""Create a message.
|
|
1929
|
+
|
|
1930
|
+
Args:
|
|
1931
|
+
name: Optional message name
|
|
1932
|
+
from_port: Source port/part path (e.g., 'sensor')
|
|
1933
|
+
to_port: Target port/part path (e.g., 'controller')
|
|
1934
|
+
of_type: Optional item type (e.g., 'SensorData')
|
|
1935
|
+
"""
|
|
1936
|
+
self.name = name if name else str(uuidlib.uuid4())
|
|
1937
|
+
self.children = []
|
|
1938
|
+
self.typedby = None
|
|
1939
|
+
self.parent = None
|
|
1940
|
+
self.grammar = True
|
|
1941
|
+
self.from_port = from_port
|
|
1942
|
+
self.to_port = to_port
|
|
1943
|
+
self.of_type = of_type
|
|
1944
|
+
|
|
1945
|
+
def set_from(self, from_port):
|
|
1946
|
+
"""Set the source of the message.
|
|
1947
|
+
|
|
1948
|
+
Args:
|
|
1949
|
+
from_port: Source path string or element with .name
|
|
1950
|
+
"""
|
|
1951
|
+
self.from_port = from_port.name if hasattr(from_port, 'name') else str(from_port)
|
|
1952
|
+
return self
|
|
1953
|
+
|
|
1954
|
+
def set_to(self, to_port):
|
|
1955
|
+
"""Set the target of the message.
|
|
1956
|
+
|
|
1957
|
+
Args:
|
|
1958
|
+
to_port: Target path string or element with .name
|
|
1959
|
+
"""
|
|
1960
|
+
self.to_port = to_port.name if hasattr(to_port, 'name') else str(to_port)
|
|
1961
|
+
return self
|
|
1962
|
+
|
|
1963
|
+
def set_of(self, of_type):
|
|
1964
|
+
"""Set the item type of the message.
|
|
1965
|
+
|
|
1966
|
+
Args:
|
|
1967
|
+
of_type: Item type string or element with .name
|
|
1968
|
+
"""
|
|
1969
|
+
self.of_type = of_type.name if hasattr(of_type, 'name') else str(of_type)
|
|
1970
|
+
return self
|
|
1971
|
+
|
|
1972
|
+
def dump(self):
|
|
1973
|
+
parts = ["message"]
|
|
1974
|
+
|
|
1975
|
+
# Name (if not a UUID)
|
|
1976
|
+
name_str = getattr(self, 'name', "") or ""
|
|
1977
|
+
try:
|
|
1978
|
+
import uuid as _uuid
|
|
1979
|
+
_uuid.UUID(name_str)
|
|
1980
|
+
# It's a UUID - anonymous message, skip name
|
|
1981
|
+
except ValueError:
|
|
1982
|
+
parts.append(name_str)
|
|
1983
|
+
|
|
1984
|
+
if self.of_type:
|
|
1985
|
+
parts.append(f"of {self.of_type}")
|
|
1986
|
+
|
|
1987
|
+
if self.from_port and self.to_port:
|
|
1988
|
+
parts.append(f"from {self.from_port} to {self.to_port}")
|
|
1989
|
+
elif self.to_port:
|
|
1990
|
+
parts.append(f"to {self.to_port}")
|
|
1991
|
+
|
|
1992
|
+
return " ".join(parts) + ";"
|
|
1993
|
+
|
|
1994
|
+
|
|
1995
|
+
class _BehaviorUsage(Usage):
|
|
1996
|
+
"""Base class for behavior-style usages (state, action, etc.).
|
|
1997
|
+
|
|
1998
|
+
These get wrapped in BehaviorUsageElement rather than StructureUsageElement.
|
|
1999
|
+
"""
|
|
2000
|
+
# Subclasses should set _is_definition_grammar based on grammar class
|
|
2001
|
+
_is_definition_grammar = False
|
|
2002
|
+
|
|
2003
|
+
def _get_definition(self, child=None):
|
|
2004
|
+
# Determine if this is a definition or usage based on grammar class name
|
|
2005
|
+
grammar_cls_name = type(self.grammar).__name__
|
|
2006
|
+
is_def = grammar_cls_name.endswith('Definition')
|
|
2007
|
+
|
|
2008
|
+
if is_def:
|
|
2009
|
+
package = self.behavior_definition_dump(child)
|
|
2010
|
+
else:
|
|
2011
|
+
package = self.usage_dump(child)
|
|
2012
|
+
|
|
2013
|
+
if child is None:
|
|
2014
|
+
package = {
|
|
2015
|
+
"name": "PackageBodyElement",
|
|
2016
|
+
"ownedRelationship": [package],
|
|
2017
|
+
"prefix": None,
|
|
2018
|
+
}
|
|
2019
|
+
return package
|
|
2020
|
+
|
|
2021
|
+
def usage_dump(self, child):
|
|
2022
|
+
# This is a behavior usage, not a structure usage.
|
|
2023
|
+
package = {
|
|
2024
|
+
"name": "BehaviorUsageElement",
|
|
2025
|
+
"ownedRelationship": self.grammar.get_definition(),
|
|
2026
|
+
}
|
|
2027
|
+
package = {"name": "OccurrenceUsageElement", "ownedRelatedElement": package}
|
|
2028
|
+
|
|
2029
|
+
if child == "DefinitionBody":
|
|
2030
|
+
package = {
|
|
2031
|
+
"name": "OccurrenceUsageMember",
|
|
2032
|
+
"prefix": None,
|
|
2033
|
+
"ownedRelatedElement": [package],
|
|
2034
|
+
}
|
|
2035
|
+
package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]}
|
|
2036
|
+
else:
|
|
2037
|
+
package = {"name": "UsageElement", "ownedRelatedElement": package}
|
|
2038
|
+
package = {
|
|
2039
|
+
"name": "PackageMember",
|
|
2040
|
+
"ownedRelatedElement": package,
|
|
2041
|
+
"prefix": None,
|
|
2042
|
+
}
|
|
2043
|
+
return package
|
|
2044
|
+
|
|
2045
|
+
def behavior_definition_dump(self, child):
|
|
2046
|
+
package = {
|
|
2047
|
+
"name": "DefinitionElement",
|
|
2048
|
+
"ownedRelatedElement": self.grammar.get_definition(),
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
if child == "DefinitionBody":
|
|
2052
|
+
package = {
|
|
2053
|
+
"name": "DefinitionMember",
|
|
2054
|
+
"prefix": None,
|
|
2055
|
+
"ownedRelatedElement": [package],
|
|
2056
|
+
}
|
|
2057
|
+
package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]}
|
|
2058
|
+
else:
|
|
2059
|
+
package = {
|
|
2060
|
+
"name": "PackageMember",
|
|
2061
|
+
"ownedRelatedElement": package,
|
|
2062
|
+
"prefix": None,
|
|
2063
|
+
}
|
|
2064
|
+
return package
|
|
2065
|
+
|
|
2066
|
+
|
|
2067
|
+
class _NonOccurrenceUsage(Usage):
|
|
2068
|
+
"""Base class for non-occurrence usages (attribute, calculation, constraint, etc.).
|
|
2069
|
+
|
|
2070
|
+
These get wrapped in NonOccurrenceUsageElement rather than StructureUsageElement.
|
|
2071
|
+
"""
|
|
2072
|
+
def _get_definition(self, child=None):
|
|
2073
|
+
grammar_cls_name = type(self.grammar).__name__
|
|
2074
|
+
is_def = grammar_cls_name.endswith('Definition')
|
|
2075
|
+
|
|
2076
|
+
if is_def:
|
|
2077
|
+
package = self.nonocc_definition_dump(child)
|
|
2078
|
+
else:
|
|
2079
|
+
package = self.usage_dump(child)
|
|
2080
|
+
|
|
2081
|
+
if child is None:
|
|
2082
|
+
package = {
|
|
2083
|
+
"name": "PackageBodyElement",
|
|
2084
|
+
"ownedRelationship": [package],
|
|
2085
|
+
"prefix": None,
|
|
2086
|
+
}
|
|
2087
|
+
return package
|
|
2088
|
+
|
|
2089
|
+
def usage_dump(self, child):
|
|
2090
|
+
# Add packaging for non-occurrence usage
|
|
2091
|
+
package = {
|
|
2092
|
+
"name": "NonOccurrenceUsageElement",
|
|
2093
|
+
"ownedRelatedElement": self.grammar.get_definition(),
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
if child == "DefinitionBody":
|
|
2097
|
+
package = {
|
|
2098
|
+
"name": "NonOccurrenceUsageMember",
|
|
2099
|
+
"prefix": None,
|
|
2100
|
+
"ownedRelatedElement": [package],
|
|
2101
|
+
}
|
|
2102
|
+
package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]}
|
|
2103
|
+
else:
|
|
2104
|
+
package = {"name": "UsageElement", "ownedRelatedElement": package}
|
|
2105
|
+
package = {
|
|
2106
|
+
"name": "PackageMember",
|
|
2107
|
+
"ownedRelatedElement": package,
|
|
2108
|
+
"prefix": None,
|
|
2109
|
+
}
|
|
2110
|
+
return package
|
|
2111
|
+
|
|
2112
|
+
def nonocc_definition_dump(self, child):
|
|
2113
|
+
package = {
|
|
2114
|
+
"name": "DefinitionElement",
|
|
2115
|
+
"ownedRelatedElement": self.grammar.get_definition(),
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
if child == "DefinitionBody":
|
|
2119
|
+
package = {
|
|
2120
|
+
"name": "DefinitionMember",
|
|
2121
|
+
"prefix": None,
|
|
2122
|
+
"ownedRelatedElement": [package],
|
|
2123
|
+
}
|
|
2124
|
+
package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]}
|
|
2125
|
+
else:
|
|
2126
|
+
package = {
|
|
2127
|
+
"name": "PackageMember",
|
|
2128
|
+
"ownedRelatedElement": package,
|
|
2129
|
+
"prefix": None,
|
|
2130
|
+
}
|
|
2131
|
+
return package
|
|
2132
|
+
|
|
2133
|
+
|
|
2134
|
+
class Transition:
|
|
2135
|
+
"""Represents a state machine transition.
|
|
2136
|
+
|
|
2137
|
+
Attributes:
|
|
2138
|
+
name: Transition name (if any)
|
|
2139
|
+
source: Source state name (for explicit transitions)
|
|
2140
|
+
trigger: Trigger event (accept parameter)
|
|
2141
|
+
guard: Guard condition expression
|
|
2142
|
+
target: Target state name
|
|
2143
|
+
effect: Effect action
|
|
2144
|
+
is_entry: Whether this is an entry transition
|
|
2145
|
+
parent: Parent State element
|
|
2146
|
+
"""
|
|
2147
|
+
def __init__(self):
|
|
2148
|
+
self.name = None
|
|
2149
|
+
self.source = None
|
|
2150
|
+
self.trigger = None
|
|
2151
|
+
self.guard = None
|
|
2152
|
+
self.target = None
|
|
2153
|
+
self.effect = None
|
|
2154
|
+
self.is_entry = False
|
|
2155
|
+
self.grammar = None
|
|
2156
|
+
self.parent = None
|
|
2157
|
+
|
|
2158
|
+
def load_from_grammar(self, grammar, is_entry=False):
|
|
2159
|
+
"""Load transition from grammar element.
|
|
2160
|
+
|
|
2161
|
+
Args:
|
|
2162
|
+
grammar: TargetTransitionUsage, EntryTransitionMember, TransitionUsageMember, or similar
|
|
2163
|
+
is_entry: Whether this is an entry transition
|
|
2164
|
+
"""
|
|
2165
|
+
self.grammar = grammar
|
|
2166
|
+
self.is_entry = is_entry
|
|
2167
|
+
|
|
2168
|
+
if grammar.__class__.__name__ == 'EntryTransitionMember':
|
|
2169
|
+
self.is_entry = True
|
|
2170
|
+
self._load_from_entry_transition(grammar)
|
|
2171
|
+
elif grammar.__class__.__name__ == 'TargetTransitionUsageMember':
|
|
2172
|
+
self._load_from_target_transition(grammar)
|
|
2173
|
+
elif grammar.__class__.__name__ == 'TargetTransitionUsage':
|
|
2174
|
+
self._load_from_target_transition_usage(grammar)
|
|
2175
|
+
elif grammar.__class__.__name__ == 'TransitionUsageMember':
|
|
2176
|
+
self._load_from_transition_usage_member(grammar)
|
|
2177
|
+
|
|
2178
|
+
return self
|
|
2179
|
+
|
|
2180
|
+
def _load_from_transition_usage_member(self, member):
|
|
2181
|
+
"""Load from TransitionUsageMember (explicit `transition name first X then Y;`)."""
|
|
2182
|
+
if hasattr(member, 'children') and member.children:
|
|
2183
|
+
usage = member.children
|
|
2184
|
+
if hasattr(usage, '__class__') and usage.__class__.__name__ == 'TransitionUsage':
|
|
2185
|
+
self._load_from_transition_usage(usage)
|
|
2186
|
+
|
|
2187
|
+
def _load_from_transition_usage(self, usage):
|
|
2188
|
+
"""Load from TransitionUsage."""
|
|
2189
|
+
# Extract name from declaration
|
|
2190
|
+
if hasattr(usage, 'declaration') and usage.declaration:
|
|
2191
|
+
decl = usage.declaration
|
|
2192
|
+
while hasattr(decl, 'declaration') and not hasattr(decl, 'identification'):
|
|
2193
|
+
decl = decl.declaration
|
|
2194
|
+
if hasattr(decl, 'identification') and decl.identification:
|
|
2195
|
+
self.name = decl.identification.declaredName
|
|
2196
|
+
|
|
2197
|
+
# Extract source and target from ownedRelationship
|
|
2198
|
+
if hasattr(usage, 'children'):
|
|
2199
|
+
for child in usage.children:
|
|
2200
|
+
child_name = child.__class__.__name__
|
|
2201
|
+
if child_name == 'TransitionSourceMember':
|
|
2202
|
+
self._extract_source(child)
|
|
2203
|
+
elif child_name == 'TransitionSuccessionMember':
|
|
2204
|
+
self._extract_target(child)
|
|
2205
|
+
elif child_name == 'TriggerActionMember':
|
|
2206
|
+
self._extract_trigger(child)
|
|
2207
|
+
elif child_name == 'GuardExpressionMember':
|
|
2208
|
+
self._extract_guard(child)
|
|
2209
|
+
elif child_name == 'EffectBehaviorMember':
|
|
2210
|
+
self._extract_effect(child)
|
|
2211
|
+
|
|
2212
|
+
def _extract_source(self, source_member):
|
|
2213
|
+
"""Extract source from TransitionSourceMember."""
|
|
2214
|
+
if hasattr(source_member, 'children') and source_member.children:
|
|
2215
|
+
qname = source_member.children
|
|
2216
|
+
if isinstance(qname, list):
|
|
2217
|
+
qname = qname[0]
|
|
2218
|
+
if hasattr(qname, 'names'):
|
|
2219
|
+
self.source = '.'.join(qname.names)
|
|
2220
|
+
|
|
2221
|
+
def _load_from_entry_transition(self, entry_member):
|
|
2222
|
+
"""Load from EntryTransitionMember."""
|
|
2223
|
+
if hasattr(entry_member, 'children') and entry_member.children:
|
|
2224
|
+
child = entry_member.children
|
|
2225
|
+
if child.__class__.__name__ == 'GuardedTargetSuccession':
|
|
2226
|
+
self._load_from_guarded_succession(child)
|
|
2227
|
+
elif child.__class__.__name__ == 'TransitionSuccession':
|
|
2228
|
+
self._extract_target_from_succession(child)
|
|
2229
|
+
|
|
2230
|
+
def _load_from_target_transition(self, target_member):
|
|
2231
|
+
"""Load from TargetTransitionUsageMember."""
|
|
2232
|
+
if hasattr(target_member, 'children') and target_member.children:
|
|
2233
|
+
usage = target_member.children
|
|
2234
|
+
if hasattr(usage, '__class__') and usage.__class__.__name__ == 'TargetTransitionUsage':
|
|
2235
|
+
self._load_from_target_transition_usage(usage)
|
|
2236
|
+
|
|
2237
|
+
def _load_from_target_transition_usage(self, usage):
|
|
2238
|
+
"""Load from TargetTransitionUsage."""
|
|
2239
|
+
if hasattr(usage, 'children'):
|
|
2240
|
+
for child in usage.children:
|
|
2241
|
+
child_name = child.__class__.__name__
|
|
2242
|
+
if child_name == 'TriggerActionMember':
|
|
2243
|
+
self._extract_trigger(child)
|
|
2244
|
+
elif child_name == 'GuardExpressionMember':
|
|
2245
|
+
self._extract_guard(child)
|
|
2246
|
+
elif child_name == 'EffectBehaviorMember':
|
|
2247
|
+
self._extract_effect(child)
|
|
2248
|
+
elif child_name == 'TransitionSuccessionMember':
|
|
2249
|
+
self._extract_target(child)
|
|
2250
|
+
|
|
2251
|
+
def _load_from_guarded_succession(self, guarded):
|
|
2252
|
+
"""Load from GuardedTargetSuccession."""
|
|
2253
|
+
if hasattr(guarded, 'children'):
|
|
2254
|
+
for child in guarded.children:
|
|
2255
|
+
if child.__class__.__name__ == 'GuardExpressionMember':
|
|
2256
|
+
self._extract_guard(child)
|
|
2257
|
+
elif child.__class__.__name__ == 'TransitionSuccessionMember':
|
|
2258
|
+
self._extract_target(child)
|
|
2259
|
+
|
|
2260
|
+
def _extract_trigger(self, trigger_member):
|
|
2261
|
+
"""Extract trigger from TriggerActionMember."""
|
|
2262
|
+
if hasattr(trigger_member, 'children') and trigger_member.children:
|
|
2263
|
+
trigger = trigger_member.children
|
|
2264
|
+
if hasattr(trigger, 'children') and trigger.children:
|
|
2265
|
+
accept_param = trigger.children
|
|
2266
|
+
if hasattr(accept_param, 'children'):
|
|
2267
|
+
for param in accept_param.children:
|
|
2268
|
+
if param.__class__.__name__ == 'PayloadParameterMember':
|
|
2269
|
+
if hasattr(param, 'children') and param.children:
|
|
2270
|
+
payload = param.children
|
|
2271
|
+
# PayloadParameter can have .children (PayloadFeature) or .identification
|
|
2272
|
+
if hasattr(payload, 'children') and payload.children:
|
|
2273
|
+
feat = payload.children
|
|
2274
|
+
if hasattr(feat, 'identification') and feat.identification:
|
|
2275
|
+
self.trigger = feat.identification.declaredName
|
|
2276
|
+
elif hasattr(feat, 'dump'):
|
|
2277
|
+
self.trigger = feat.dump()
|
|
2278
|
+
elif hasattr(payload, 'identification') and payload.identification:
|
|
2279
|
+
self.trigger = payload.identification.declaredName
|
|
2280
|
+
|
|
2281
|
+
def _extract_guard(self, guard_member):
|
|
2282
|
+
"""Extract guard from GuardExpressionMember."""
|
|
2283
|
+
if hasattr(guard_member, 'children') and guard_member.children:
|
|
2284
|
+
self.guard = guard_member.children.dump()
|
|
2285
|
+
|
|
2286
|
+
def _extract_effect(self, effect_member):
|
|
2287
|
+
"""Extract effect from EffectBehaviorMember."""
|
|
2288
|
+
if hasattr(effect_member, 'children') and effect_member.children:
|
|
2289
|
+
effect = effect_member.children
|
|
2290
|
+
if hasattr(effect, 'declaration') and effect.declaration:
|
|
2291
|
+
self.effect = effect.declaration.dump()
|
|
2292
|
+
|
|
2293
|
+
def _extract_target(self, succession_member):
|
|
2294
|
+
"""Extract target from TransitionSuccessionMember."""
|
|
2295
|
+
if hasattr(succession_member, 'children') and succession_member.children:
|
|
2296
|
+
succession = succession_member.children
|
|
2297
|
+
if hasattr(succession, 'children') and succession.children:
|
|
2298
|
+
self._extract_target_from_succession(succession)
|
|
2299
|
+
|
|
2300
|
+
def _extract_target_from_succession(self, succession):
|
|
2301
|
+
"""Extract target from TransitionSuccession."""
|
|
2302
|
+
if hasattr(succession, 'children') and succession.children:
|
|
2303
|
+
connector = succession.children
|
|
2304
|
+
if hasattr(connector, 'children'):
|
|
2305
|
+
target_list = connector.children
|
|
2306
|
+
if isinstance(target_list, list) and target_list:
|
|
2307
|
+
target = target_list[0]
|
|
2308
|
+
if hasattr(target, 'dump'):
|
|
2309
|
+
self.target = target.dump()
|
|
2310
|
+
elif hasattr(target_list, 'dump'):
|
|
2311
|
+
self.target = target_list.dump()
|
|
2312
|
+
|
|
2313
|
+
def __repr__(self):
|
|
2314
|
+
parts = []
|
|
2315
|
+
if self.trigger:
|
|
2316
|
+
parts.append(f"trigger={self.trigger!r}")
|
|
2317
|
+
if self.guard:
|
|
2318
|
+
parts.append(f"guard={self.guard!r}")
|
|
2319
|
+
if self.target:
|
|
2320
|
+
parts.append(f"target={self.target!r}")
|
|
2321
|
+
if self.is_entry:
|
|
2322
|
+
parts.append("entry=True")
|
|
2323
|
+
return f"Transition({', '.join(parts)})"
|
|
2324
|
+
|
|
2325
|
+
|
|
2326
|
+
class State(_BehaviorUsage):
|
|
2327
|
+
sysml_type = 'state'
|
|
2328
|
+
"""SysML v2 State Machine state usage/definition.
|
|
2329
|
+
|
|
2330
|
+
Usage:
|
|
2331
|
+
State() # state ;
|
|
2332
|
+
State(name='Idle') # state Idle;
|
|
2333
|
+
State(definition=True, name='Mode') # state def Mode;
|
|
2334
|
+
"""
|
|
2335
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2336
|
+
Usage.__init__(self)
|
|
2337
|
+
if definition:
|
|
2338
|
+
self.grammar = StateDefinition()
|
|
2339
|
+
else:
|
|
2340
|
+
self.grammar = StateUsage()
|
|
2341
|
+
|
|
2342
|
+
self.transitions = []
|
|
2343
|
+
self.entry_actions = []
|
|
2344
|
+
self.exit_actions = []
|
|
2345
|
+
self.do_actions = []
|
|
2346
|
+
|
|
2347
|
+
if name is not None:
|
|
2348
|
+
self._set_name(name)
|
|
2349
|
+
if shortname is not None:
|
|
2350
|
+
self._set_name(shortname, short=True)
|
|
2351
|
+
|
|
2352
|
+
def load_from_grammar(self, grammar):
|
|
2353
|
+
"""Load state from grammar, extracting nested states, transitions, and actions."""
|
|
2354
|
+
self.grammar = grammar
|
|
2355
|
+
self.children = []
|
|
2356
|
+
self.transitions = []
|
|
2357
|
+
self.entry_actions = []
|
|
2358
|
+
self.exit_actions = []
|
|
2359
|
+
self.do_actions = []
|
|
2360
|
+
|
|
2361
|
+
# Extract name
|
|
2362
|
+
if hasattr(grammar, 'declaration') and grammar.declaration:
|
|
2363
|
+
decl = grammar.declaration
|
|
2364
|
+
# Handle nested declaration structure
|
|
2365
|
+
while hasattr(decl, 'declaration') and not hasattr(decl, 'identification'):
|
|
2366
|
+
decl = decl.declaration
|
|
2367
|
+
if hasattr(decl, 'identification') and decl.identification:
|
|
2368
|
+
self.name = decl.identification.declaredName
|
|
2369
|
+
|
|
2370
|
+
# Extract nested states, transitions, and actions from body
|
|
2371
|
+
# StateDefinition: grammar.body -> StateDefBody -> children -> StateBodyPart -> children -> items
|
|
2372
|
+
# StateUsage: grammar.body -> StateUsageBody -> children -> StateDefBody -> children -> StateBodyPart -> children -> items
|
|
2373
|
+
body = getattr(grammar, 'body', None)
|
|
2374
|
+
if body is None:
|
|
2375
|
+
return self
|
|
2376
|
+
|
|
2377
|
+
# Handle StateUsageBody wrapper (has .children -> StateDefBody)
|
|
2378
|
+
body_type = body.__class__.__name__
|
|
2379
|
+
if body_type == 'StateUsageBody':
|
|
2380
|
+
body = body.children
|
|
2381
|
+
if body is None:
|
|
2382
|
+
return self
|
|
2383
|
+
|
|
2384
|
+
if not hasattr(body, 'children'):
|
|
2385
|
+
return self
|
|
2386
|
+
|
|
2387
|
+
state_body_part = body.children
|
|
2388
|
+
if state_body_part is None:
|
|
2389
|
+
return self
|
|
2390
|
+
|
|
2391
|
+
if hasattr(state_body_part, 'children'):
|
|
2392
|
+
items = state_body_part.children
|
|
2393
|
+
elif isinstance(state_body_part, list):
|
|
2394
|
+
items = state_body_part
|
|
2395
|
+
else:
|
|
2396
|
+
items = []
|
|
2397
|
+
|
|
2398
|
+
if not items:
|
|
2399
|
+
return self
|
|
2400
|
+
|
|
2401
|
+
for item in items:
|
|
2402
|
+
if not hasattr(item, 'children') or not item.children:
|
|
2403
|
+
continue
|
|
2404
|
+
# Each StateBodyItem can have multiple members (e.g., state + transition)
|
|
2405
|
+
for member in item.children:
|
|
2406
|
+
member_name = member.__class__.__name__
|
|
2407
|
+
|
|
2408
|
+
if member_name == 'BehaviorUsageMember':
|
|
2409
|
+
self._extract_state_from_behavior_member(member)
|
|
2410
|
+
elif member_name == 'TargetTransitionUsageMember':
|
|
2411
|
+
self._extract_transition(member)
|
|
2412
|
+
elif member_name == 'EntryTransitionMember':
|
|
2413
|
+
self._extract_entry_transition(member)
|
|
2414
|
+
elif member_name == 'TransitionUsageMember':
|
|
2415
|
+
self._extract_transition(member)
|
|
2416
|
+
elif member_name == 'EntryActionMember':
|
|
2417
|
+
self._extract_entry_action(member)
|
|
2418
|
+
elif member_name == 'ExitActionMember':
|
|
2419
|
+
self._extract_exit_action(member)
|
|
2420
|
+
elif member_name == 'DoActionMember':
|
|
2421
|
+
self._extract_do_action(member)
|
|
2422
|
+
|
|
2423
|
+
return self
|
|
2424
|
+
|
|
2425
|
+
def _extract_state_from_behavior_member(self, behavior_member):
|
|
2426
|
+
"""Extract nested state from BehaviorUsageMember."""
|
|
2427
|
+
if hasattr(behavior_member, 'children'):
|
|
2428
|
+
for child in behavior_member.children:
|
|
2429
|
+
if hasattr(child, 'children'):
|
|
2430
|
+
# child is BehaviorUsageElement, its children is the actual usage (StateUsage, etc.)
|
|
2431
|
+
usage = child.children
|
|
2432
|
+
if not usage:
|
|
2433
|
+
continue
|
|
2434
|
+
|
|
2435
|
+
usage_type = usage.__class__.__name__
|
|
2436
|
+
if usage_type in ('StateUsage', 'StateDefinition'):
|
|
2437
|
+
is_def = usage_type == 'StateDefinition'
|
|
2438
|
+
nested_state = State(definition=is_def)
|
|
2439
|
+
nested_state.parent = self
|
|
2440
|
+
nested_state.load_from_grammar(usage)
|
|
2441
|
+
self.children.append(nested_state)
|
|
2442
|
+
|
|
2443
|
+
def _extract_transition(self, target_member):
|
|
2444
|
+
"""Extract transition from TargetTransitionUsageMember."""
|
|
2445
|
+
transition = Transition()
|
|
2446
|
+
transition.parent = self
|
|
2447
|
+
transition.load_from_grammar(target_member)
|
|
2448
|
+
self.transitions.append(transition)
|
|
2449
|
+
|
|
2450
|
+
def _extract_entry_transition(self, entry_member):
|
|
2451
|
+
"""Extract entry transition from EntryTransitionMember."""
|
|
2452
|
+
transition = Transition()
|
|
2453
|
+
transition.parent = self
|
|
2454
|
+
transition.load_from_grammar(entry_member, is_entry=True)
|
|
2455
|
+
self.transitions.append(transition)
|
|
2456
|
+
|
|
2457
|
+
def _extract_entry_action(self, entry_member):
|
|
2458
|
+
"""Extract entry action from EntryActionMember."""
|
|
2459
|
+
if hasattr(entry_member, 'children') and entry_member.children:
|
|
2460
|
+
action = entry_member.children
|
|
2461
|
+
self.entry_actions.append(action)
|
|
2462
|
+
|
|
2463
|
+
def _extract_exit_action(self, exit_member):
|
|
2464
|
+
"""Extract exit action from ExitActionMember."""
|
|
2465
|
+
if hasattr(exit_member, 'children') and exit_member.children:
|
|
2466
|
+
action = exit_member.children
|
|
2467
|
+
self.exit_actions.append(action)
|
|
2468
|
+
|
|
2469
|
+
def _extract_do_action(self, do_member):
|
|
2470
|
+
"""Extract do action from DoActionMember."""
|
|
2471
|
+
if hasattr(do_member, 'children') and do_member.children:
|
|
2472
|
+
action = do_member.children
|
|
2473
|
+
self.do_actions.append(action)
|
|
2474
|
+
|
|
2475
|
+
|
|
2476
|
+
class Constraint(_NonOccurrenceUsage):
|
|
2477
|
+
sysml_type = 'constraint'
|
|
2478
|
+
"""SysML v2 Constraint usage/definition.
|
|
2479
|
+
|
|
2480
|
+
Usage:
|
|
2481
|
+
Constraint() # constraint ;
|
|
2482
|
+
Constraint(name='PowerLimit') # constraint PowerLimit;
|
|
2483
|
+
Constraint(definition=True, name='Limit') # constraint def Limit;
|
|
2484
|
+
"""
|
|
2485
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2486
|
+
Usage.__init__(self)
|
|
2487
|
+
if definition:
|
|
2488
|
+
self.grammar = ConstraintDefinition()
|
|
2489
|
+
else:
|
|
2490
|
+
self.grammar = ConstraintUsage()
|
|
2491
|
+
|
|
2492
|
+
if name is not None:
|
|
2493
|
+
self._set_name(name)
|
|
2494
|
+
if shortname is not None:
|
|
2495
|
+
self._set_name(shortname, short=True)
|
|
2496
|
+
|
|
2497
|
+
|
|
2498
|
+
class Connection(Usage):
|
|
2499
|
+
sysml_type = 'connection'
|
|
2500
|
+
"""SysML v2 Connection usage/definition.
|
|
2501
|
+
|
|
2502
|
+
Usage:
|
|
2503
|
+
Connection() # connection ;
|
|
2504
|
+
Connection(name='wire') # connection wire;
|
|
2505
|
+
Connection(definition=True, name='DataLink') # connection def DataLink;
|
|
2506
|
+
"""
|
|
2507
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2508
|
+
Usage.__init__(self)
|
|
2509
|
+
if definition:
|
|
2510
|
+
self.grammar = ConnectionDefinition()
|
|
2511
|
+
else:
|
|
2512
|
+
self.grammar = ConnectionUsage()
|
|
2513
|
+
|
|
2514
|
+
if name is not None:
|
|
2515
|
+
self._set_name(name)
|
|
2516
|
+
if shortname is not None:
|
|
2517
|
+
self._set_name(shortname, short=True)
|
|
2518
|
+
|
|
2519
|
+
|
|
2520
|
+
class Flow(Usage):
|
|
2521
|
+
sysml_type = 'flow'
|
|
2522
|
+
"""SysML v2 Flow connection usage/definition.
|
|
2523
|
+
|
|
2524
|
+
Usage:
|
|
2525
|
+
Flow() # flow ;
|
|
2526
|
+
Flow(name='fuelFlow') # flow fuelFlow;
|
|
2527
|
+
Flow(definition=True, name='WaterFlow') # flow def WaterFlow;
|
|
2528
|
+
"""
|
|
2529
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2530
|
+
Usage.__init__(self)
|
|
2531
|
+
if definition:
|
|
2532
|
+
self.grammar = FlowConnectionDefinition()
|
|
2533
|
+
else:
|
|
2534
|
+
self.grammar = FlowConnectionUsage()
|
|
2535
|
+
|
|
2536
|
+
if name is not None:
|
|
2537
|
+
self._set_name(name)
|
|
2538
|
+
if shortname is not None:
|
|
2539
|
+
self._set_name(shortname, short=True)
|
|
2540
|
+
|
|
2541
|
+
|
|
2542
|
+
class Calculation(_NonOccurrenceUsage):
|
|
2543
|
+
sysml_type = 'calculation'
|
|
2544
|
+
"""SysML v2 Calculation usage/definition.
|
|
2545
|
+
|
|
2546
|
+
Usage:
|
|
2547
|
+
Calculation() # calc ;
|
|
2548
|
+
Calculation(name='computeArea') # calc computeArea;
|
|
2549
|
+
Calculation(definition=True, name='Distance') # calc def Distance;
|
|
2550
|
+
"""
|
|
2551
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2552
|
+
Usage.__init__(self)
|
|
2553
|
+
if definition:
|
|
2554
|
+
self.grammar = CalculationDefinition()
|
|
2555
|
+
else:
|
|
2556
|
+
self.grammar = CalculationUsage()
|
|
2557
|
+
|
|
2558
|
+
if name is not None:
|
|
2559
|
+
self._set_name(name)
|
|
2560
|
+
if shortname is not None:
|
|
2561
|
+
self._set_name(shortname, short=True)
|
|
2562
|
+
|
|
2563
|
+
|
|
2564
|
+
class Enumeration(Usage):
|
|
2565
|
+
sysml_type = 'enumeration'
|
|
2566
|
+
"""SysML v2 Enumeration definition.
|
|
2567
|
+
|
|
2568
|
+
Note: SysML v2 only has EnumerationDefinition, no EnumerationUsage.
|
|
2569
|
+
|
|
2570
|
+
Usage:
|
|
2571
|
+
Enumeration(name='Color') # enum def Color;
|
|
2572
|
+
"""
|
|
2573
|
+
def __init__(self, definition=True, name=None, shortname=None):
|
|
2574
|
+
Usage.__init__(self)
|
|
2575
|
+
# EnumerationDefinition is the only form
|
|
2576
|
+
self.grammar = EnumerationDefinition()
|
|
2577
|
+
|
|
2578
|
+
if name is not None:
|
|
2579
|
+
self._set_name(name)
|
|
2580
|
+
if shortname is not None:
|
|
2581
|
+
self._set_name(shortname, short=True)
|
|
2582
|
+
|
|
2583
|
+
|
|
2584
|
+
class Allocation(Usage):
|
|
2585
|
+
sysml_type = 'allocation'
|
|
2586
|
+
"""SysML v2 Allocation usage/definition.
|
|
2587
|
+
|
|
2588
|
+
Allocation represents mapping from one model element to another.
|
|
2589
|
+
|
|
2590
|
+
Usage:
|
|
2591
|
+
Allocation() # allocation ;
|
|
2592
|
+
Allocation(name='alloc1') # allocation alloc1;
|
|
2593
|
+
Allocation(definition=True, name='AllocSpec') # allocation def AllocSpec;
|
|
2594
|
+
"""
|
|
2595
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2596
|
+
Usage.__init__(self)
|
|
2597
|
+
if definition:
|
|
2598
|
+
self.grammar = AllocationDefinition()
|
|
2599
|
+
else:
|
|
2600
|
+
self.grammar = AllocationUsage()
|
|
2601
|
+
|
|
2602
|
+
if name is not None:
|
|
2603
|
+
self._set_name(name)
|
|
2604
|
+
if shortname is not None:
|
|
2605
|
+
self._set_name(shortname, short=True)
|
|
2606
|
+
|
|
2607
|
+
|
|
2608
|
+
class Metadata(_NonOccurrenceUsage):
|
|
2609
|
+
sysml_type = 'metadata'
|
|
2610
|
+
"""SysML v2 Metadata usage/definition.
|
|
2611
|
+
|
|
2612
|
+
Metadata attaches additional information to model elements.
|
|
2613
|
+
|
|
2614
|
+
Usage:
|
|
2615
|
+
Metadata() # metadata ;
|
|
2616
|
+
Metadata(name='tag1') # metadata tag1;
|
|
2617
|
+
Metadata(definition=True, name='AuthorMeta') # metadata def AuthorMeta;
|
|
2618
|
+
"""
|
|
2619
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2620
|
+
Usage.__init__(self)
|
|
2621
|
+
if definition:
|
|
2622
|
+
self.grammar = MetadataDefinition()
|
|
2623
|
+
else:
|
|
2624
|
+
self.grammar = MetadataUsage()
|
|
2625
|
+
|
|
2626
|
+
if name is not None:
|
|
2627
|
+
self._set_name(name)
|
|
2628
|
+
if shortname is not None:
|
|
2629
|
+
self._set_name(shortname, short=True)
|
|
2630
|
+
|
|
2631
|
+
|
|
2632
|
+
class Rendering(Usage):
|
|
2633
|
+
sysml_type = 'rendering'
|
|
2634
|
+
"""SysML v2 Rendering usage/definition.
|
|
2635
|
+
|
|
2636
|
+
Rendering specifies how views should be rendered.
|
|
2637
|
+
|
|
2638
|
+
Usage:
|
|
2639
|
+
Rendering() # rendering ;
|
|
2640
|
+
Rendering(name='myRender') # rendering myRender;
|
|
2641
|
+
Rendering(definition=True, name='DefRender') # rendering def DefRender;
|
|
2642
|
+
"""
|
|
2643
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2644
|
+
Usage.__init__(self)
|
|
2645
|
+
if definition:
|
|
2646
|
+
self.grammar = RenderingDefinition()
|
|
2647
|
+
else:
|
|
2648
|
+
self.grammar = RenderingUsage()
|
|
2649
|
+
|
|
2650
|
+
if name is not None:
|
|
2651
|
+
self._set_name(name)
|
|
2652
|
+
if shortname is not None:
|
|
2653
|
+
self._set_name(shortname, short=True)
|
|
2654
|
+
|
|
2655
|
+
|
|
2656
|
+
class Individual(Usage):
|
|
2657
|
+
sysml_type = 'individual'
|
|
2658
|
+
"""SysML v2 Individual usage/definition.
|
|
2659
|
+
|
|
2660
|
+
Individual represents a specific instance or occurrence.
|
|
2661
|
+
|
|
2662
|
+
Usage:
|
|
2663
|
+
Individual() # individual ;
|
|
2664
|
+
Individual(name='instance1') # individual instance1;
|
|
2665
|
+
Individual(definition=True, name='DefIndiv') # individual def DefIndiv;
|
|
2666
|
+
"""
|
|
2667
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2668
|
+
Usage.__init__(self)
|
|
2669
|
+
if definition:
|
|
2670
|
+
self.grammar = IndividualDefinition()
|
|
2671
|
+
else:
|
|
2672
|
+
self.grammar = IndividualUsageSimple()
|
|
2673
|
+
|
|
2674
|
+
if name is not None:
|
|
2675
|
+
self._set_name(name)
|
|
2676
|
+
if shortname is not None:
|
|
2677
|
+
self._set_name(shortname, short=True)
|
|
2678
|
+
|
|
2679
|
+
|
|
2680
|
+
class FlowDef(Usage):
|
|
2681
|
+
sysml_type = 'flow'
|
|
2682
|
+
"""SysML v2 FlowDefinition alternate form.
|
|
2683
|
+
|
|
2684
|
+
Note: This is the simpler 'flow def' form (distinct from FlowConnectionDefinition).
|
|
2685
|
+
Usage already provides Flow class for flowConnectionUsage/Definition.
|
|
2686
|
+
|
|
2687
|
+
Usage:
|
|
2688
|
+
FlowDef(name='DataStream') # flow def DataStream;
|
|
2689
|
+
"""
|
|
2690
|
+
def __init__(self, name=None, shortname=None):
|
|
2691
|
+
Usage.__init__(self)
|
|
2692
|
+
self.grammar = FlowDefinition()
|
|
2693
|
+
|
|
2694
|
+
if name is not None:
|
|
2695
|
+
self._set_name(name)
|
|
2696
|
+
if shortname is not None:
|
|
2697
|
+
self._set_name(shortname, short=True)
|
|
2698
|
+
|
|
2699
|
+
|
|
2700
|
+
class View(Usage):
|
|
2701
|
+
sysml_type = 'view'
|
|
2702
|
+
"""SysML v2 View usage/definition.
|
|
2703
|
+
|
|
2704
|
+
Views define how models are presented and filtered.
|
|
2705
|
+
|
|
2706
|
+
Usage:
|
|
2707
|
+
View() # view ;
|
|
2708
|
+
View(name='systemOverview') # view systemOverview;
|
|
2709
|
+
View(definition=True, name='SysView') # view def SysView;
|
|
2710
|
+
"""
|
|
2711
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2712
|
+
Usage.__init__(self)
|
|
2713
|
+
if definition:
|
|
2714
|
+
self.grammar = ViewDefinition()
|
|
2715
|
+
else:
|
|
2716
|
+
self.grammar = ViewUsage()
|
|
2717
|
+
|
|
2718
|
+
if name is not None:
|
|
2719
|
+
self._set_name(name)
|
|
2720
|
+
if shortname is not None:
|
|
2721
|
+
self._set_name(shortname, short=True)
|
|
2722
|
+
|
|
2723
|
+
|
|
2724
|
+
class Viewpoint(_BehaviorUsage):
|
|
2725
|
+
sysml_type = 'viewpoint'
|
|
2726
|
+
"""SysML v2 Viewpoint usage/definition.
|
|
2727
|
+
|
|
2728
|
+
Viewpoints specify viewing perspectives with stakeholder concerns.
|
|
2729
|
+
|
|
2730
|
+
Usage:
|
|
2731
|
+
Viewpoint() # viewpoint ;
|
|
2732
|
+
Viewpoint(name='stakeholderVP') # viewpoint stakeholderVP;
|
|
2733
|
+
Viewpoint(definition=True, name='VPDef') # viewpoint def VPDef;
|
|
2734
|
+
"""
|
|
2735
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2736
|
+
Usage.__init__(self)
|
|
2737
|
+
if definition:
|
|
2738
|
+
self.grammar = ViewpointDefinition()
|
|
2739
|
+
else:
|
|
2740
|
+
self.grammar = ViewpointUsage()
|
|
2741
|
+
|
|
2742
|
+
if name is not None:
|
|
2743
|
+
self._set_name(name)
|
|
2744
|
+
if shortname is not None:
|
|
2745
|
+
self._set_name(shortname, short=True)
|
|
2746
|
+
|
|
2747
|
+
|
|
2748
|
+
class Concern(_BehaviorUsage):
|
|
2749
|
+
sysml_type = 'concern'
|
|
2750
|
+
"""SysML v2 Concern usage/definition.
|
|
2751
|
+
|
|
2752
|
+
Concerns represent stakeholder concerns for viewpoints.
|
|
2753
|
+
|
|
2754
|
+
Usage:
|
|
2755
|
+
Concern() # concern ;
|
|
2756
|
+
Concern(name='security') # concern security;
|
|
2757
|
+
Concern(definition=True, name='Safety') # concern def Safety;
|
|
2758
|
+
"""
|
|
2759
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2760
|
+
Usage.__init__(self)
|
|
2761
|
+
if definition:
|
|
2762
|
+
self.grammar = ConcernDefinition()
|
|
2763
|
+
else:
|
|
2764
|
+
self.grammar = ConcernUsage()
|
|
2765
|
+
|
|
2766
|
+
if name is not None:
|
|
2767
|
+
self._set_name(name)
|
|
2768
|
+
if shortname is not None:
|
|
2769
|
+
self._set_name(shortname, short=True)
|
|
2770
|
+
|
|
2771
|
+
|
|
2772
|
+
class Case(_BehaviorUsage):
|
|
2773
|
+
sysml_type = 'case'
|
|
2774
|
+
"""SysML v2 Case usage/definition.
|
|
2775
|
+
|
|
2776
|
+
A case is a broad classifier for analysis, verification, and use cases.
|
|
2777
|
+
|
|
2778
|
+
Usage:
|
|
2779
|
+
Case() # case ;
|
|
2780
|
+
Case(name='scenario1') # case scenario1;
|
|
2781
|
+
Case(definition=True, name='CaseSpec') # case def CaseSpec;
|
|
2782
|
+
"""
|
|
2783
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2784
|
+
Usage.__init__(self)
|
|
2785
|
+
if definition:
|
|
2786
|
+
self.grammar = CaseDefinition()
|
|
2787
|
+
else:
|
|
2788
|
+
self.grammar = CaseUsage()
|
|
2789
|
+
|
|
2790
|
+
if name is not None:
|
|
2791
|
+
self._set_name(name)
|
|
2792
|
+
if shortname is not None:
|
|
2793
|
+
self._set_name(shortname, short=True)
|
|
2794
|
+
|
|
2795
|
+
|
|
2796
|
+
class AnalysisCase(_BehaviorUsage):
|
|
2797
|
+
sysml_type = 'analysis'
|
|
2798
|
+
"""SysML v2 AnalysisCase usage/definition.
|
|
2799
|
+
|
|
2800
|
+
Analysis cases represent analytical scenarios or studies.
|
|
2801
|
+
|
|
2802
|
+
Usage:
|
|
2803
|
+
AnalysisCase() # analysis ;
|
|
2804
|
+
AnalysisCase(name='thermal1') # analysis thermal1;
|
|
2805
|
+
AnalysisCase(definition=True, name='Thermal') # analysis def Thermal;
|
|
2806
|
+
"""
|
|
2807
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2808
|
+
Usage.__init__(self)
|
|
2809
|
+
if definition:
|
|
2810
|
+
self.grammar = AnalysisCaseDefinition()
|
|
2811
|
+
else:
|
|
2812
|
+
self.grammar = AnalysisCaseUsage()
|
|
2813
|
+
|
|
2814
|
+
if name is not None:
|
|
2815
|
+
self._set_name(name)
|
|
2816
|
+
if shortname is not None:
|
|
2817
|
+
self._set_name(shortname, short=True)
|
|
2818
|
+
|
|
2819
|
+
|
|
2820
|
+
class VerificationCase(_BehaviorUsage):
|
|
2821
|
+
sysml_type = 'verification'
|
|
2822
|
+
"""SysML v2 VerificationCase usage/definition.
|
|
2823
|
+
|
|
2824
|
+
Verification cases represent verification scenarios or tests.
|
|
2825
|
+
|
|
2826
|
+
Usage:
|
|
2827
|
+
VerificationCase() # verification ;
|
|
2828
|
+
VerificationCase(name='test1') # verification test1;
|
|
2829
|
+
VerificationCase(definition=True, name='Verify1') # verification case def Verify1;
|
|
2830
|
+
"""
|
|
2831
|
+
def __init__(self, definition=False, name=None, shortname=None):
|
|
2832
|
+
Usage.__init__(self)
|
|
2833
|
+
if definition:
|
|
2834
|
+
self.grammar = VerificationCaseDefinition()
|
|
2835
|
+
else:
|
|
2836
|
+
self.grammar = VerificationCaseUsage()
|
|
2837
|
+
|
|
2838
|
+
if name is not None:
|
|
2839
|
+
self._set_name(name)
|
|
2840
|
+
if shortname is not None:
|
|
2841
|
+
self._set_name(shortname, short=True)
|
|
2842
|
+
|
|
2843
|
+
|
|
2844
|
+
class Reference(Usage):
|
|
2845
|
+
sysml_type = 'reference'
|
|
2846
|
+
def __init__(self, name=None, shortname=None, redefines=None):
|
|
2847
|
+
self.name = name if name else str(uuidlib.uuid4())
|
|
2848
|
+
self.children = []
|
|
2849
|
+
self.typedby = None
|
|
2850
|
+
self.grammar = None
|
|
2851
|
+
self.parent = None
|
|
2852
|
+
self.shortname = shortname
|
|
2853
|
+
self.redefines = redefines # for redefinition like ref :>> name :
|
|
2854
|
+
self.ref_type = None # type reference
|
|
2855
|
+
|
|
2856
|
+
def set_type(self, type_obj):
|
|
2857
|
+
"""Set the type this reference points to.
|
|
2858
|
+
|
|
2859
|
+
Args:
|
|
2860
|
+
type_obj: Another element (Item, Part, etc.) to reference
|
|
2861
|
+
"""
|
|
2862
|
+
self.ref_type = type_obj
|
|
2863
|
+
return self
|
|
2864
|
+
|
|
2865
|
+
def _set_typed_by(self, type_obj):
|
|
2866
|
+
"""Alias for set_type for consistency with other classes."""
|
|
2867
|
+
return self.set_type(type_obj)
|
|
2868
|
+
|
|
2869
|
+
def dump(self):
|
|
2870
|
+
name_str = getattr(self, 'name', "") or ""
|
|
2871
|
+
type_str = ""
|
|
2872
|
+
|
|
2873
|
+
if self.ref_type:
|
|
2874
|
+
type_name = getattr(self.ref_type, 'name', str(self.ref_type))
|
|
2875
|
+
type_str = f" : {type_name}"
|
|
2876
|
+
|
|
2877
|
+
if self.redefines:
|
|
2878
|
+
return f"ref :>> {name_str}{type_str};"
|
|
2879
|
+
|
|
2880
|
+
return f"ref {name_str}{type_str};"
|
|
2881
|
+
|
|
2882
|
+
|
|
2883
|
+
class DefaultReference(Usage):
|
|
2884
|
+
def __init__(self):
|
|
2885
|
+
Usage.__init__(self)
|
|
2886
|
+
self.grammar = DefaultReferenceUsage()
|
|
2887
|
+
|
|
2888
|
+
def set_direction(self, direction):
|
|
2889
|
+
r = RefPrefix()
|
|
2890
|
+
if direction == "in":
|
|
2891
|
+
r.direction.isIn = True
|
|
2892
|
+
elif direction == "out":
|
|
2893
|
+
r.direction.isOut = True
|
|
2894
|
+
elif direction == "inout":
|
|
2895
|
+
r.direction.isInOut = True
|
|
2896
|
+
else:
|
|
2897
|
+
raise ValueError
|
|
2898
|
+
self.grammar.prefix = r
|
|
2899
|
+
return self
|
|
2900
|
+
|
|
2901
|
+
def usage_dump(self, child):
|
|
2902
|
+
# This is a usage.
|
|
2903
|
+
|
|
2904
|
+
self._ensure_body("definition")
|
|
2905
|
+
|
|
2906
|
+
# Add packaging
|
|
2907
|
+
package = {
|
|
2908
|
+
"name": "NonOccurrenceUsageElement",
|
|
2909
|
+
"ownedRelatedElement": self.grammar.get_definition(),
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
if child == "DefinitionBody":
|
|
2913
|
+
package = {
|
|
2914
|
+
"name": "NonOccurrenceUsageMember",
|
|
2915
|
+
"prefix": None,
|
|
2916
|
+
"ownedRelatedElement": [package],
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2919
|
+
package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]}
|
|
2920
|
+
elif "PackageBody":
|
|
2921
|
+
package = {"name": "UsageElement", "ownedRelatedElement": package}
|
|
2922
|
+
package = {
|
|
2923
|
+
"name": "PackageMember",
|
|
2924
|
+
"ownedRelatedElement": package,
|
|
2925
|
+
"prefix": None,
|
|
2926
|
+
}
|
|
2927
|
+
|
|
2928
|
+
return package
|
|
2929
|
+
|
|
2930
|
+
def _get_definition(self, child=None):
|
|
2931
|
+
package = self.usage_dump(child)
|
|
2932
|
+
|
|
2933
|
+
if child is None:
|
|
2934
|
+
package = {
|
|
2935
|
+
"name": "PackageBodyElement",
|
|
2936
|
+
"ownedRelationship": [package],
|
|
2937
|
+
"prefix": None,
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2940
|
+
# Add the typed by definition to the package output
|
|
2941
|
+
if self.typedby is not None:
|
|
2942
|
+
if child is None:
|
|
2943
|
+
package["ownedRelationship"].insert(
|
|
2944
|
+
0, self.typedby._get_definition(child="PackageBody")
|
|
2945
|
+
)
|
|
2946
|
+
elif child == "PackageBody":
|
|
2947
|
+
package = [self.typedby._get_definition(child="PackageBody"), package]
|
|
2948
|
+
else:
|
|
2949
|
+
package["ownedRelationship"].insert(
|
|
2950
|
+
0, self.typedby._get_definition(child=child)["ownedRelationship"][0]
|
|
2951
|
+
)
|
|
2952
|
+
|
|
2953
|
+
return package
|
|
2954
|
+
|
|
2955
|
+
# def dump(self, child=None):
|
|
2956
|
+
# package = self.usage_dump(child)
|
|
2957
|
+
|
|
2958
|
+
# if child is None:
|
|
2959
|
+
# package = {
|
|
2960
|
+
# "name": "PackageBodyElement",
|
|
2961
|
+
# "ownedRelationship": [package],
|
|
2962
|
+
# "prefix": None,
|
|
2963
|
+
# }
|
|
2964
|
+
|
|
2965
|
+
# # Add the typed by definition to the package output
|
|
2966
|
+
# if self.typedby is not None:
|
|
2967
|
+
# if child is None:
|
|
2968
|
+
# package["ownedRelationship"].insert(
|
|
2969
|
+
# 0, self.typedby.dump(child="PackageBody")
|
|
2970
|
+
# )
|
|
2971
|
+
# elif child == "PackageBody":
|
|
2972
|
+
# package = [self.typedby.dump(child="PackageBody"), package]
|
|
2973
|
+
# else:
|
|
2974
|
+
# package["ownedRelationship"].insert(
|
|
2975
|
+
# 0, self.typedby.dump(child=child)["ownedRelationship"][0]
|
|
2976
|
+
# )
|
|
2977
|
+
|
|
2978
|
+
# return package
|