robotransform 0.0.3__tar.gz → 0.0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: robotransform
3
- Version: 0.0.3
3
+ Version: 0.0.5
4
4
  Summary: Perform model transformations for the RoboSapiens project.
5
5
  Keywords: transformation
6
6
  Author: Arkadiusz Michał Ryś
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "robotransform"
7
- version = "0.0.3"
7
+ version = "0.0.5"
8
8
  description="Perform model transformations for the RoboSapiens project."
9
9
  authors = [
10
10
  {name = "Arkadiusz Michał Ryś", email = "Arkadiusz.Michal.Rys@gmail.com"},
@@ -0,0 +1,598 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Type as ClassType, Any, List, Optional, Union
5
+
6
+
7
+ @dataclass
8
+ class ControllerDef:
9
+ name: str
10
+ uses: List[QualifiedName]
11
+ provides: List[QualifiedName]
12
+ requires: List[QualifiedName]
13
+ connections: List[Connection]
14
+ machines: List[Union[StateMachineDef, StateMachineRef]]
15
+ events: List[Event]
16
+ operations: List[Operation]
17
+ variables: List[Variable]
18
+ parent: Any
19
+
20
+
21
+ @dataclass
22
+ class Connection:
23
+ source: QualifiedName
24
+ event_source: QualifiedName
25
+ target: QualifiedName
26
+ event_target: QualifiedName
27
+ asynchronous: bool
28
+ bidirectional: bool
29
+ parent: Any
30
+
31
+
32
+ @dataclass
33
+ class StateMachineRef:
34
+ name: str
35
+ ref: QualifiedName
36
+ parent: Any
37
+
38
+
39
+ @dataclass
40
+ class Operation:
41
+ operation: Union[OperationRef, OperationDef]
42
+ parent: Any
43
+
44
+
45
+ @dataclass
46
+ class OperationRef:
47
+ name: str
48
+ ref: QualifiedName
49
+ parent: Any
50
+
51
+
52
+ @dataclass
53
+ class Variable:
54
+ name: str
55
+ type: Type
56
+ parent: Any
57
+ initial: Optional[Expression] = None
58
+ modifier: Optional[VariableModifier] = None
59
+
60
+
61
+ @dataclass
62
+ class Expression:
63
+ expression: Union[ForAll, Exists, LambdaExp, Iff]
64
+ parent: Any
65
+
66
+
67
+ @dataclass
68
+ class ForAll:
69
+ variables: List[Variable]
70
+ predicate: Expression
71
+ parent: Any
72
+ suchthat: Optional[Expression]
73
+
74
+
75
+ @dataclass
76
+ class Exists:
77
+ variables: List[Variable]
78
+ unique: bool
79
+ predicate: Expression
80
+ parent: Any
81
+ suchthat: Optional[Expression]
82
+
83
+
84
+ @dataclass
85
+ class LambdaExp:
86
+ variables: List[Variable]
87
+ predicate: Expression
88
+ parent: Any
89
+ suchthat: Optional[Expression]
90
+
91
+
92
+ @dataclass
93
+ class Iff:
94
+ left: Implies
95
+ right: List[Implies]
96
+ parent: Any
97
+
98
+
99
+ @dataclass
100
+ class Implies:
101
+ left: Or
102
+ right: List[Or]
103
+ parent: Any
104
+
105
+
106
+ @dataclass
107
+ class Or:
108
+ left: And
109
+ right: List[And]
110
+ parent: Any
111
+
112
+
113
+ @dataclass
114
+ class And:
115
+ left: Not
116
+ right: List[Not]
117
+ parent: Any
118
+
119
+
120
+ @dataclass
121
+ class Not:
122
+ exp: Union[Not, Comp]
123
+ parent: Any
124
+
125
+
126
+ @dataclass
127
+ class Comp:
128
+ left: DefiniteDescription
129
+
130
+ parent: Any
131
+ comp: Optional[Comparison] # TODO Unify these
132
+ right: Optional[DefiniteDescription] # TODO Unify these
133
+ set: Optional[DefiniteDescription] # TODO Unify these
134
+
135
+
136
+ @dataclass
137
+ class DefiniteDescription:
138
+ variables: List[Variable]
139
+ expression: Union[Expression, LetExpression]
140
+ parent: Any
141
+ suchthat: Optional[Expression]
142
+
143
+
144
+ @dataclass
145
+ class Comparison:
146
+ operator: str
147
+ right: DefiniteDescription
148
+ parent: Any
149
+
150
+
151
+ @dataclass
152
+ class LetExpression:
153
+ declarations: List[Declaration]
154
+ expression: Union[LetExpression, IfExpression]
155
+ parent: Any
156
+
157
+
158
+ @dataclass
159
+ class Declaration:
160
+ name: str
161
+ expression: Expression
162
+ parent: Any
163
+
164
+
165
+ @dataclass
166
+ class IfExpression:
167
+ condition: Expression
168
+ ifexp: Expression
169
+ elseexp: Expression
170
+ expression: TypedExpression
171
+ parent: Any
172
+
173
+
174
+ @dataclass
175
+ class TypedExpression:
176
+ expression: PlusMinus
177
+
178
+ parent: Any
179
+ type: Optional[Type]
180
+
181
+
182
+ @dataclass
183
+ class PlusMinus:
184
+ expression: MultDivMod
185
+ right: List[MultDivMod]
186
+ parent: Any
187
+
188
+
189
+ @dataclass
190
+ class MultDivMod:
191
+ expression: CatExp
192
+ right: List[CatExp]
193
+ parent: Any
194
+
195
+
196
+ @dataclass
197
+ class CatExp:
198
+ expression: Neg
199
+ right: List[Neg]
200
+ parent: Any
201
+
202
+
203
+ @dataclass
204
+ class Neg:
205
+ expression: Union[Neg, Selection]
206
+ parent: Any
207
+
208
+
209
+ @dataclass
210
+ class Selection:
211
+ expression: ArrayExp
212
+ member: List[QualifiedName]
213
+ parent: Any
214
+
215
+
216
+ @dataclass
217
+ class ArrayExp:
218
+ expression: CallExp
219
+ parameters: List[Expression]
220
+ parent: Any
221
+
222
+
223
+ @dataclass
224
+ class CallExp:
225
+ expression: Atomic
226
+ args: List[Expression]
227
+ parent: Any
228
+
229
+
230
+ @dataclass
231
+ class Atomic: # TODO Add subs
232
+ value: Union[str, int, float, bool]
233
+ parent: Any
234
+
235
+
236
+ @dataclass
237
+ class Node: # TODO Add subs
238
+ parent: Any
239
+
240
+
241
+ @dataclass
242
+ class Type:
243
+ source: FunctionType
244
+ target: Optional[Type] = None
245
+ parent: Any = None
246
+
247
+ def __repr__(self):
248
+ if self.target:
249
+ return f"{self.source} <-> {self.target}"
250
+ return f"{self.source}"
251
+
252
+ @dataclass
253
+ class Field:
254
+ name: str
255
+ type: Type
256
+ parent: Any
257
+
258
+
259
+ @dataclass
260
+ class RecordType:
261
+ name: str
262
+ fields: List[Field]
263
+ parent: Any
264
+
265
+ @dataclass
266
+ class Parameter:
267
+ name: str
268
+ type: Type
269
+ parent: Any
270
+
271
+ @dataclass
272
+ class Function:
273
+ name: str
274
+ parameters: List[Parameter]
275
+ type: Type
276
+ body: Body
277
+ parent: Any
278
+
279
+
280
+ @dataclass
281
+ class Body:
282
+ elements: List[BodyContent]
283
+ parent: Any
284
+
285
+
286
+ @dataclass
287
+ class BodyContent:
288
+ parent: Any
289
+
290
+
291
+ @dataclass
292
+ class Module:
293
+ name: str
294
+ connections: List[Connection]
295
+ nodes: List[ConnectionNode]
296
+ parent: Any
297
+
298
+
299
+ @dataclass
300
+ class VariableModifier:
301
+ parent: Any
302
+
303
+
304
+ @dataclass
305
+ class Interface:
306
+ name: str
307
+ operations: List[OperationSig]
308
+ events: List[Event]
309
+ parent: Any
310
+ clocks: List[Clock]
311
+ variables: List[Variable]
312
+
313
+
314
+ @dataclass
315
+ class Clock:
316
+ name: str
317
+
318
+
319
+ @dataclass
320
+ class OperationSig:
321
+ name: str
322
+ parameters: List[Parameter]
323
+ terminates: bool
324
+ parent: Any
325
+
326
+
327
+ @dataclass
328
+ class RoboticPlatformDef:
329
+ name: str
330
+ uses: List[QualifiedName]
331
+ provides: List[QualifiedName]
332
+ requires: List[QualifiedName]
333
+ operations: List[OperationSig]
334
+ events: List[Event]
335
+ parent: Any
336
+ variables: List[Variable]
337
+
338
+
339
+ @dataclass
340
+ class OperationDef:
341
+ name: str
342
+ parameters: List[Parameter]
343
+ terminates: str
344
+ preconditions: List[Expression]
345
+ postconditions: List[Expression]
346
+ uses: List[QualifiedName]
347
+ provides: List[QualifiedName]
348
+ variables: List[Variable]
349
+ events: List[Event]
350
+ nodes: List[Node]
351
+ transitions: List[Transition]
352
+ clock: List[Transition]
353
+ parent: Any
354
+
355
+
356
+ @dataclass
357
+ class Package:
358
+ name: QualifiedName
359
+ imports: List[Import]
360
+ controllers: List[ControllerDef]
361
+ modules: List[Module]
362
+ functions: List[Function]
363
+ types: List[RecordType]
364
+ machines: List[StateMachineDef]
365
+ interfaces: List[Interface]
366
+ robots: List[RoboticPlatformDef]
367
+ operations: List[OperationDef]
368
+
369
+
370
+ @dataclass
371
+ class ConnectionNode: # TODO add subs
372
+ parent: Any
373
+
374
+
375
+ @dataclass
376
+ class QualifiedName:
377
+ parts: List[str]
378
+ parent: Any
379
+
380
+ def __hash__(self):
381
+ return hash(str(self.parts))
382
+
383
+ def __repr__(self):
384
+ return "::".join(self.parts)
385
+
386
+
387
+ @dataclass
388
+ class StateMachineDef:
389
+ name: str
390
+ uses: List[QualifiedName]
391
+ provides: List[QualifiedName]
392
+ requires: List[QualifiedName]
393
+ events: List[Event]
394
+ nodes: List[Node]
395
+ transitions: List[Transition]
396
+ clocks: List[Clock]
397
+ parent: Any
398
+ variables: List[Variable]
399
+
400
+
401
+ @dataclass
402
+ class Transition:
403
+ name: str
404
+ source: QualifiedName
405
+ target: QualifiedName
406
+
407
+ reset: List[ClockReset]
408
+
409
+ parent: Any
410
+ trigger: Optional[Trigger]
411
+ deadline: Optional[Expression]
412
+ condition: Optional[ConditionExpr]
413
+ action: Optional[Statement]
414
+
415
+
416
+ @dataclass
417
+ class ConditionExpr: # TODO
418
+ parent: Any
419
+
420
+
421
+ @dataclass
422
+ class Statement:
423
+ statements: List[EndStatement]
424
+ parent: Any
425
+
426
+
427
+ @dataclass
428
+ class EndStatement: # TODO
429
+ parent: Any
430
+ deadline: Optional[Expression]
431
+
432
+
433
+ @dataclass
434
+ class ClockReset:
435
+ clock: QualifiedName
436
+ parent: Any
437
+
438
+
439
+ @dataclass
440
+ class Trigger:
441
+ trigger: Communication
442
+ probability: Expression
443
+ parent: Any
444
+
445
+
446
+ @dataclass
447
+ class CommunicationStmt:
448
+ communication: Communication
449
+ parent: Any
450
+
451
+
452
+ @dataclass
453
+ class Communication:
454
+ event: QualifiedName
455
+ source: QualifiedName
456
+ predicate: List[Expression]
457
+ type: Union[InputType, OutputType, SyncType]
458
+ parent: Any
459
+
460
+
461
+ @dataclass
462
+ class InputType:
463
+ parameter: QualifiedName
464
+ parent: Any
465
+
466
+
467
+ @dataclass
468
+ class OutputType:
469
+ value: CallExp
470
+ parent: Any
471
+
472
+
473
+ @dataclass
474
+ class SyncType:
475
+ value: CallExp
476
+ parent: Any
477
+
478
+
479
+ @dataclass
480
+ class QualifiedNameWithWildcard:
481
+ name: QualifiedName
482
+ parent: Any
483
+
484
+ def __hash__(self):
485
+ return hash(str(self.name))
486
+
487
+ def __repr__(self):
488
+ return str(self.name) + "::*"
489
+
490
+
491
+ @dataclass
492
+ class Import:
493
+ name: QualifiedNameWithWildcard
494
+ parent: Any
495
+
496
+ def __repr__(self):
497
+ return str(self.name)
498
+
499
+
500
+ @dataclass
501
+ class FunctionType:
502
+ source: ProductType
503
+ parent: Any
504
+ target: Optional[FunctionType]
505
+ # added by processor
506
+ source_chain: list = field(default_factory=list)
507
+ final_target: Any = None
508
+
509
+ def __repr__(self):
510
+ if self.target:
511
+ return f"{self.source} -> {self.target}"
512
+ return f"{self.source}"
513
+
514
+
515
+ @dataclass
516
+ class SetType:
517
+ domain: Type
518
+ parent: Any
519
+
520
+
521
+ @dataclass
522
+ class AnyType:
523
+ identifier: str
524
+ parent: Any
525
+
526
+
527
+ @dataclass
528
+ class TypeRef:
529
+ type: Union[SetType, SeqType, AnyType, Type, QualifiedName]
530
+ parent: Any
531
+
532
+ def __repr__(self):
533
+ return f"{self.type}"
534
+
535
+
536
+ @dataclass
537
+ class VectorDef:
538
+ base: Type
539
+ size: int # TODO Add processor to set this to into from Atomic
540
+ parent: Any
541
+
542
+
543
+ @dataclass
544
+ class MatrixDef:
545
+ base: Type
546
+ rows: Atomic
547
+ columns: Atomic
548
+ parent: Any
549
+
550
+
551
+ @dataclass
552
+ class VectorType:
553
+ source: Union[VectorDef, MatrixDef, TypeRef]
554
+ parent: Any
555
+
556
+ def __repr__(self):
557
+ return f"{self.source}"
558
+
559
+
560
+ @dataclass
561
+ class ProductType:
562
+ types: List[Union[VectorType, TypeRef]]
563
+ flat_types: List[VectorType] = field(default_factory=list)
564
+ parent: Any = None
565
+
566
+ def __repr__(self):
567
+ if len(self.types) > 1:
568
+ joined = "*".join(map(str, self.types))
569
+ return f"{joined}"
570
+ return f"{self.types[0]}"
571
+
572
+
573
+ @dataclass
574
+ class SeqType:
575
+ domain: Type
576
+ parent: Any
577
+
578
+ def __repr__(self):
579
+ return f"[{self.domain}]"
580
+
581
+
582
+ @dataclass
583
+ class Event:
584
+ name: str
585
+ broadcast: bool
586
+ type: Type
587
+ parent: Any
588
+
589
+ def __repr__(self):
590
+ return f"Event: {self.name} {self.broadcast, self.type}"
591
+
592
+
593
+ def all_concepts() -> List[ClassType]:
594
+ import inspect
595
+ return [
596
+ obj for _, obj in globals().items()
597
+ if inspect.isclass(obj) and obj.__module__ == __name__
598
+ ]
@@ -0,0 +1,29 @@
1
+ def type_to_port(_type) -> str:
2
+ # TODO this is wrong
3
+ if str(_type) in {"event", }:
4
+ return "event"
5
+ return "data"
6
+
7
+ def type_to_aadl_type(_type) -> str:
8
+ typename = str(_type)
9
+ # Boolean,
10
+ # Character,
11
+ # Float, Float_32, Float_64,
12
+ # Integer, Integer_8, Integer_16, Integer_32, Integer_64,
13
+ # Natural,
14
+ # String,
15
+ # Unsigned_8, Unsigned_16, Unsigned_32, Unsigned_64
16
+ mapping = {
17
+ "boolean": "Base_Types::Boolean",
18
+ "nat" : "Base_Types::Natural",
19
+ "real" : "Base_Types::Float",
20
+ }
21
+ # TODO Seq -> Array[...]
22
+ # TODO Matrix to Array[Array[...]]
23
+ # REASON: AADL does not support variable length arrays
24
+ # TODO Very hacky, not correct
25
+ if typename.startswith("[") and typename.endswith("]"):
26
+ typename = typename[1:-1]
27
+ elif "*" in typename:
28
+ typename = typename.split("*")[0]
29
+ return mapping.get(typename, f"messages::{typename}")
@@ -8,8 +8,9 @@ from jinja2 import Environment, FileSystemLoader, Template
8
8
  import io
9
9
  from typing import Union, Optional, Iterable, Iterator
10
10
 
11
- from robotransform.concepts import all_concepts, RCPackage
12
- from robotransform.filters import typename_to_port
11
+ from robotransform.concepts import all_concepts, Package
12
+ from robotransform.filters import type_to_port, type_to_aadl_type
13
+ from robotransform.processors import processors
13
14
 
14
15
 
15
16
  @dataclass
@@ -28,7 +29,7 @@ class Store:
28
29
  yield item
29
30
  continue
30
31
 
31
- def parse_imports(self, package: RCPackage, parent_path: Path, visited):
32
+ def parse_imports(self, package: Package, parent_path: Path, visited):
32
33
  stack = [package]
33
34
  while stack:
34
35
  package = stack.pop()
@@ -45,7 +46,7 @@ class Store:
45
46
  stack.append(sub_package)
46
47
  return visited
47
48
 
48
- def load(self, imports: bool = True) -> dict[Path, RCPackage]:
49
+ def load(self, imports: bool = True) -> dict[Path, Package]:
49
50
  visited = {}
50
51
  for path in self:
51
52
  package = parse_robochart(path)
@@ -85,11 +86,12 @@ def get_robochart_metamodel(name: str = "robochart.tx"):
85
86
  arklog.debug(f"Loading ({name}) metamodel.")
86
87
  metamodel_path = Path(__file__).resolve().parent / name
87
88
  metamodel = metamodel_from_str(metamodel_path.read_text(), classes=all_concepts(), memoization=True)
89
+ metamodel.register_obj_processors(processors)
88
90
  return metamodel
89
91
 
90
92
 
91
93
  @lru_cache(maxsize=1)
92
- def parse_robochart(source: Path | str) -> RCPackage:
94
+ def parse_robochart(source: Path | str) -> Package:
93
95
  arklog.debug(f"Parsing ({source}).")
94
96
  metamodel = get_robochart_metamodel()
95
97
  data = source.read_text() if isinstance(source, Path) else source
@@ -99,8 +101,9 @@ def parse_robochart(source: Path | str) -> RCPackage:
99
101
  @lru_cache(maxsize=2)
100
102
  def get_template(name: str) -> Template:
101
103
  environment = Environment(loader=FileSystemLoader(Path(__file__).resolve().parent / "templates"))
102
- environment.filters["typename_to_port"] = typename_to_port # For use with pipes
103
- # environment.globals["typename_to_port"] = typename_to_port # For use as a function
104
+ environment.filters["type_to_port"] = type_to_port # For use with pipes
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
104
107
  templates = {
105
108
  "messages": "messages.aadl",
106
109
  "logical": "logical.aadl",
@@ -108,7 +111,7 @@ def get_template(name: str) -> Template:
108
111
  if found := templates.get(name):
109
112
  return environment.get_template(found)
110
113
  else:
111
- raise ValueError(f"No template found for name '{name}'")
114
+ raise ValueError(f"No template found for name ({name}).")
112
115
 
113
116
 
114
117
  def write_output(data: str, output: Optional[Union[io.TextIOBase, Path, str]] = None) -> str:
@@ -122,7 +125,7 @@ def write_output(data: str, output: Optional[Union[io.TextIOBase, Path, str]] =
122
125
  output.write(data)
123
126
  output.flush()
124
127
  else:
125
- raise TypeError(f"Unsupported output type: {type(output)}.")
128
+ raise TypeError(f"Unsupported output type ({type(output)}).")
126
129
  return data
127
130
 
128
131