robotransform 0.0.5__py3-none-any.whl → 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.
- robotransform/__init__.py +3 -3
- robotransform/__main__.py +29 -0
- robotransform/aadl.py +198 -0
- robotransform/convert.py +464 -0
- robotransform/filters.py +1 -6
- robotransform/main.py +28 -32
- robotransform/robochart.tx +1 -1
- robotransform/templates/aadl.jinja +18 -0
- robotransform/templates/{messages.aadl → messages.aadl.jinja} +6 -0
- {robotransform-0.0.5.dist-info → robotransform-0.1.0.dist-info}/METADATA +6 -15
- robotransform-0.1.0.dist-info/RECORD +15 -0
- {robotransform-0.0.5.dist-info → robotransform-0.1.0.dist-info}/WHEEL +2 -2
- robotransform/templates/logical.aadl +0 -72
- robotransform-0.0.5.dist-info/RECORD +0 -12
- {robotransform-0.0.5.dist-info → robotransform-0.1.0.dist-info}/entry_points.txt +0 -0
robotransform/__init__.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from robotransform.main import Store, MapleKStore
|
|
1
|
+
from robotransform.main import Store, MapleKStore
|
|
2
|
+
from robotransform.convert import dump_aadl
|
|
2
3
|
__all__ = (
|
|
3
4
|
"Store",
|
|
4
5
|
"MapleKStore",
|
|
5
|
-
"
|
|
6
|
-
"dump_logical",
|
|
6
|
+
"dump_aadl",
|
|
7
7
|
)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import arklog
|
|
7
|
+
|
|
8
|
+
from robotransform import Store, dump_aadl
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main():
|
|
12
|
+
parser = argparse.ArgumentParser(description="RoboTransform CLI.")
|
|
13
|
+
parser.add_argument(
|
|
14
|
+
"path",
|
|
15
|
+
type=Path,
|
|
16
|
+
help="Path to a rct file."
|
|
17
|
+
)
|
|
18
|
+
args = parser.parse_args()
|
|
19
|
+
|
|
20
|
+
if args.path.exists():
|
|
21
|
+
arklog.debug(f"Path exists: ({args.path}).")
|
|
22
|
+
store = Store((args.path,))
|
|
23
|
+
arklog.info(dump_aadl(store))
|
|
24
|
+
else:
|
|
25
|
+
arklog.debug(f"Path does not exist: ({args.path.resolve()}).")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == "__main__":
|
|
29
|
+
main()
|
robotransform/aadl.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import Dict, List, Optional, Literal
|
|
4
|
+
|
|
5
|
+
ComponentCategory = Literal[
|
|
6
|
+
"system", "process", "thread", "data", "processor", "bus", "device",
|
|
7
|
+
"memory", "virtual_processor", "virtual_bus"
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
FeatureDirection = Literal["in", "out", "in out"]
|
|
11
|
+
PortCategory = Literal["event", "event_data", "data"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class Mode:
|
|
16
|
+
name: str
|
|
17
|
+
initial: bool = False
|
|
18
|
+
|
|
19
|
+
def to_aadl(self, indent: str = "") -> str:
|
|
20
|
+
initial = "initial " if self.initial else ""
|
|
21
|
+
lines = [f"{indent}{self.name}: {initial}mode;"]
|
|
22
|
+
return "\n".join(lines)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class Port:
|
|
27
|
+
name: str
|
|
28
|
+
direction: FeatureDirection
|
|
29
|
+
port_category: PortCategory = "data"
|
|
30
|
+
data_type: Optional[str] = None
|
|
31
|
+
|
|
32
|
+
def to_aadl(self, indent: str = "") -> str:
|
|
33
|
+
port_type = "data port"
|
|
34
|
+
if self.port_category == "event":
|
|
35
|
+
port_type = "event port"
|
|
36
|
+
elif self.port_category == "event_data":
|
|
37
|
+
port_type = "event data port"
|
|
38
|
+
dt = f" {self.data_type}" if self.data_type else ""
|
|
39
|
+
return f"{indent}{self.name}: {self.direction} {port_type}{dt};"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class Subcomponent:
|
|
44
|
+
name: str
|
|
45
|
+
category: ComponentCategory
|
|
46
|
+
component_type: str
|
|
47
|
+
component_implementation: Optional[str] = None
|
|
48
|
+
|
|
49
|
+
def to_aadl(self, indent: str = "") -> str:
|
|
50
|
+
impl_part = f".{self.component_implementation}" if self.component_implementation else ""
|
|
51
|
+
return f"{indent}{self.name}: {self.category} {self.component_type}{impl_part};"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class Connection:
|
|
56
|
+
name: str
|
|
57
|
+
source: str
|
|
58
|
+
destination: str
|
|
59
|
+
bidirectional: bool = False
|
|
60
|
+
|
|
61
|
+
def to_aadl(self, indent: str = "") -> str:
|
|
62
|
+
arrow = "<->" if self.bidirectional else "->"
|
|
63
|
+
return f"{indent}{self.name}: {self.source} {arrow} {self.destination};"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass
|
|
67
|
+
class ComponentType:
|
|
68
|
+
name: str
|
|
69
|
+
category: ComponentCategory
|
|
70
|
+
features: Dict[str, Port] = field(default_factory=dict)
|
|
71
|
+
modes: List[Mode] = field(default_factory=list)
|
|
72
|
+
|
|
73
|
+
def to_aadl(self, indent: str = "") -> str:
|
|
74
|
+
lines = [f"{indent}{self.category} {self.name}"]
|
|
75
|
+
if self.features:
|
|
76
|
+
lines.append(f"{indent} features")
|
|
77
|
+
for f in self.features.values():
|
|
78
|
+
lines.append(f.to_aadl(indent + " "))
|
|
79
|
+
if self.modes:
|
|
80
|
+
lines.append(f"{indent} modes")
|
|
81
|
+
for m in self.modes:
|
|
82
|
+
lines.append(m.to_aadl(indent + " "))
|
|
83
|
+
lines.append(f"{indent}end {self.name};")
|
|
84
|
+
return "\n".join(lines)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class BehaviorGuard:
|
|
89
|
+
expression: str
|
|
90
|
+
|
|
91
|
+
def to_aadl(self) -> str:
|
|
92
|
+
return f"-[{self.expression}]-" if self.expression else ""
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass
|
|
96
|
+
class BehaviorTransition:
|
|
97
|
+
source: str
|
|
98
|
+
destination: str
|
|
99
|
+
guard: Optional[BehaviorGuard] = None
|
|
100
|
+
|
|
101
|
+
def to_aadl(self) -> str:
|
|
102
|
+
if self.guard and self.guard.expression:
|
|
103
|
+
return f"{self.source} -[{self.guard.expression}]-> {self.destination};"
|
|
104
|
+
return f"{self.source} -> {self.destination};"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@dataclass
|
|
108
|
+
class BehaviorSpecification:
|
|
109
|
+
transitions: List[BehaviorTransition] = field(default_factory=list)
|
|
110
|
+
|
|
111
|
+
def add_transition(self, source: str, destination: str, guard_expression: Optional[str] = None) -> None:
|
|
112
|
+
self.transitions.append(
|
|
113
|
+
BehaviorTransition(
|
|
114
|
+
source=source,
|
|
115
|
+
destination=destination,
|
|
116
|
+
guard=BehaviorGuard(guard_expression) if guard_expression else None,
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def to_aadl(self, indent: str = "") -> str:
|
|
121
|
+
lines = [f"{indent}annex behaviour_specification {{**", f"{indent} mode transitions"]
|
|
122
|
+
for t in self.transitions:
|
|
123
|
+
lines.append(f"{indent} {t.to_aadl()}")
|
|
124
|
+
lines.append(f"{indent}**}};")
|
|
125
|
+
return "\n".join(lines)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@dataclass
|
|
129
|
+
class ComponentImplementation:
|
|
130
|
+
name: str
|
|
131
|
+
category: str
|
|
132
|
+
type_name: str
|
|
133
|
+
subcomponents: Dict[str, Subcomponent] = field(default_factory=dict)
|
|
134
|
+
connections: List['Connection'] = field(default_factory=list)
|
|
135
|
+
modes: List['Mode'] = field(default_factory=list)
|
|
136
|
+
behavior: Optional['BehaviorSpecification'] = None
|
|
137
|
+
|
|
138
|
+
def to_aadl_header(self, indent: str = "") -> str:
|
|
139
|
+
return f"{indent}{self.category} implementation {self.name} for {self.type_name}"
|
|
140
|
+
|
|
141
|
+
def to_aadl(self, indent: str = "") -> str:
|
|
142
|
+
lines = [self.to_aadl_header(indent)]
|
|
143
|
+
if self.subcomponents:
|
|
144
|
+
lines.append(f"{indent} subcomponents")
|
|
145
|
+
for s in self.subcomponents.values():
|
|
146
|
+
lines.append(s.to_aadl(indent + " "))
|
|
147
|
+
if self.connections:
|
|
148
|
+
lines.append(f"{indent} connections")
|
|
149
|
+
for c in self.connections:
|
|
150
|
+
lines.append(c.to_aadl(indent + " "))
|
|
151
|
+
if self.modes:
|
|
152
|
+
lines.append(f"{indent} modes")
|
|
153
|
+
for m in self.modes:
|
|
154
|
+
lines.append(m.to_aadl(indent + " "))
|
|
155
|
+
if self.behavior:
|
|
156
|
+
lines.append(self.behavior.to_aadl(indent + " "))
|
|
157
|
+
lines.append(f"{indent}end {self.name};")
|
|
158
|
+
return "\n".join(lines)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@dataclass
|
|
162
|
+
class ThreadImplementation(ComponentImplementation):
|
|
163
|
+
category: str = field(init=False, default="thread")
|
|
164
|
+
|
|
165
|
+
@dataclass
|
|
166
|
+
class ProcessImplementation(ComponentImplementation):
|
|
167
|
+
category: str = field(init=False, default="process")
|
|
168
|
+
|
|
169
|
+
@dataclass
|
|
170
|
+
class SystemImplementation(ComponentImplementation):
|
|
171
|
+
category: str = field(init=False, default="system")
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@dataclass
|
|
175
|
+
class AADLPackage:
|
|
176
|
+
name: str
|
|
177
|
+
with_packages: List[str] = field(default_factory=list)
|
|
178
|
+
public_types: Dict[str, ComponentType] = field(default_factory=dict)
|
|
179
|
+
public_implementations: Dict[str, ComponentImplementation] = field(default_factory=dict)
|
|
180
|
+
private_types: Dict[str, ComponentType] = field(default_factory=dict)
|
|
181
|
+
private_implementations: Dict[str, ComponentImplementation] = field(default_factory=dict)
|
|
182
|
+
|
|
183
|
+
def to_aadl(self) -> str:
|
|
184
|
+
lines = [f"package {self.name}", "public"]
|
|
185
|
+
if self.with_packages:
|
|
186
|
+
lines.append(f" with {', '.join(self.with_packages)};")
|
|
187
|
+
for t in self.public_types.values():
|
|
188
|
+
lines.append(t.to_aadl(" "))
|
|
189
|
+
for i in self.public_implementations.values():
|
|
190
|
+
lines.append(i.to_aadl(" "))
|
|
191
|
+
if self.private_types or self.private_implementations:
|
|
192
|
+
lines.append("private")
|
|
193
|
+
for t in self.private_types.values():
|
|
194
|
+
lines.append(t.to_aadl(" "))
|
|
195
|
+
for i in self.private_implementations.values():
|
|
196
|
+
lines.append(i.to_aadl(" "))
|
|
197
|
+
lines.append(f"end {self.name};")
|
|
198
|
+
return "\n".join(lines)
|
robotransform/convert.py
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional, Union
|
|
7
|
+
|
|
8
|
+
from robotransform.aadl import (
|
|
9
|
+
AADLPackage,
|
|
10
|
+
ComponentType,
|
|
11
|
+
Connection as AADLConnection,
|
|
12
|
+
Port,
|
|
13
|
+
Mode,
|
|
14
|
+
BehaviorSpecification,
|
|
15
|
+
BehaviorTransition,
|
|
16
|
+
BehaviorGuard,
|
|
17
|
+
Subcomponent,
|
|
18
|
+
ProcessImplementation,
|
|
19
|
+
ThreadImplementation,
|
|
20
|
+
SystemImplementation,
|
|
21
|
+
)
|
|
22
|
+
from robotransform.filters import type_to_aadl_type
|
|
23
|
+
from robotransform.main import get_template, write_output
|
|
24
|
+
from robotransform.concepts import Package, StateMachineDef, ControllerDef, RoboticPlatformDef, Variable, Event, Module
|
|
25
|
+
|
|
26
|
+
_IDENTIFIER_RE = re.compile(r"[^0-9A-Za-z_]")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _aadl_id(value: object) -> str:
|
|
30
|
+
if value is None:
|
|
31
|
+
return "unnamed"
|
|
32
|
+
text = str(value)
|
|
33
|
+
text = text.replace("::", "_")
|
|
34
|
+
text = _IDENTIFIER_RE.sub("_", text)
|
|
35
|
+
if text and text[0].isdigit():
|
|
36
|
+
text = f"n_{text}"
|
|
37
|
+
return text or "unnamed"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _local_name(value: object) -> str:
|
|
41
|
+
if value is None:
|
|
42
|
+
return "unnamed"
|
|
43
|
+
if hasattr(value, "parts"):
|
|
44
|
+
parts = getattr(value, "parts")
|
|
45
|
+
if parts:
|
|
46
|
+
return str(parts[-1])
|
|
47
|
+
text = str(value)
|
|
48
|
+
return text.split("::")[-1]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _aadl_name(value: object) -> str:
|
|
52
|
+
return _aadl_id(_local_name(value))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _aadl_qualified_name(value: object) -> str:
|
|
56
|
+
if hasattr(value, "parts"):
|
|
57
|
+
parts = getattr(value, "parts")
|
|
58
|
+
return "::".join(_aadl_id(part) for part in parts)
|
|
59
|
+
return str(value)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _unique_name(base: str, existing: set[str]) -> str:
|
|
63
|
+
name = base
|
|
64
|
+
index = 1
|
|
65
|
+
while name in existing:
|
|
66
|
+
name = f"{base}_{index}"
|
|
67
|
+
index += 1
|
|
68
|
+
return name
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _message_type_name(type_ref: Optional[str]) -> Optional[str]:
|
|
72
|
+
if not type_ref or "::" not in type_ref:
|
|
73
|
+
return None
|
|
74
|
+
package, name = type_ref.split("::", 1)
|
|
75
|
+
if package != "messages":
|
|
76
|
+
return None
|
|
77
|
+
return name
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _collect_message_types(packages: list[AADLPackage]) -> set[str]:
|
|
81
|
+
names: set[str] = set()
|
|
82
|
+
for pkg in packages:
|
|
83
|
+
for comp in pkg.public_types.values():
|
|
84
|
+
for feature in comp.features.values():
|
|
85
|
+
if isinstance(feature, Port):
|
|
86
|
+
msg_name = _message_type_name(feature.data_type)
|
|
87
|
+
if msg_name:
|
|
88
|
+
names.add(msg_name)
|
|
89
|
+
for impl in pkg.public_implementations.values():
|
|
90
|
+
for sub in impl.subcomponents.values():
|
|
91
|
+
if sub.category != "data":
|
|
92
|
+
continue
|
|
93
|
+
msg_name = _message_type_name(sub.component_type)
|
|
94
|
+
if msg_name:
|
|
95
|
+
names.add(msg_name)
|
|
96
|
+
return names
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _collect_defined_message_types(robo_packages: list[Package]) -> set[str]:
|
|
100
|
+
names: set[str] = set()
|
|
101
|
+
for pkg in robo_packages:
|
|
102
|
+
for record in getattr(pkg, "types", []):
|
|
103
|
+
names.add(str(getattr(record, "name", "")))
|
|
104
|
+
return names
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _render_messages(robo_packages: list[Package], aadl_packages: list[AADLPackage],
|
|
108
|
+
output: Optional[Union[io.TextIOBase, Path, str]]) -> str:
|
|
109
|
+
used_types = _collect_message_types(aadl_packages)
|
|
110
|
+
defined_types = _collect_defined_message_types(robo_packages)
|
|
111
|
+
extra_types = sorted(used_types - defined_types)
|
|
112
|
+
template = get_template("messages")
|
|
113
|
+
data = template.render(packages=robo_packages, extra_types=extra_types)
|
|
114
|
+
return write_output(data, output)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def robocart_package_to_aadl_full(rc_pkg: "Package") -> AADLPackage:
|
|
118
|
+
aadl_pkg = AADLPackage(
|
|
119
|
+
name=_aadl_name(rc_pkg.name),
|
|
120
|
+
with_packages=["Base_Types", "messages"],
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# ---- registries ----
|
|
124
|
+
def register_type(comp_type: ComponentType) -> ComponentType:
|
|
125
|
+
return aadl_pkg.public_types.setdefault(comp_type.name, comp_type)
|
|
126
|
+
|
|
127
|
+
def register_impl(comp_impl):
|
|
128
|
+
return aadl_pkg.public_implementations.setdefault(comp_impl.name, comp_impl)
|
|
129
|
+
|
|
130
|
+
local_type_names = {str(getattr(t, "name", "")) for t in getattr(rc_pkg, "types", [])}
|
|
131
|
+
|
|
132
|
+
# ---- helpers ----
|
|
133
|
+
def resolve_type(robo_type: object) -> str:
|
|
134
|
+
typename = str(robo_type)
|
|
135
|
+
short_name = typename.split("::")[-1]
|
|
136
|
+
if short_name in local_type_names:
|
|
137
|
+
return _aadl_id(short_name)
|
|
138
|
+
return type_to_aadl_type(robo_type)
|
|
139
|
+
|
|
140
|
+
def convert_event(ev: "Event") -> Port:
|
|
141
|
+
data_type = resolve_type(ev.type) if getattr(ev, "type", None) else None
|
|
142
|
+
port_category = "event_data" if data_type else "event"
|
|
143
|
+
return Port(
|
|
144
|
+
name=_aadl_id(ev.name),
|
|
145
|
+
direction="in out",
|
|
146
|
+
port_category=port_category,
|
|
147
|
+
data_type=data_type,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
def convert_variable(var: "Variable") -> Subcomponent:
|
|
151
|
+
return Subcomponent(
|
|
152
|
+
name=_aadl_id(var.name),
|
|
153
|
+
category="data",
|
|
154
|
+
component_type=resolve_type(var.type),
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
def transition_guard(transition) -> Optional[str]:
|
|
158
|
+
trigger = getattr(transition, "trigger", None)
|
|
159
|
+
if not trigger:
|
|
160
|
+
return None
|
|
161
|
+
communication = getattr(trigger, "trigger", None)
|
|
162
|
+
if communication:
|
|
163
|
+
return _aadl_name(getattr(communication, "event", ""))
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
def ensure_process(sm: "StateMachineDef") -> ProcessImplementation:
|
|
167
|
+
type_name = _aadl_name(sm.name)
|
|
168
|
+
impl_name = f"{type_name}.impl"
|
|
169
|
+
if impl_name in aadl_pkg.public_implementations:
|
|
170
|
+
return aadl_pkg.public_implementations[impl_name]
|
|
171
|
+
|
|
172
|
+
proc_type = ComponentType(name=type_name, category="process")
|
|
173
|
+
for ev in getattr(sm, "events", []):
|
|
174
|
+
port = convert_event(ev)
|
|
175
|
+
proc_type.features.setdefault(port.name, port)
|
|
176
|
+
register_type(proc_type)
|
|
177
|
+
|
|
178
|
+
proc_impl = ProcessImplementation(name=impl_name, type_name=type_name)
|
|
179
|
+
|
|
180
|
+
nodes = list(getattr(sm, "nodes", []) or [])
|
|
181
|
+
state_names: list[str] = []
|
|
182
|
+
initial_names: set[str] = set()
|
|
183
|
+
for idx, node in enumerate(nodes):
|
|
184
|
+
node_type = node.__class__.__name__
|
|
185
|
+
if node_type == "State":
|
|
186
|
+
raw_name = getattr(node, "name", f"state_{idx}")
|
|
187
|
+
state_names.append(_aadl_name(raw_name))
|
|
188
|
+
elif node_type == "Initial":
|
|
189
|
+
initial_names.add(_aadl_name(getattr(node, "name", "")))
|
|
190
|
+
|
|
191
|
+
state_name_set = set(state_names)
|
|
192
|
+
initial_targets: set[str] = set()
|
|
193
|
+
transitions: list[BehaviorTransition] = []
|
|
194
|
+
for t in getattr(sm, "transitions", []):
|
|
195
|
+
src = _aadl_name(getattr(t, "source", ""))
|
|
196
|
+
dst = _aadl_name(getattr(t, "target", ""))
|
|
197
|
+
if src in initial_names and dst in state_name_set:
|
|
198
|
+
initial_targets.add(dst)
|
|
199
|
+
if src in state_name_set and dst in state_name_set:
|
|
200
|
+
guard_expr = transition_guard(t)
|
|
201
|
+
guard = BehaviorGuard(guard_expr) if guard_expr else None
|
|
202
|
+
transitions.append(BehaviorTransition(source=src, destination=dst, guard=guard))
|
|
203
|
+
|
|
204
|
+
for state_name in state_names:
|
|
205
|
+
proc_impl.modes.append(Mode(name=state_name, initial=state_name in initial_targets))
|
|
206
|
+
|
|
207
|
+
if proc_impl.modes and not any(m.initial for m in proc_impl.modes):
|
|
208
|
+
proc_impl.modes[0].initial = True
|
|
209
|
+
|
|
210
|
+
subcomponent_names = set()
|
|
211
|
+
for state_name in state_names:
|
|
212
|
+
thread_type_name = _aadl_id(f"{type_name}_{state_name}_Thread")
|
|
213
|
+
thread_impl_name = f"{thread_type_name}.impl"
|
|
214
|
+
register_type(ComponentType(name=thread_type_name, category="thread"))
|
|
215
|
+
register_impl(ThreadImplementation(name=thread_impl_name, type_name=thread_type_name))
|
|
216
|
+
sub_name = _unique_name(f"{state_name}_thread", subcomponent_names)
|
|
217
|
+
subcomponent_names.add(sub_name)
|
|
218
|
+
proc_impl.subcomponents[sub_name] = Subcomponent(
|
|
219
|
+
name=sub_name,
|
|
220
|
+
category="thread",
|
|
221
|
+
component_type=thread_type_name,
|
|
222
|
+
component_implementation="impl",
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
for var in getattr(sm, "variables", []):
|
|
226
|
+
data_sub = convert_variable(var)
|
|
227
|
+
data_sub.name = _unique_name(data_sub.name, subcomponent_names)
|
|
228
|
+
subcomponent_names.add(data_sub.name)
|
|
229
|
+
proc_impl.subcomponents[data_sub.name] = data_sub
|
|
230
|
+
|
|
231
|
+
if transitions:
|
|
232
|
+
behavior = BehaviorSpecification(transitions=transitions)
|
|
233
|
+
proc_impl.behavior = behavior
|
|
234
|
+
|
|
235
|
+
register_impl(proc_impl)
|
|
236
|
+
return proc_impl
|
|
237
|
+
|
|
238
|
+
def connection_endpoint(component, event, subcomponents: set[str]) -> str:
|
|
239
|
+
component_name = _aadl_name(component)
|
|
240
|
+
event_name = _aadl_name(event)
|
|
241
|
+
if component_name in subcomponents:
|
|
242
|
+
return f"{component_name}.{event_name}"
|
|
243
|
+
return event_name
|
|
244
|
+
|
|
245
|
+
def convert_connection(conn, subcomponents: set[str]) -> AADLConnection:
|
|
246
|
+
src = _aadl_name(getattr(conn, "source", ""))
|
|
247
|
+
dst = _aadl_name(getattr(conn, "target", ""))
|
|
248
|
+
src_evt = _aadl_name(getattr(conn, "event_source", ""))
|
|
249
|
+
dst_evt = _aadl_name(getattr(conn, "event_target", ""))
|
|
250
|
+
name = _aadl_id(f"{src}_{src_evt}_to_{dst}_{dst_evt}")
|
|
251
|
+
return AADLConnection(
|
|
252
|
+
name=name,
|
|
253
|
+
source=connection_endpoint(conn.source, conn.event_source, subcomponents),
|
|
254
|
+
destination=connection_endpoint(conn.target, conn.event_target, subcomponents),
|
|
255
|
+
bidirectional=getattr(conn, "bidirectional", False),
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
def ensure_controller(controller: "ControllerDef") -> SystemImplementation:
|
|
259
|
+
type_name = _aadl_name(controller.name)
|
|
260
|
+
impl_name = f"{type_name}.impl"
|
|
261
|
+
if impl_name in aadl_pkg.public_implementations:
|
|
262
|
+
return aadl_pkg.public_implementations[impl_name]
|
|
263
|
+
|
|
264
|
+
sys_type = ComponentType(name=type_name, category="system")
|
|
265
|
+
for ev in getattr(controller, "events", []):
|
|
266
|
+
port = convert_event(ev)
|
|
267
|
+
sys_type.features.setdefault(port.name, port)
|
|
268
|
+
register_type(sys_type)
|
|
269
|
+
|
|
270
|
+
sys_impl = SystemImplementation(name=impl_name, type_name=type_name)
|
|
271
|
+
subcomponent_names = set()
|
|
272
|
+
port_subcomponents = set()
|
|
273
|
+
|
|
274
|
+
for sm in getattr(controller, "machines", []):
|
|
275
|
+
if isinstance(sm, StateMachineDef) or sm.__class__.__name__ == "StateMachineDef":
|
|
276
|
+
proc_impl = ensure_process(sm)
|
|
277
|
+
sub_name = _aadl_name(getattr(sm, "name", "process"))
|
|
278
|
+
sub_name = _unique_name(sub_name, subcomponent_names)
|
|
279
|
+
subcomponent_names.add(sub_name)
|
|
280
|
+
port_subcomponents.add(sub_name)
|
|
281
|
+
sys_impl.subcomponents[sub_name] = Subcomponent(
|
|
282
|
+
name=sub_name,
|
|
283
|
+
category="process",
|
|
284
|
+
component_type=proc_impl.type_name,
|
|
285
|
+
component_implementation="impl",
|
|
286
|
+
)
|
|
287
|
+
elif sm.__class__.__name__ == "StateMachineRef":
|
|
288
|
+
sub_name = _aadl_name(getattr(sm, "name", "process_ref"))
|
|
289
|
+
sub_name = _unique_name(sub_name, subcomponent_names)
|
|
290
|
+
subcomponent_names.add(sub_name)
|
|
291
|
+
port_subcomponents.add(sub_name)
|
|
292
|
+
sys_impl.subcomponents[sub_name] = Subcomponent(
|
|
293
|
+
name=sub_name,
|
|
294
|
+
category="process",
|
|
295
|
+
component_type=_aadl_qualified_name(getattr(sm, "ref", "")),
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
for var in getattr(controller, "variables", []):
|
|
299
|
+
data_sub = convert_variable(var)
|
|
300
|
+
data_sub.name = _unique_name(data_sub.name, subcomponent_names)
|
|
301
|
+
subcomponent_names.add(data_sub.name)
|
|
302
|
+
sys_impl.subcomponents[data_sub.name] = data_sub
|
|
303
|
+
|
|
304
|
+
for conn in getattr(controller, "connections", []):
|
|
305
|
+
sys_impl.connections.append(convert_connection(conn, port_subcomponents))
|
|
306
|
+
|
|
307
|
+
register_impl(sys_impl)
|
|
308
|
+
return sys_impl
|
|
309
|
+
|
|
310
|
+
def ensure_robotic_platform(platform: "RoboticPlatformDef") -> SystemImplementation:
|
|
311
|
+
type_name = _aadl_name(platform.name)
|
|
312
|
+
impl_name = f"{type_name}.impl"
|
|
313
|
+
if impl_name in aadl_pkg.public_implementations:
|
|
314
|
+
return aadl_pkg.public_implementations[impl_name]
|
|
315
|
+
|
|
316
|
+
sys_type = ComponentType(name=type_name, category="system")
|
|
317
|
+
for ev in getattr(platform, "events", []):
|
|
318
|
+
port = convert_event(ev)
|
|
319
|
+
sys_type.features.setdefault(port.name, port)
|
|
320
|
+
register_type(sys_type)
|
|
321
|
+
|
|
322
|
+
sys_impl = SystemImplementation(name=impl_name, type_name=type_name)
|
|
323
|
+
subcomponent_names = set()
|
|
324
|
+
|
|
325
|
+
for var in getattr(platform, "variables", []):
|
|
326
|
+
data_sub = convert_variable(var)
|
|
327
|
+
data_sub.name = _unique_name(data_sub.name, subcomponent_names)
|
|
328
|
+
subcomponent_names.add(data_sub.name)
|
|
329
|
+
sys_impl.subcomponents[data_sub.name] = data_sub
|
|
330
|
+
|
|
331
|
+
register_impl(sys_impl)
|
|
332
|
+
return sys_impl
|
|
333
|
+
|
|
334
|
+
def ensure_module(module: "Module") -> SystemImplementation:
|
|
335
|
+
type_name = _aadl_name(module.name)
|
|
336
|
+
impl_name = f"{type_name}.impl"
|
|
337
|
+
if impl_name in aadl_pkg.public_implementations:
|
|
338
|
+
return aadl_pkg.public_implementations[impl_name]
|
|
339
|
+
|
|
340
|
+
module_type = ComponentType(name=type_name, category="system")
|
|
341
|
+
register_type(module_type)
|
|
342
|
+
|
|
343
|
+
module_impl = SystemImplementation(name=impl_name, type_name=type_name)
|
|
344
|
+
subcomponent_names = set()
|
|
345
|
+
port_subcomponents = set()
|
|
346
|
+
|
|
347
|
+
for node in getattr(module, "nodes", []):
|
|
348
|
+
node_type = node.__class__.__name__
|
|
349
|
+
if node_type == "ControllerDef":
|
|
350
|
+
controller_impl = ensure_controller(node)
|
|
351
|
+
sub_name = _aadl_name(getattr(node, "name", "controller"))
|
|
352
|
+
sub_name = _unique_name(sub_name, subcomponent_names)
|
|
353
|
+
subcomponent_names.add(sub_name)
|
|
354
|
+
port_subcomponents.add(sub_name)
|
|
355
|
+
module_impl.subcomponents[sub_name] = Subcomponent(
|
|
356
|
+
name=sub_name,
|
|
357
|
+
category="system",
|
|
358
|
+
component_type=controller_impl.type_name,
|
|
359
|
+
component_implementation="impl",
|
|
360
|
+
)
|
|
361
|
+
elif node_type == "ControllerRef":
|
|
362
|
+
sub_name = _aadl_name(getattr(node, "name", "controller_ref"))
|
|
363
|
+
sub_name = _unique_name(sub_name, subcomponent_names)
|
|
364
|
+
subcomponent_names.add(sub_name)
|
|
365
|
+
port_subcomponents.add(sub_name)
|
|
366
|
+
module_impl.subcomponents[sub_name] = Subcomponent(
|
|
367
|
+
name=sub_name,
|
|
368
|
+
category="system",
|
|
369
|
+
component_type=_aadl_qualified_name(getattr(node, "ref", "")),
|
|
370
|
+
)
|
|
371
|
+
elif node_type == "StateMachineDef":
|
|
372
|
+
proc_impl = ensure_process(node)
|
|
373
|
+
sub_name = _aadl_name(getattr(node, "name", "process"))
|
|
374
|
+
sub_name = _unique_name(sub_name, subcomponent_names)
|
|
375
|
+
subcomponent_names.add(sub_name)
|
|
376
|
+
port_subcomponents.add(sub_name)
|
|
377
|
+
module_impl.subcomponents[sub_name] = Subcomponent(
|
|
378
|
+
name=sub_name,
|
|
379
|
+
category="process",
|
|
380
|
+
component_type=proc_impl.type_name,
|
|
381
|
+
component_implementation="impl",
|
|
382
|
+
)
|
|
383
|
+
elif node_type == "StateMachineRef":
|
|
384
|
+
sub_name = _aadl_name(getattr(node, "name", "process_ref"))
|
|
385
|
+
sub_name = _unique_name(sub_name, subcomponent_names)
|
|
386
|
+
subcomponent_names.add(sub_name)
|
|
387
|
+
port_subcomponents.add(sub_name)
|
|
388
|
+
module_impl.subcomponents[sub_name] = Subcomponent(
|
|
389
|
+
name=sub_name,
|
|
390
|
+
category="process",
|
|
391
|
+
component_type=_aadl_qualified_name(getattr(node, "ref", "")),
|
|
392
|
+
)
|
|
393
|
+
elif node_type == "RoboticPlatformDef":
|
|
394
|
+
platform_impl = ensure_robotic_platform(node)
|
|
395
|
+
sub_name = _aadl_name(getattr(node, "name", "platform"))
|
|
396
|
+
sub_name = _unique_name(sub_name, subcomponent_names)
|
|
397
|
+
subcomponent_names.add(sub_name)
|
|
398
|
+
port_subcomponents.add(sub_name)
|
|
399
|
+
module_impl.subcomponents[sub_name] = Subcomponent(
|
|
400
|
+
name=sub_name,
|
|
401
|
+
category="system",
|
|
402
|
+
component_type=platform_impl.type_name,
|
|
403
|
+
component_implementation="impl",
|
|
404
|
+
)
|
|
405
|
+
elif node_type == "RoboticPlatformRef":
|
|
406
|
+
sub_name = _aadl_name(getattr(node, "name", "platform_ref"))
|
|
407
|
+
sub_name = _unique_name(sub_name, subcomponent_names)
|
|
408
|
+
subcomponent_names.add(sub_name)
|
|
409
|
+
port_subcomponents.add(sub_name)
|
|
410
|
+
module_impl.subcomponents[sub_name] = Subcomponent(
|
|
411
|
+
name=sub_name,
|
|
412
|
+
category="system",
|
|
413
|
+
component_type=_aadl_qualified_name(getattr(node, "ref", "")),
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
for conn in getattr(module, "connections", []):
|
|
417
|
+
module_impl.connections.append(convert_connection(conn, port_subcomponents))
|
|
418
|
+
|
|
419
|
+
register_impl(module_impl)
|
|
420
|
+
return module_impl
|
|
421
|
+
|
|
422
|
+
# ---- top-level package conversion ----
|
|
423
|
+
for record in getattr(rc_pkg, "types", []):
|
|
424
|
+
data_name = _aadl_name(getattr(record, "name", "data"))
|
|
425
|
+
register_type(ComponentType(name=data_name, category="data"))
|
|
426
|
+
|
|
427
|
+
for ctl in getattr(rc_pkg, "controllers", []):
|
|
428
|
+
ensure_controller(ctl)
|
|
429
|
+
|
|
430
|
+
for sm in getattr(rc_pkg, "machines", []):
|
|
431
|
+
if isinstance(sm, StateMachineDef) or sm.__class__.__name__ == "StateMachineDef":
|
|
432
|
+
ensure_process(sm)
|
|
433
|
+
|
|
434
|
+
for robot in getattr(rc_pkg, "robots", []):
|
|
435
|
+
ensure_robotic_platform(robot)
|
|
436
|
+
|
|
437
|
+
for mod in getattr(rc_pkg, "modules", []):
|
|
438
|
+
ensure_module(mod)
|
|
439
|
+
|
|
440
|
+
return aadl_pkg
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def dump_aadl(rc_input: Union["Package", "Store"], output: Optional[Union[io.TextIOBase, Path, str]] = None,
|
|
444
|
+
template_name: str = "aadl",
|
|
445
|
+
messages_output: Optional[Union[io.TextIOBase, Path, str]] = None) -> str:
|
|
446
|
+
# If a Store, render all packages inside it
|
|
447
|
+
if hasattr(rc_input, "__iter__") and not isinstance(rc_input, Package):
|
|
448
|
+
robo_packages = list(rc_input.load().values())
|
|
449
|
+
packages = [robocart_package_to_aadl_full(pkg) for pkg in robo_packages]
|
|
450
|
+
else:
|
|
451
|
+
robo_packages = [rc_input]
|
|
452
|
+
packages = [robocart_package_to_aadl_full(rc_input)]
|
|
453
|
+
|
|
454
|
+
template = get_template(template_name)
|
|
455
|
+
data = template.render(packages=packages)
|
|
456
|
+
write_output(data, output)
|
|
457
|
+
|
|
458
|
+
if messages_output is None and isinstance(output, (str, Path)):
|
|
459
|
+
messages_output = Path(output).parent / "messages.aadl"
|
|
460
|
+
|
|
461
|
+
if messages_output is not None:
|
|
462
|
+
_render_messages(robo_packages, packages, messages_output)
|
|
463
|
+
|
|
464
|
+
return data
|
robotransform/filters.py
CHANGED
robotransform/main.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from dataclasses import dataclass, fields
|
|
2
3
|
from functools import lru_cache
|
|
3
4
|
from pathlib import Path
|
|
@@ -6,10 +7,10 @@ import arklog
|
|
|
6
7
|
from textx import metamodel_from_str
|
|
7
8
|
from jinja2 import Environment, FileSystemLoader, Template
|
|
8
9
|
import io
|
|
9
|
-
from typing import Union, Optional, Iterable, Iterator
|
|
10
|
+
from typing import Union, Optional, Iterable, Iterator, Callable
|
|
10
11
|
|
|
11
12
|
from robotransform.concepts import all_concepts, Package
|
|
12
|
-
from robotransform.filters import
|
|
13
|
+
from robotransform.filters import type_to_aadl_type
|
|
13
14
|
from robotransform.processors import processors
|
|
14
15
|
|
|
15
16
|
|
|
@@ -29,30 +30,39 @@ class Store:
|
|
|
29
30
|
yield item
|
|
30
31
|
continue
|
|
31
32
|
|
|
32
|
-
def parse_imports(self, package: Package, parent_path: Path, visited):
|
|
33
|
+
def parse_imports(self, package: Package, parent_path: Path, visited: dict[Path, Package]):
|
|
33
34
|
stack = [package]
|
|
35
|
+
unresolved = []
|
|
34
36
|
while stack:
|
|
35
|
-
|
|
36
|
-
for imp in
|
|
37
|
+
current_package = stack.pop()
|
|
38
|
+
for imp in current_package.imports:
|
|
37
39
|
name = imp.name.name.parts[-1]
|
|
38
|
-
if name in visited:
|
|
39
|
-
continue
|
|
40
40
|
path = parent_path / f"{name}.rct"
|
|
41
|
+
|
|
42
|
+
if path in visited or path in unresolved: # check path, not name
|
|
43
|
+
continue
|
|
41
44
|
if not path.exists():
|
|
42
|
-
arklog.debug(f"Can't import {path}.")
|
|
45
|
+
arklog.debug(f"Can't import ({path}).")
|
|
46
|
+
unresolved.append(path)
|
|
43
47
|
continue
|
|
48
|
+
|
|
44
49
|
sub_package = parse_robochart(path)
|
|
45
|
-
visited[path] = sub_package
|
|
50
|
+
visited[path] = sub_package # mark visited immediately
|
|
46
51
|
stack.append(sub_package)
|
|
52
|
+
|
|
47
53
|
return visited
|
|
48
54
|
|
|
49
55
|
def load(self, imports: bool = True) -> dict[Path, Package]:
|
|
50
|
-
visited = {}
|
|
56
|
+
visited: dict[Path, Package] = {}
|
|
57
|
+
|
|
51
58
|
for path in self:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
if path not in visited:
|
|
60
|
+
package = parse_robochart(path)
|
|
61
|
+
visited[path] = package # mark visited immediately
|
|
62
|
+
if imports:
|
|
63
|
+
# parse imports recursively
|
|
64
|
+
visited |= self.parse_imports(package, path.parent, visited)
|
|
65
|
+
|
|
56
66
|
return visited
|
|
57
67
|
|
|
58
68
|
|
|
@@ -98,15 +108,13 @@ def parse_robochart(source: Path | str) -> Package:
|
|
|
98
108
|
return metamodel.model_from_str(data)
|
|
99
109
|
|
|
100
110
|
|
|
101
|
-
@lru_cache(maxsize=
|
|
111
|
+
@lru_cache(maxsize=3)
|
|
102
112
|
def get_template(name: str) -> Template:
|
|
103
113
|
environment = Environment(loader=FileSystemLoader(Path(__file__).resolve().parent / "templates"))
|
|
104
|
-
environment.filters["
|
|
105
|
-
environment.filters["type_to_aadl_type"] = type_to_aadl_type # For use with pipes
|
|
106
|
-
# environment.globals["type_to_port"] = type_to_port # For use as a function
|
|
114
|
+
environment.filters["type_to_aadl_type"] = type_to_aadl_type # For use with pipes
|
|
107
115
|
templates = {
|
|
108
|
-
"messages": "messages.aadl",
|
|
109
|
-
"
|
|
116
|
+
"messages": "messages.aadl.jinja",
|
|
117
|
+
"aadl": "aadl.jinja",
|
|
110
118
|
}
|
|
111
119
|
if found := templates.get(name):
|
|
112
120
|
return environment.get_template(found)
|
|
@@ -129,18 +137,6 @@ def write_output(data: str, output: Optional[Union[io.TextIOBase, Path, str]] =
|
|
|
129
137
|
return data
|
|
130
138
|
|
|
131
139
|
|
|
132
|
-
def dump_messages(store: Store, output: Optional[Union[io.TextIOBase, Path, str]] = None) -> None:
|
|
133
|
-
template = get_template("messages")
|
|
134
|
-
output = output if output else Path("output/generated/messages/messages.aadl")
|
|
135
|
-
write_output(template.render(packages=store.load().values()), output)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
def dump_logical(store: Store, output: Optional[Union[io.TextIOBase, Path, str]] = None) -> None:
|
|
139
|
-
template = get_template("logical")
|
|
140
|
-
output = output if output else Path("output/generated/LogicalArchitecture.aadl")
|
|
141
|
-
write_output(template.render(packages=store.load().values()), output)
|
|
142
|
-
|
|
143
|
-
|
|
144
140
|
def main():
|
|
145
141
|
pass
|
|
146
142
|
|
robotransform/robochart.tx
CHANGED
|
@@ -302,7 +302,7 @@ Transition:
|
|
|
302
302
|
'transition' name=ID '{'
|
|
303
303
|
'from' source=QualifiedName
|
|
304
304
|
'to' target=QualifiedName
|
|
305
|
-
trigger
|
|
305
|
+
(trigger=Trigger)?
|
|
306
306
|
(reset*=ClockReset '<{' deadline=Expression '}')?
|
|
307
307
|
('condition' condition=ConditionExpr)?
|
|
308
308
|
('action' action=Statement)?
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{#- Render all AADL packages -#}
|
|
2
|
+
{% for pkg in packages -%}
|
|
3
|
+
package {{ pkg.name }}
|
|
4
|
+
public
|
|
5
|
+
{% if pkg.with_packages -%}
|
|
6
|
+
with {{ pkg.with_packages | join(', ') }};
|
|
7
|
+
{% endif -%}
|
|
8
|
+
{% for comp in pkg.public_types.values() -%}
|
|
9
|
+
{{ comp.to_aadl(" ") }}
|
|
10
|
+
{% endfor -%}
|
|
11
|
+
{% for impl in pkg.public_implementations.values() -%}
|
|
12
|
+
{{ impl.to_aadl(" ") }}
|
|
13
|
+
{% endfor -%}
|
|
14
|
+
end {{ pkg.name }};
|
|
15
|
+
{% if not loop.last %}
|
|
16
|
+
|
|
17
|
+
{% endif -%}
|
|
18
|
+
{% endfor %}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: robotransform
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
4
4
|
Summary: Perform model transformations for the RoboSapiens project.
|
|
5
5
|
Keywords: transformation
|
|
6
6
|
Author: Arkadiusz Michał Ryś
|
|
@@ -688,23 +688,14 @@ Requires-Dist: arkfast>=0.1.0,<1
|
|
|
688
688
|
Requires-Dist: textx>=4.2.3,<5
|
|
689
689
|
Requires-Dist: jinja2>=3.1.6,<4
|
|
690
690
|
Requires-Dist: pyecore>=0.15.2,<1
|
|
691
|
-
Requires-
|
|
692
|
-
Requires-Dist: sphinx-rtd-theme ; extra == 'doc'
|
|
693
|
-
Requires-Dist: sphinx-tabs ; extra == 'doc'
|
|
694
|
-
Requires-Dist: sphinx-toolbox ; extra == 'doc'
|
|
695
|
-
Requires-Dist: sphinxext-opengraph ; extra == 'doc'
|
|
696
|
-
Requires-Dist: sphinx-notfound-page ; extra == 'doc'
|
|
697
|
-
Requires-Dist: sphinxcontrib-drawio ; extra == 'doc'
|
|
698
|
-
Requires-Dist: readthedocs-sphinx-search ; extra == 'doc'
|
|
699
|
-
Requires-Dist: myst-parser ; extra == 'doc'
|
|
700
|
-
Requires-Dist: pytest ; extra == 'test'
|
|
701
|
-
Requires-Python: >=3.12
|
|
691
|
+
Requires-Python: >=3.14
|
|
702
692
|
Project-URL: source, https://git.rys.one/phd/robosapiens/robotransform
|
|
703
|
-
Provides-Extra:
|
|
704
|
-
Provides-Extra: test
|
|
693
|
+
Provides-Extra: gui
|
|
705
694
|
Description-Content-Type: text/markdown
|
|
706
695
|
|
|
707
696
|
# RoboTransform
|
|
708
697
|
|
|
709
|
-
Library to perform model
|
|
698
|
+
Library to perform model-to-model transformations in the context of RoboSAPIENS.
|
|
710
699
|
|
|
700
|
+
For installation steps follow [the documentation](https://robotransform-0f96de.pages.rys.one/).
|
|
701
|
+
We also provide [the reasoning behind certain decisions](-/jobs/artifacts/main/download?job=typst).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
robotransform/__init__.py,sha256=xvdDZSVP3mLi7gN7a2Qdtyvh-ZQ1YwXlIaGFvcb1Ulg,157
|
|
2
|
+
robotransform/__main__.py,sha256=PcaDvzku32_BZ3c9ODZMUJKveARGID3FGOq0XA60c7o,617
|
|
3
|
+
robotransform/aadl.py,sha256=tPlmiSltLSbC8kqU-FlxyDPdcdTjUT4rKHwEweFgBow,6664
|
|
4
|
+
robotransform/concepts.py,sha256=MXPff6XwQyabWJcSC5armw3eI4xGDmnd6yZpmHdO6m8,9933
|
|
5
|
+
robotransform/convert.py,sha256=KStKLUDAXD15j4-jzqIG-rga8c5WGB3J4URjAGuJvt0,18819
|
|
6
|
+
robotransform/filters.py,sha256=uEG2xs-gvtxpmyItbXtjLeOXgCJlACbPgAL1Hi2n5iE,838
|
|
7
|
+
robotransform/main.py,sha256=xrbu1Dal027VPAYSzRjHFqh7OuFHQZ_tkL_xz7lYFro,4620
|
|
8
|
+
robotransform/processors.py,sha256=8NaNFTAm3iaNAzbp5D8-Uv_qIWyxVklIbmGtXi5--nM,1578
|
|
9
|
+
robotransform/robochart.tx,sha256=lM4ooS8jvb949q20X4t6jZzh1M3VCtlxUORlWS3GA4w,10229
|
|
10
|
+
robotransform/templates/aadl.jinja,sha256=7BHQvBPsJby5XSmiqEXd8mrQwEdSG3WPtwzcDu8WSlY,424
|
|
11
|
+
robotransform/templates/messages.aadl.jinja,sha256=1EOMiBE-Lh5FWnfjSsVoICDU_-ZcgFEY1sMasXP5k00,530
|
|
12
|
+
robotransform-0.1.0.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
|
|
13
|
+
robotransform-0.1.0.dist-info/entry_points.txt,sha256=NvmK-01oEE7ji06NbIxr7pZGUEJwbwMLjjfHssOVmB0,52
|
|
14
|
+
robotransform-0.1.0.dist-info/METADATA,sha256=MwlUaGCSB2st_rvml5t5CzYM2oSmJ8U8LMNDYoYZ-h0,42259
|
|
15
|
+
robotransform-0.1.0.dist-info/RECORD,,
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
{%- macro render_port(name, direction, type) -%}
|
|
2
|
-
{{ name }}: {{ direction }} {{ type | type_to_port }} port {{ type | type_to_aadl_type}};
|
|
3
|
-
{%- endmacro -%}
|
|
4
|
-
|
|
5
|
-
{%- macro render_node_threads(machine) -%}
|
|
6
|
-
{%- for node in machine.nodes %}
|
|
7
|
-
thread {{ node.name }}
|
|
8
|
-
features {# TODO: Replace these with real resolved fields #}
|
|
9
|
-
input: in data port Base_Types::Float;
|
|
10
|
-
output: out data port Base_Types::Float;
|
|
11
|
-
end {{ node.name }};
|
|
12
|
-
thread implementation {{ node.name }}.impl
|
|
13
|
-
end {{ node.name }}.impl;
|
|
14
|
-
{%- endfor %}
|
|
15
|
-
{%- endmacro -%}
|
|
16
|
-
|
|
17
|
-
package LogicalArchitecture
|
|
18
|
-
public
|
|
19
|
-
with messages, Base_Types;
|
|
20
|
-
{%- for package in packages %}
|
|
21
|
-
process {{package.name}}
|
|
22
|
-
{%- set interface_vars = package.interfaces | map(attribute="variables") | sum(start=[]) -%}
|
|
23
|
-
{%- set machine_vars = package.machines | map(attribute="variables") | sum(start=[]) -%}
|
|
24
|
-
{%- if interface_vars or machine_vars %}
|
|
25
|
-
features
|
|
26
|
-
{%- for interface in package.interfaces -%}
|
|
27
|
-
{%- for variable in interface.variables %}
|
|
28
|
-
{{ render_port(variable.name, "in", variable.type) }}
|
|
29
|
-
{%- endfor %}
|
|
30
|
-
{%- endfor %}
|
|
31
|
-
{%- for machine in package.machines -%}
|
|
32
|
-
{%- for variable in machine.variables %}
|
|
33
|
-
{{ render_port(variable.name, "in", variable.type) }}
|
|
34
|
-
{%- endfor %}
|
|
35
|
-
{%- endfor -%}
|
|
36
|
-
{%- endif %}
|
|
37
|
-
end {{package.name}};
|
|
38
|
-
process implementation {{package.name}}.impl
|
|
39
|
-
{%- set machines_with_nodes = package.machines | selectattr('nodes') | selectattr('nodes', '!=', []) | list %}
|
|
40
|
-
{%- if machines_with_nodes %}
|
|
41
|
-
modes
|
|
42
|
-
{%- for machine in machines_with_nodes -%}
|
|
43
|
-
{% for node in machine.nodes %}
|
|
44
|
-
{{node.name}}: mode;
|
|
45
|
-
{%- endfor %}
|
|
46
|
-
{%- endfor %}
|
|
47
|
-
{%- endif %}
|
|
48
|
-
{%- if machines_with_nodes %}
|
|
49
|
-
subcomponents
|
|
50
|
-
{%- for machine in machines_with_nodes -%}
|
|
51
|
-
{% for node in machine.nodes %}
|
|
52
|
-
{{node.name}}: thread {{node.name}}; {# TODO: Filter so not all nodes are transformed into threads #}
|
|
53
|
-
{%- endfor %}
|
|
54
|
-
{%- endfor %}
|
|
55
|
-
{%- endif %}
|
|
56
|
-
{%- set machines_with_transitions = package.machines | selectattr("transitions") | selectattr('transitions', '!=', []) | list %}
|
|
57
|
-
{%- if machines_with_transitions %}
|
|
58
|
-
connections
|
|
59
|
-
{%- for machine in machines_with_transitions -%}
|
|
60
|
-
{% for transition in machine.transitions %}
|
|
61
|
-
{{ transition.name }}: port {{ transition.source }} -> {{ transition.target }}; {# TODO: Check if these are correct #}
|
|
62
|
-
{%- endfor %}
|
|
63
|
-
{%- endfor %}
|
|
64
|
-
{%- endif %}
|
|
65
|
-
end {{package.name}}.impl;
|
|
66
|
-
{%- if machines_with_nodes %}
|
|
67
|
-
{%- for machine in machines_with_nodes -%}
|
|
68
|
-
{{ render_node_threads(machine) }}
|
|
69
|
-
{%- endfor %}
|
|
70
|
-
{%- endif %}
|
|
71
|
-
{%- endfor %}
|
|
72
|
-
end LogicalArchitecture;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
robotransform/__init__.py,sha256=8IkQ3Astb5vWt6yKgB0e3FqniYWPy9wufasZR9OwXmI,166
|
|
2
|
-
robotransform/concepts.py,sha256=MXPff6XwQyabWJcSC5armw3eI4xGDmnd6yZpmHdO6m8,9933
|
|
3
|
-
robotransform/filters.py,sha256=E9yM36Rktb28v32F9SQg0lB9xYPB1YcR5A4o45e7PRY,936
|
|
4
|
-
robotransform/main.py,sha256=afE30HpVo5weXeBO60LOpkCDS4cZ0EKo-nuD0xUG5cI,5025
|
|
5
|
-
robotransform/processors.py,sha256=8NaNFTAm3iaNAzbp5D8-Uv_qIWyxVklIbmGtXi5--nM,1578
|
|
6
|
-
robotransform/robochart.tx,sha256=dz_4hr-reu9ubuXdZR4WNKkp-gs_txgzyRvR-p7nphA,10227
|
|
7
|
-
robotransform/templates/logical.aadl,sha256=_kvpAij37DjL4aHrizBrwG5RCO7LJXD0tkl__vCdAZU,2743
|
|
8
|
-
robotransform/templates/messages.aadl,sha256=gSEULreDkIM-ukODyD1WnaV1qFTw_j5EAM2Z9u-Xkmo,383
|
|
9
|
-
robotransform-0.0.5.dist-info/WHEEL,sha256=z-mOpxbJHqy3cq6SvUThBZdaLGFZzdZPtgWLcP2NKjQ,79
|
|
10
|
-
robotransform-0.0.5.dist-info/entry_points.txt,sha256=NvmK-01oEE7ji06NbIxr7pZGUEJwbwMLjjfHssOVmB0,52
|
|
11
|
-
robotransform-0.0.5.dist-info/METADATA,sha256=y3dPRoUqXaWAnWip65BJtH82q2LV5E4_y9uJnV_6br0,42563
|
|
12
|
-
robotransform-0.0.5.dist-info/RECORD,,
|
|
File without changes
|