wirely 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.
Files changed (59) hide show
  1. wirely/__init__.py +406 -0
  2. wirely/__main__.py +45 -0
  3. wirely/ast.py +1135 -0
  4. wirely/block.py +542 -0
  5. wirely/block_type.py +342 -0
  6. wirely/blocks.lark +126 -0
  7. wirely/compiler.py +125 -0
  8. wirely/engine.py +418 -0
  9. wirely/enum.py +15 -0
  10. wirely/example.py +36 -0
  11. wirely/graphviz.py +107 -0
  12. wirely/knx/__init__.py +0 -0
  13. wirely/knx/connection_adapter.py +90 -0
  14. wirely/knx/connection_config.py +152 -0
  15. wirely/lib/abb_jra.wrl +64 -0
  16. wirely/lib/csv.wrl +32 -0
  17. wirely/lib/ext_prog.wrl +12 -0
  18. wirely/lib/gpio.wrl +23 -0
  19. wirely/lib/knx.wrl +80 -0
  20. wirely/lib/memory.wrl +45 -0
  21. wirely/lib/mqtt.wrl +66 -0
  22. wirely/lib/std.wrl +134 -0
  23. wirely/lib/time.wrl +93 -0
  24. wirely/lib/two_n.wrl +111 -0
  25. wirely/misc/__init__.py +0 -0
  26. wirely/misc/service.py +48 -0
  27. wirely/native/__init__.py +74 -0
  28. wirely/native/abb_jra.py +66 -0
  29. wirely/native/csv.py +194 -0
  30. wirely/native/ext_prog.py +77 -0
  31. wirely/native/gpio.py +125 -0
  32. wirely/native/knx.py +455 -0
  33. wirely/native/memory.py +113 -0
  34. wirely/native/mqtt.py +605 -0
  35. wirely/native/std.py +334 -0
  36. wirely/native/test_library.py +14 -0
  37. wirely/native/time.py +359 -0
  38. wirely/native/two_n.py +632 -0
  39. wirely/node.py +125 -0
  40. wirely/parser.py +175 -0
  41. wirely/program.py +155 -0
  42. wirely/run.py +143 -0
  43. wirely/service.py +65 -0
  44. wirely/test.py +569 -0
  45. wirely/time.py +172 -0
  46. wirely/two_n/__init__.py +0 -0
  47. wirely/two_n/cert.py +126 -0
  48. wirely/two_n/client.py +402 -0
  49. wirely/two_n/fake_server.py +415 -0
  50. wirely/two_n/grab_images.py +146 -0
  51. wirely/types.py +522 -0
  52. wirely/util.py +111 -0
  53. wirely/value.py +163 -0
  54. wirely-0.1.0.dist-info/METADATA +94 -0
  55. wirely-0.1.0.dist-info/RECORD +59 -0
  56. wirely-0.1.0.dist-info/WHEEL +5 -0
  57. wirely-0.1.0.dist-info/entry_points.txt +2 -0
  58. wirely-0.1.0.dist-info/licenses/LICENSE +21 -0
  59. wirely-0.1.0.dist-info/top_level.txt +1 -0
wirely/block.py ADDED
@@ -0,0 +1,542 @@
1
+ import abc
2
+
3
+ import wirely as blocks
4
+ from wirely.util import check_parameters
5
+
6
+ # TODO: Rename this to BlockInstantiation or BlockUsage?
7
+ # TODO: Probably Input, Output, StateVariable etc. should be moved out of this and only exist in BlockType
8
+ class Block(blocks.Node):
9
+ def __init__(self, graph, *, name, block_type, par_values, instantiation):
10
+ super().__init__(graph=graph, name=name)
11
+
12
+ self.block_type = block_type
13
+ self.par_values = par_values
14
+ self.instantiation = instantiation
15
+ # TODO: Clean up
16
+ for par in self.par_values:
17
+ val = self.par_values[par]
18
+ if not isinstance(val, blocks.ValueParameter) and not isinstance(val, blocks.Value) and not isinstance(val, blocks.Type):
19
+ raise Exception(f'Got invalid parameter value: {val}')
20
+ # TODO: Also check for contains_parameters? When should this be done?
21
+ # if val.contains_parameters:
22
+ # raise Exception(f'Got parameter value {val} contains parameters')
23
+
24
+ # TODO: A lot of this stuff should be moved to BlockType, instead the Block instance should only store the connections to the BlockType's inputs and from the BlockType's outputs
25
+ self.block_inputs = []
26
+ self.block_outputs = []
27
+ self.block_inputs_byname = {}
28
+ self.block_outputs_byname = {}
29
+ self.block_temporaries = []
30
+ self.block_statevars = []
31
+ self.block_procedures = []
32
+ self.last_proc_id = 0
33
+
34
+ if self.name in self.graph.blocks:
35
+ raise Exception(f'Duplicate block name {self.name!r}')
36
+ self.graph.blocks[self.name] = self
37
+
38
+ def __repr__(self):
39
+ # return f"{type(self).__name__}{{{self.graph}.{self.name}}}"
40
+ return f"{self.graph}.{self.name}[{type(self).__name__}]"
41
+
42
+ def __str__(self):
43
+ return f"{self.graph}.{self.name}"
44
+
45
+ def validate(self):
46
+ for input in self.all_block_inputs:
47
+ if input.connected_source is None:
48
+ # TODO: Hack
49
+ if isinstance(input.block, blocks.BlockOutput):
50
+ continue
51
+ raise Exception(f'Input {self.graph}.{self.name}.{input.name} is not connected')
52
+
53
+ for output in self.block_outputs:
54
+ if output.temporary.producer is None:
55
+ # TODO: Hack
56
+ if isinstance(output.temporary.block, blocks.BlockInput):
57
+ continue
58
+ raise Exception(f'Output {self.graph}.{self.name}.{output.name} has no producer')
59
+
60
+ def create_native_state(self, path, engine, static_block_context):
61
+ if path[-1] != self:
62
+ raise Exception('path[-1] != self')
63
+ # TODO
64
+ if hasattr(self, 'block_type') and hasattr(self.block_type, 'is_native'):
65
+ if self.block_type.is_native:
66
+ # print('QQQ', self.name)
67
+ return self.native_class(path, engine, static_block_context=static_block_context)
68
+ else:
69
+ # print('WWW', self.name)
70
+ pass
71
+
72
+ return None
73
+
74
+ # TODO: Clean up
75
+ @property
76
+ def all_block_inputs(self):
77
+ res = []
78
+ for input in self.block_inputs:
79
+ if input.is_list:
80
+ # TODO: Currently the individual entries of the list are already in block_inputs
81
+ # res += input.members
82
+ pass
83
+ else:
84
+ res.append(input)
85
+ return res
86
+
87
+ # TODO: Rename
88
+ # TODO: Must probably be cleaned up to allow multiple instantiations of the same block
89
+ # path: A tuple which contains the name of the block being instantiated
90
+ def instantiate(self, *, singletons, add_var, variable_map, state_map_new, all_variables, state_map_changed, state_map, state_variables, instances, path, parent_instance):
91
+ if self.block_type.is_singleton:
92
+ if self.block_type in singletons:
93
+ return
94
+
95
+ # TODO: This probably should not need an instance of Block here
96
+ singletons[self.block_type] = self
97
+
98
+ # TODO: This is an ugly hack, remove
99
+ if hasattr(self.block_type, 'singleton_instance'):
100
+ raise Exception("hasattr(self.block_type, 'singleton_instance')")
101
+ # print(f'Using {self} as instance for {self.block_type}')
102
+ self.block_type.singleton_instance = self
103
+
104
+ path = (self.block_type,)
105
+
106
+ if self.block_type.is_singleton:
107
+ instance = blocks.BlockInstance(self.block_type, parent_instance=None)
108
+ else:
109
+ instance = blocks.BlockInstance(self, parent_instance=parent_instance)
110
+
111
+ if path != instance.path:
112
+ raise Exception(f'path {path} != instance.path {instance.path}')
113
+
114
+ if instance.path in instances:
115
+ raise Exception(f'Duplicate path {path}')
116
+ instances[instance.path] = instance
117
+
118
+ for name, child_block in self.block_type.blocks.items():
119
+ child_path = path + (child_block,)
120
+ child_block.instantiate(singletons=singletons, add_var=add_var, variable_map=variable_map, state_map_new=state_map_new, all_variables=all_variables, state_map_changed=state_map_changed, state_map=state_map, state_variables=state_variables, instances=instances, path=child_path, parent_instance=instance)
121
+
122
+ # TODO: Clean up
123
+ # path_prefix = '.'.join([block.name for block in path])
124
+ path_prefix = '.'.join([(block.name if isinstance(block, blocks.Block) else block.name.id_str) for block in path])
125
+ for state_var in self.block_statevars:
126
+ v = blocks.Variable(path_prefix + '.' + state_var.name + '.new', state_var.var_type)
127
+ state_map_new[path, state_var] = v
128
+ all_variables.append(v)
129
+
130
+ v = blocks.Variable(path_prefix + '.' + state_var.name + '.changed', blocks.types.boolean)
131
+ state_map_changed[path, state_var] = v
132
+ all_variables.append(v)
133
+
134
+ v = blocks.Variable(path_prefix + '.' + state_var.name, state_var.var_type)
135
+ state_map[path, state_var] = v
136
+ state_variables.append(v)
137
+ for var in self.all_block_inputs:
138
+ if var.var_type is None:
139
+ continue
140
+ variable_map[path, var.var_identifier] = add_var(*blocks.resolve_variable(path, var))
141
+ for var in self.block_outputs:
142
+ if var.var_type is None:
143
+ continue
144
+ variable_map[path, var.var_identifier] = add_var(*blocks.resolve_variable(path, var))
145
+ for var in self.block_temporaries:
146
+ variable_map[path, var.var_identifier] = add_var(*blocks.resolve_variable(path, var))
147
+
148
+ # TODO: Probably should be merged into instantiate()
149
+ def get_block_procedures_paths(self, prefix):
150
+ # TODO: Handle singletons properly?
151
+ res = [(blocks.path_resolve_singleton(prefix + (self,)), proc) for proc in self.block_procedures]
152
+ for child_block in self.block_type.blocks.values():
153
+ res += child_block.get_block_procedures_paths(prefix + (self,))
154
+ return res
155
+
156
+ # TODO: Probably should be merged into instantiate()
157
+ def get_all_block_paths(self, prefix):
158
+ # TODO: Handle singletons properly?
159
+ res = [blocks.path_resolve_singleton(prefix + (self,))]
160
+ for child_block in self.block_type.blocks.values():
161
+ res += child_block.get_all_block_paths(prefix + (self,))
162
+ return res
163
+
164
+ class Member(abc.ABC):
165
+ def __init__(self, block: 'Block', name: str):
166
+ if not isinstance(block, Block):
167
+ raise Exception('block parameter is not a Block')
168
+ if not isinstance(name, str):
169
+ raise Exception('name parameter is not a str')
170
+ name = str(name)
171
+
172
+ self.block = block
173
+ self.name = name
174
+
175
+ def __repr__(self):
176
+ return f"{self.block}.{self.name}"
177
+
178
+ # TODO: Move out of block class / Remove Member parent?
179
+ class Source(Member, abc.ABC):
180
+ @property
181
+ @abc.abstractmethod
182
+ def temporary(self):
183
+ ...
184
+
185
+ # TODO: Move out of block class / Remove Member parent?
186
+ class Target(Member, abc.ABC):
187
+ pass
188
+
189
+ # TODO: Handle var_type == None better
190
+ # TODO: Clean up, move more functionality to BlockInput
191
+ class Input(Source):
192
+ def __init__(self, block: 'Block', name: str, is_list: bool, var_type: blocks.types.Type, *, block_input: blocks.BlockInput):
193
+ Block.Member.__init__(self, block, name)
194
+ if not isinstance(is_list, bool):
195
+ raise Exception('is_list parameter is not of type bool')
196
+ if var_type is not None and not isinstance(var_type, blocks.types.Type):
197
+ raise Exception('var_type parameter is not a Type')
198
+
199
+ self.is_list = bool(is_list)
200
+ self.var_type = var_type
201
+ self.block_input = block_input
202
+
203
+ self.conn_spec = self.block_input.conn_spec
204
+
205
+ if isinstance(self.conn_spec, blocks.ConnectorSpecificationData):
206
+ if self.conn_spec.kind_spec.kind == blocks.ConnectionKind.Value:
207
+ self.impl_var_type = self.var_type
208
+ elif self.conn_spec.kind_spec.kind == blocks.ConnectionKind.Event:
209
+ self.impl_var_type = blocks.types.TypeOption(self.var_type)
210
+ else:
211
+ raise Exception(f'Unknown ConnectionKind: {self.conn_spec.kind_spec.kind}')
212
+ else:
213
+ # TODO: ?
214
+ self.impl_var_type = None
215
+
216
+ if self.is_list:
217
+ self.members = []
218
+ else:
219
+ self.connected_source = None
220
+
221
+ self.block.block_inputs.append(self)
222
+ if self.name in self.block.block_inputs_byname:
223
+ raise Exception(f'Duplicate input name {name!r}')
224
+ self.block.block_inputs_byname[self.name] = self
225
+
226
+ def __repr__(self):
227
+ return f"{self.block}.{self.name}"
228
+
229
+ @property
230
+ def temporary(self):
231
+ if self.is_list:
232
+ raise Exception('Trying to get temporary for list')
233
+ if self.connected_source is None:
234
+ raise Exception(f'{self} is not connected')
235
+ # TODO: Cache multiple follows?
236
+ return self.connected_source.temporary
237
+
238
+ def connect(self, output):
239
+ # TODO: Clean up class structure for value sources / targets
240
+ if not isinstance(output, Block.Output) and not isinstance(output, blocks.BlockInput) and not isinstance(output, blocks.BlockStateVariable) and not isinstance(output, blocks.BlockTemporaryVariable):
241
+ raise Exception('output parameter value is not an Output instance and not a BlockInput, BlockStateVariable or BlockTemporaryVariable')
242
+ if self.is_list:
243
+ # TODO: Clean up
244
+ # TODO: What should be used for block_input here?
245
+ input = Block.Input(self.block, f'{self.name}.{len(self.members)}', False, self.var_type, block_input=self)
246
+ input.connect(output)
247
+ self.members.append(input)
248
+ else:
249
+ if self.connected_source is not None:
250
+ raise Exception(f'{self} is already connected to {self.connected_source}, trying to connect to {output}')
251
+
252
+ self.connected_source = output
253
+
254
+ # TODO: Remove and replace with self, Input should contains a reference to BlockType, not to Block
255
+ @property
256
+ def var_identifier(self):
257
+ return 'INP ' + self.block.block_type.name.id_str + '.' + self.name
258
+
259
+ # TODO: Handle var_type == None better
260
+ # TODO: Clean up, move more functionality to BlockOutput
261
+ class Output(Target):
262
+ # TODO: Allow creating Output without Temporary?
263
+ def __init__(self, block: 'Block', name: str, var_type: blocks.types.Type, input_dependencies=[], *, block_output: blocks.BlockOutput):
264
+ Block.Member.__init__(self, block, name)
265
+ if var_type is not None and not isinstance(var_type, blocks.types.Type):
266
+ raise Exception('var_type parameter is not a Type')
267
+
268
+ self.var_type = var_type
269
+ self.block_output = block_output
270
+
271
+ self.conn_spec = self.block_output.conn_spec
272
+
273
+ if isinstance(self.conn_spec, blocks.ConnectorSpecificationData):
274
+ if self.conn_spec.kind_spec.kind == blocks.ConnectionKind.Value:
275
+ self.impl_var_type = self.var_type
276
+ elif self.conn_spec.kind_spec.kind == blocks.ConnectionKind.Event:
277
+ self.impl_var_type = blocks.types.TypeOption(self.var_type)
278
+ else:
279
+ raise Exception(f'Unknown ConnectionKind: {self.conn_spec.kind_spec.kind}')
280
+ else:
281
+ # TODO: ?
282
+ self.impl_var_type = None
283
+
284
+ self.input_dependencies = []
285
+ for dependency in input_dependencies:
286
+ if not isinstance(dependency, Block.Input):
287
+ raise Exception('input_dependencies parameter value is not an Input instance')
288
+ if dependency.block != self.block:
289
+ raise Exception('input_dependencies parameter value is for another block')
290
+ self.input_dependencies.append(dependency)
291
+
292
+ if self.var_type is not None:
293
+ self.temporary = Block.Temporary(block, name + '_val', var_type, impl_var_type=self.impl_var_type)
294
+ # TODO: Hack
295
+ self.orig_temporary = self.temporary
296
+
297
+ self.block.block_outputs.append(self)
298
+ if self.name in self.block.block_outputs_byname:
299
+ raise Exception(f'Duplicate output name {name!r}')
300
+ self.block.block_outputs_byname[self.name] = self
301
+
302
+ @property
303
+ def name_desc(self):
304
+ if self.name == '':
305
+ return 'implicit output'
306
+ else:
307
+ return self.name
308
+
309
+ def __repr__(self):
310
+ return f"{self.block}.{self.name}"
311
+
312
+ # TODO: Remove and replace with self, Output should contains a reference to BlockType, not to Block
313
+ @property
314
+ def var_identifier(self):
315
+ return 'OUT ' + self.block.block_type.name.id_str + '.' + self.name
316
+
317
+ # TODO: Allow both temporaries and output values to be references to other values
318
+ class Temporary(Source, Target):
319
+ def __init__(self, block: 'Block', name: str, var_type: blocks.types.Type, *, impl_var_type):
320
+ Block.Member.__init__(self, block, name)
321
+ if not isinstance(var_type, blocks.types.Type):
322
+ raise Exception('var_type parameter is not a Type')
323
+
324
+ self.var_type = var_type
325
+
326
+ self.impl_var_type = impl_var_type
327
+
328
+ self.producer = None
329
+
330
+ self.block.block_temporaries.append(self)
331
+
332
+ def __repr__(self):
333
+ return f"{self.block}.{self.name}"
334
+
335
+ @property
336
+ def temporary(self):
337
+ return self
338
+
339
+ # TODO: Remove and replace with self, Temporary should contains a reference to BlockType, not to Block
340
+ @property
341
+ def var_identifier(self):
342
+ return 'TEMP ' + self.block.block_type.name.id_str + '.' + self.name
343
+
344
+ class StateVariable(Source, Target):
345
+ def __init__(self, block: 'Block', name: str, var_type: blocks.types.Type, initial_value):
346
+ Block.Member.__init__(self, block, name)
347
+ if not isinstance(var_type, blocks.types.Type):
348
+ raise Exception('var_type parameter is not a Type')
349
+
350
+ self.var_type = var_type
351
+ self.initial_value = self.var_type.verify_value(initial_value)
352
+
353
+ self.impl_var_type = self.var_type
354
+
355
+ self.producer = None
356
+
357
+ self.block.block_statevars.append(self)
358
+
359
+ def __repr__(self):
360
+ return f"StateVariable[{self}]"
361
+
362
+ def __str__(self):
363
+ return f"{self.block}.{self.name}"
364
+
365
+ # TODO
366
+ @property
367
+ def temporary(self):
368
+ return self
369
+
370
+ class Procedure:
371
+ # TODO: Make name mandatory
372
+ def __init__(self, block: 'Block', dependencies, results, impl, can_trigger=False, name=None, *, static_context, declaration_procedure):
373
+ if not isinstance(block, Block):
374
+ raise Exception('block parameter is not a Block')
375
+
376
+ self.block = block
377
+ self.name = name
378
+ self.declaration_procedure = declaration_procedure
379
+ # TODO: Is this a complete static context? Probably not because the context might also depend on the parameters to the current block. Move this somewhere else?
380
+ self.static_context = static_context
381
+
382
+ self.block.last_proc_id += 1
383
+ self.id = self.block.last_proc_id
384
+
385
+ self.dependencies = []
386
+ for dependency in dependencies:
387
+ if not isinstance(dependency, Block.Source):
388
+ raise Exception('dependencies parameter value is not an Input or Temporary instance')
389
+ # TODO: Clean up inheritance
390
+ # TODO: Allow depending on the new value of the state variable?
391
+ # TODO: Also make dependency on old value explicit?
392
+ if isinstance(dependency, Block.StateVariable):
393
+ raise Exception('dependencies parameter value is a StateVariable instance')
394
+ # TODO: Allow dependencies on other blocks? Probably yes. Maybe check where dependency.block is a child of the current block?
395
+ # if dependency.block != self.block:
396
+ # raise Exception('dependencies parameter value is for another block')
397
+ self.dependencies.append(dependency)
398
+
399
+ self.results = []
400
+ for result in results:
401
+ if not isinstance(result, Block.Target):
402
+ raise Exception(f'results parameter value is not an Output or Temporary instance: {type(result)}')
403
+ if result.block != self.block:
404
+ raise Exception('results parameter value is for another block')
405
+ self.results.append(result)
406
+
407
+ # TODO: whether dependencies of output include required inputs as dependencies
408
+
409
+ # TODO: Clean up temporary / output stuff
410
+ if result.temporary.producer is not None:
411
+ raise Exception(f'{result} already has producer {result.temporary.producer}, got new producer {self}')
412
+ # print(f'Setting result for {result} / {result.temporary}')
413
+ result.temporary.producer = self
414
+
415
+ self.impl = impl
416
+ self.can_trigger = can_trigger
417
+
418
+ self.block.block_procedures.append(self)
419
+
420
+ def __repr__(self):
421
+ if self.name is not None:
422
+ return f"{self.block}.{self.name}"
423
+ else:
424
+ return f"{self.block}.proc{self.id}"
425
+
426
+ # TODO: Remove and replace with self, Procedure should contains a reference to BlockType, not to Block
427
+ @property
428
+ def proc_identifier(self):
429
+ return 'PROC ' + self.block.block_type.name.id_str + '.' + self.name
430
+
431
+ class BlockInstance(blocks.NodeInstance):
432
+ @check_parameters
433
+ def __init__(self, block, parent_instance):
434
+ if isinstance(block, blocks.Block):
435
+ super().__init__(block, parent_instance=parent_instance)
436
+ # Alias for self.node
437
+ self.block = block
438
+
439
+ self.is_singleton = False
440
+
441
+ self.block_type = self.block.block_type
442
+ elif isinstance(block, blocks.BlockType):
443
+ if parent_instance != None:
444
+ raise Exception('parent_instance != None')
445
+ # TODO: Clean up? Create separate type?
446
+ super().__init__(None, parent_instance=None)
447
+ self.block = None
448
+
449
+ self.is_singleton = True
450
+
451
+ self.block_type = block
452
+ else:
453
+ raise Exception(f'Unknown value for block: {block}')
454
+
455
+ if self.is_singleton:
456
+ self.parameter_values = {}
457
+ else:
458
+ self.parameter_values = dict(self.block.par_values)
459
+
460
+ # Resolve parameter values from parent
461
+ parent_parameter_values = None
462
+ if self.parent_instance is not None:
463
+ parent_parameter_values = self.parent_instance.parameter_values
464
+ # TODO: Do this properly, handle nested parameters etc.
465
+ for key in list(self.parameter_values):
466
+ # TODO: Clean up
467
+ val = self.parameter_values[key]
468
+ if isinstance(val, blocks.TypeParameter) or isinstance(val, blocks.ValueParameter):
469
+ par = val.parameter
470
+ if par not in parent_parameter_values:
471
+ if key.is_optional:
472
+ # TODO: Clean this up. Store a value like None in this case?
473
+ del self.parameter_values[key]
474
+ continue
475
+ raise Exception(f'Could not find parameter {par.name} in parent')
476
+ # TODO: Check type etc.
477
+ new_val = parent_parameter_values[par]
478
+ # print('QQQ', val, new_val)
479
+ # TODO: Properly handle type parameters
480
+ if isinstance(val, blocks.TypeParameter):
481
+ if not isinstance(val, blocks.Type):
482
+ # TODO: hints?
483
+ raise blocks.ProgramError(val.parameter, f'[TODO: Error message] Got parameter of type {new_val.value_type} for {val.parameter.name} where type parameter was expected')
484
+ else:
485
+ if val.value_type != new_val.value_type:
486
+ # TODO: Fix error message / hints
487
+ hints = [
488
+ blocks.CompilerHint(val.parameter, 'Parameter is declared here'),
489
+ ]
490
+ raise blocks.ProgramError(val.parameter, f'[TODO: Error message] Got parameter of type {new_val.value_type} for {val.parameter.name} where parameter of type {val.value_type} expected', hints=hints)
491
+ # TODO: Check whether this is fully resolved
492
+ self.parameter_values[key] = new_val
493
+
494
+ # TODO: Clean this up. Probably other places should also used the parents' parameters
495
+ # TODO: Also, probably make sure that no parameters have been resolved here? Or should the be resolved as far as possible? Currently they are resolved in a weird way (a direct parameter might be resolved while the same parameter in a function call is not).
496
+ all_par_values = dict(self.parameter_values)
497
+ next_parent = self.parent_instance
498
+ while next_parent is not None:
499
+ for key in next_parent.parameter_values:
500
+ if key not in all_par_values:
501
+ all_par_values[key] = next_parent.parameter_values[key]
502
+ next_parent = next_parent.parent_instance
503
+
504
+ # print(f'Resolving while creating BlockInstance: {self.parameter_values} /// {all_par_values}')
505
+ # TODO: Store this?
506
+ parameter_values_resolved = {key: value.resolve_self(par_values=all_par_values) for key, value in self.parameter_values.items()}
507
+
508
+ parameter_values_bystr = {key.name.id_str: value for key, value in parameter_values_resolved.items()}
509
+ native_class = self.block_type.native_class
510
+ parsed_native_instance = None
511
+
512
+ # TODO: Pass this differently
513
+ parameter_values_bystr[''] = {}
514
+ if self.block is None:
515
+ # Singleton
516
+ parameter_values_bystr['']['BlkFilename'] = None
517
+ else:
518
+ # TODO: Get the filename from somewhere else?
519
+ parameter_values_bystr['']['BlkFilename'] = self.block.instantiation.source_position.filename
520
+
521
+ if native_class is not None:
522
+ # TODO: Make sure that this is executed if a native class exists even if there is no native procedure in the block and the block has no native state?
523
+ data_type = native_class.native_block_data_type
524
+ if data_type is not None:
525
+ try:
526
+ parsed_native_instance = data_type.create(parameter_values=parameter_values_bystr)
527
+ except blocks.ProgramError as e:
528
+ raise
529
+ except Exception as e:
530
+ raise blocks.InternalCompilerError(block.instantiation, e, msg=f'Error while parsing parameters: {e}')
531
+ self.static_context = blocks.StaticBlockContext(parameter_values=parameter_values_bystr, parsed_native_instance=parsed_native_instance)
532
+
533
+ @property
534
+ def path(self):
535
+ if self.is_singleton:
536
+ return (self.block_type,)
537
+
538
+ if self.parent_instance is None:
539
+ base_path = ()
540
+ else:
541
+ base_path = self.parent_instance.path
542
+ return base_path + (self.block,)