statable 3.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 (117) hide show
  1. codegen/__init__.py +38 -0
  2. codegen/c_code_generator.py +1752 -0
  3. codegen/code_merger.py +371 -0
  4. codegen/code_templates.py +509 -0
  5. codegen/config.py +167 -0
  6. codegen/enum_generator.py +377 -0
  7. codegen/event_queue_generator.py +303 -0
  8. codegen/interrupt_generator.py +345 -0
  9. codegen/naming_convention.py +171 -0
  10. codegen/osal_generator.py +282 -0
  11. codegen/role_function_generator.py +1244 -0
  12. codegen/sample_data.py +269 -0
  13. codegen/state_actions_generator.py +395 -0
  14. codegen/struct_generator.py +721 -0
  15. codegen/timer_generator.py +299 -0
  16. codegen/transition_generator.py +907 -0
  17. codegen/type_mapper.py +69 -0
  18. codegen/validate/__init__.py +38 -0
  19. codegen/validate/change_actions.py +90 -0
  20. codegen/validate/change_applier.py +416 -0
  21. codegen/validate/clipboard_manager.py +47 -0
  22. codegen/validate/data/__init__.py +30 -0
  23. codegen/validate/data/action_definitions.py +200 -0
  24. codegen/validate/data/keywords.py +46 -0
  25. codegen/validate/data/prompt_templates.py +176 -0
  26. codegen/validate/data/validation_rules.py +205 -0
  27. codegen/validate/items/__init__.py +30 -0
  28. codegen/validate/items/base_validator.py +25 -0
  29. codegen/validate/items/cell_validator.py +275 -0
  30. codegen/validate/items/custom_type_validator.py +75 -0
  31. codegen/validate/items/event_validator.py +78 -0
  32. codegen/validate/items/flag_validator.py +74 -0
  33. codegen/validate/items/interrupt_validator.py +75 -0
  34. codegen/validate/items/queue_validator.py +73 -0
  35. codegen/validate/items/role_function_validator.py +175 -0
  36. codegen/validate/items/state_validator.py +88 -0
  37. codegen/validate/items/timer_validator.py +120 -0
  38. codegen/validate/items/transition_validator.py +113 -0
  39. codegen/validate/items/variable_validator.py +132 -0
  40. codegen/validate/logger.py +52 -0
  41. codegen/validate/models.py +177 -0
  42. codegen/validate/prompt_generator.py +724 -0
  43. codegen/validate/response_parser.py +154 -0
  44. codegen/validate/response_validator.py +275 -0
  45. codegen/validate/validation_dialog.py +322 -0
  46. codegen/validate/validator.py +94 -0
  47. codegen/variable_generator.py +419 -0
  48. statable/__init__.py +71 -0
  49. statable/__main__.py +49 -0
  50. statable/cli.py +251 -0
  51. statable/global_defs.py +256 -0
  52. statable/mermaid_gen.py +144 -0
  53. statable/model.py +426 -0
  54. statable/parser.py +64 -0
  55. statable/sample_data.py +435 -0
  56. statable/shared/__init__.py +24 -0
  57. statable/shared/condition_library.py +63 -0
  58. statable/shared/literal_library.py +66 -0
  59. statable/shared/role_function_library.py +150 -0
  60. statable/state_machine.py +121 -0
  61. statable/xml_io.py +1164 -0
  62. statable-3.1.0.dist-info/METADATA +151 -0
  63. statable-3.1.0.dist-info/RECORD +117 -0
  64. statable-3.1.0.dist-info/WHEEL +5 -0
  65. statable-3.1.0.dist-info/entry_points.txt +2 -0
  66. statable-3.1.0.dist-info/top_level.txt +3 -0
  67. statable_gui/__init__.py +23 -0
  68. statable_gui/action_edit_dialog.py +214 -0
  69. statable_gui/code_generation_dialog.py +486 -0
  70. statable_gui/code_generation_settings_dialog.py +522 -0
  71. statable_gui/common_widgets.py +537 -0
  72. statable_gui/condition_builder_dialog.py +500 -0
  73. statable_gui/condition_edit_dialog.py +123 -0
  74. statable_gui/condition_template_dialog.py +58 -0
  75. statable_gui/config.py +21 -0
  76. statable_gui/dialogs.py +439 -0
  77. statable_gui/event_definition_dialog.py +605 -0
  78. statable_gui/event_delivery_settings_dialog.py +191 -0
  79. statable_gui/event_queue_dialog.py +245 -0
  80. statable_gui/global_defs.py +167 -0
  81. statable_gui/global_defs_dialog.py +796 -0
  82. statable_gui/i18n/__init__.py +118 -0
  83. statable_gui/interrupt_handler_edit_dialog.py +810 -0
  84. statable_gui/layer_settings_dialog.py +180 -0
  85. statable_gui/libcntrl/__init__.py +23 -0
  86. statable_gui/libcntrl/condition_library.py +13 -0
  87. statable_gui/libcntrl/literal_library.py +13 -0
  88. statable_gui/libcntrl/literal_management_dialog.py +185 -0
  89. statable_gui/libcntrl/role_function_edit_dialog.py +145 -0
  90. statable_gui/libcntrl/role_function_library.py +13 -0
  91. statable_gui/literal_definition_dialog.py +62 -0
  92. statable_gui/logger.py +83 -0
  93. statable_gui/main_window.py +1380 -0
  94. statable_gui/matrix_table.py +413 -0
  95. statable_gui/preference_keys.py +18 -0
  96. statable_gui/preferences.py +74 -0
  97. statable_gui/role_function_dialog.py +244 -0
  98. statable_gui/sample_data.py +11 -0
  99. statable_gui/state_actions_dialog.py +398 -0
  100. statable_gui/symbol_picker.py +170 -0
  101. statable_gui/traceball.py +37 -0
  102. statable_gui/transition_editor_direct/__init__.py +15 -0
  103. statable_gui/transition_editor_direct/actions_tab.py +856 -0
  104. statable_gui/transition_editor_direct/code_widget.py +344 -0
  105. statable_gui/transition_editor_direct/coverage_analyzer.py +163 -0
  106. statable_gui/transition_editor_direct/dialog.py +335 -0
  107. statable_gui/transition_editor_direct/draft.py +270 -0
  108. statable_gui/transition_editor_direct/edit_dialogs.py +160 -0
  109. statable_gui/transition_editor_direct/overview_tab.py +173 -0
  110. statable_gui/transition_editor_direct/palette_widget.py +233 -0
  111. statable_gui/transition_editor_direct/relations_edit_dialog.py +156 -0
  112. statable_gui/transition_editor_direct/relations_tab.py +230 -0
  113. statable_gui/transition_editor_direct/system_global_dialog.py +52 -0
  114. statable_gui/transition_editor_direct/transition_actions_dialog.py +109 -0
  115. statable_gui/transition_editor_direct/transitions_tab.py +620 -0
  116. statable_gui/validation_dialog.py +285 -0
  117. statable_gui/widgets.py +1315 -0
@@ -0,0 +1,377 @@
1
+ # codegen/enum_generator.py
2
+ """
3
+ C enum code generation module (multi-layer state machine support)
4
+
5
+ [v1.5 fix]
6
+ - generate_event_enum: filter out empty-name events from the main loop
7
+ (NONE is already handled at the top, preventing duplicate definitions)
8
+ """
9
+
10
+ import sys
11
+ import os
12
+ import logging
13
+ from string import Template
14
+ from typing import Dict, List, Any, Optional
15
+
16
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
17
+
18
+ from statable.model import State, Event, StateType, EventKind
19
+ from statable.global_defs import EventFlag
20
+
21
+ try:
22
+ from .naming_convention import CNamingConvention
23
+ from .code_templates import CodeTemplates
24
+ except ImportError:
25
+ from naming_convention import CNamingConvention
26
+ from code_templates import CodeTemplates
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+
31
+ class CEnumGenerator:
32
+ """C enum code generation class (multi-layer state machine support)"""
33
+
34
+ ENUM_TEMPLATES = {
35
+ 'section_comment': Template(
36
+ '/* $description */\n'
37
+ ),
38
+ 'enum_start': 'typedef enum {\n',
39
+ 'value_with_comment': Template(
40
+ ' $name = $value, /* $comment */\n'
41
+ ),
42
+ 'value': Template(
43
+ ' $name = $value,\n'
44
+ ),
45
+ 'max_value': Template(
46
+ ' $name /* element count (for system use) */\n'
47
+ ),
48
+ 'enum_end': Template(
49
+ '} $type_name;\n'
50
+ ),
51
+ }
52
+
53
+ LAYER_TYPE_NAMES = {
54
+ 'state': {
55
+ 'value_prefix': 'STATE',
56
+ 'type_suffix': '_t',
57
+ 'max_suffix': '_MAX',
58
+ 'none_value': None,
59
+ },
60
+ 'event': {
61
+ 'value_prefix': 'EVENT',
62
+ 'type_suffix': '_t',
63
+ 'max_suffix': '_MAX',
64
+ 'none_value': 'NONE',
65
+ },
66
+ 'flag': {
67
+ 'value_prefix': 'FLAG',
68
+ 'type_suffix': '_t',
69
+ 'max_suffix': '_MAX',
70
+ 'none_value': None,
71
+ },
72
+ }
73
+
74
+ COMMENT_FORMATS = {
75
+ 'state': {
76
+ 'description_suffix': None,
77
+ 'type_suffix': 'Type: {type_name}',
78
+ 'title_prefix': 'Title: ',
79
+ },
80
+ 'event': {
81
+ 'description_suffix': None,
82
+ 'kind_suffix': 'Kind: {kind_name}',
83
+ 'title_prefix': 'Title: ',
84
+ },
85
+ 'flag': {
86
+ 'description_suffix': None,
87
+ 'title_prefix': 'Title: ',
88
+ },
89
+ }
90
+
91
+ def __init__(self):
92
+ self.naming = CNamingConvention()
93
+ self.templates = CodeTemplates()
94
+ self.strings = self.templates.STRINGS
95
+ self.formats = self.templates.FORMATS
96
+ self.layer_name: str = ""
97
+
98
+ def set_layer(self, layer_name: str):
99
+ self.layer_name = layer_name
100
+ logger.debug(f"CEnumGenerator.set_layer: layer_name='{layer_name}'")
101
+
102
+ def _log_debug(self, message, level='debug'):
103
+ log_func = getattr(logger, level, logger.debug)
104
+ log_func(message)
105
+
106
+ def _state_value_name(self, state_name: str) -> str:
107
+ pascal = self.naming.to_pascal_case(state_name) if state_name else "Unknown"
108
+ if self.layer_name:
109
+ return f"STATE_{self.layer_name}_{pascal}"
110
+ return f"STATE_{pascal}"
111
+
112
+ def _event_value_name(self, event_name: str) -> str:
113
+ if not event_name:
114
+ upper = "NONE"
115
+ else:
116
+ upper = self.naming.to_upper_snake(event_name)
117
+ if self.layer_name:
118
+ return f"EVENT_{self.layer_name}_{upper}"
119
+ return f"EVENT_{upper}"
120
+
121
+ def _flag_value_name(self, flag_name: str) -> str:
122
+ upper = self.naming.to_upper_snake(flag_name)
123
+ return f"FLAG_{upper}"
124
+
125
+ def _state_type_name(self) -> str:
126
+ if self.layer_name:
127
+ return f"STATE_{self.layer_name}_t"
128
+ return "STATE_t"
129
+
130
+ def _event_type_name(self) -> str:
131
+ if self.layer_name:
132
+ return f"EVENT_{self.layer_name}_t"
133
+ return "EVENT_t"
134
+
135
+ def _flag_type_name(self) -> str:
136
+ return "FLAG_t"
137
+
138
+ def _state_max_name(self) -> str:
139
+ if self.layer_name:
140
+ return f"STATE_{self.layer_name}_MAX"
141
+ return "STATE_MAX"
142
+
143
+ def _event_max_name(self) -> str:
144
+ if self.layer_name:
145
+ return f"EVENT_{self.layer_name}_MAX"
146
+ return "EVENT_MAX"
147
+
148
+ def _flag_max_name(self) -> str:
149
+ return "FLAG_MAX"
150
+
151
+ def _generate_state_comment(self, state: State) -> str:
152
+ comments = []
153
+ if getattr(state, 'description', ''):
154
+ comments.append(state.description)
155
+ if getattr(state, 'type', None) and state.type != StateType.NORMAL:
156
+ comments.append(f"Type: {state.type.name}")
157
+ if getattr(state, 'title', ''):
158
+ comments.append(f"Title: {state.title}")
159
+ return ' '.join(comments)
160
+
161
+ def _generate_event_comment(self, event: Event) -> str:
162
+ comments = []
163
+ if getattr(event, 'description', ''):
164
+ comments.append(event.description)
165
+ if getattr(event, 'kind', None) and event.kind != EventKind.SIGNAL:
166
+ comments.append(f"Kind: {event.kind.name}")
167
+ if getattr(event, 'title', ''):
168
+ comments.append(f"Title: {event.title}")
169
+ return ' '.join(comments)
170
+
171
+ def _generate_flag_comment(self, flag: EventFlag) -> str:
172
+ comments = []
173
+ if getattr(flag, 'description', ''):
174
+ comments.append(flag.description)
175
+ if getattr(flag, 'title', ''):
176
+ comments.append(f"Title: {flag.title}")
177
+ return ' '.join(comments)
178
+
179
+ def _generate_enum_values(self, items: List[Any],
180
+ value_name_func,
181
+ comment_func,
182
+ none_value: Optional[str] = None,
183
+ none_comment: str = "") -> str:
184
+ T = self.ENUM_TEMPLATES
185
+ parts = []
186
+
187
+ if none_value is not None:
188
+ none_name = value_name_func("")
189
+ parts.append(T['value_with_comment'].substitute(
190
+ name=none_name,
191
+ value=0,
192
+ comment=none_comment,
193
+ ))
194
+ start_index = 1
195
+ else:
196
+ start_index = 0
197
+
198
+ for i, item in enumerate(items):
199
+ value = start_index + i
200
+ name = value_name_func(getattr(item, 'name', 'unnamed'))
201
+ comment = comment_func(item)
202
+
203
+ if comment:
204
+ parts.append(T['value_with_comment'].substitute(
205
+ name=name, value=value, comment=comment,
206
+ ))
207
+ else:
208
+ parts.append(T['value'].substitute(
209
+ name=name, value=value,
210
+ ))
211
+
212
+ return ''.join(parts)
213
+
214
+ def generate_state_enum(self, states: List[State]) -> str:
215
+ if not states:
216
+ return ''
217
+
218
+ self._log_debug(f"=== generate_state_enum START: {len(states)} states ===")
219
+ T = self.ENUM_TEMPLATES
220
+ parts = []
221
+
222
+ desc = f"{self.layer_name} layer state definitions" if self.layer_name else "State definitions"
223
+ parts.append(T['section_comment'].substitute(description=desc))
224
+
225
+ parts.append(T['enum_start'])
226
+
227
+ parts.append(self._generate_enum_values(
228
+ items=states,
229
+ value_name_func=self._state_value_name,
230
+ comment_func=self._generate_state_comment,
231
+ none_value=None,
232
+ ))
233
+
234
+ parts.append(T['max_value'].substitute(name=self._state_max_name()))
235
+ parts.append(T['enum_end'].substitute(type_name=self._state_type_name()))
236
+
237
+ result = ''.join(parts)
238
+ self._log_debug(f"=== generate_state_enum END ===")
239
+ return result
240
+
241
+ def generate_event_enum(self, events: List[Event]) -> str:
242
+ """
243
+ Generate event enum (including NONE = 0).
244
+
245
+ [v1.5 fix]
246
+ Empty-name events (used for completion transitions, `name=""`)
247
+ are already handled as NONE at the top, so exclude them from
248
+ the main loop. This prevents duplicate EVENT_<Layer>_NONE.
249
+ """
250
+ if not events:
251
+ return ''
252
+
253
+ # v1.5 fix: exclude empty-name events
254
+ non_empty_events = [
255
+ e for e in events if getattr(e, 'name', '')
256
+ ]
257
+ filtered = len(events) - len(non_empty_events)
258
+ if filtered:
259
+ self._log_debug(
260
+ f"generate_event_enum: filtered out {filtered} empty-name "
261
+ f"event(s) (already processed as NONE)"
262
+ )
263
+
264
+ self._log_debug(f"=== generate_event_enum START: "
265
+ f"{len(non_empty_events)} events ===")
266
+ T = self.ENUM_TEMPLATES
267
+ parts = []
268
+
269
+ desc = f"{self.layer_name} layer event definitions" if self.layer_name else "Event definitions"
270
+ parts.append(T['section_comment'].substitute(description=desc))
271
+
272
+ parts.append(T['enum_start'])
273
+
274
+ parts.append(self._generate_enum_values(
275
+ items=non_empty_events,
276
+ value_name_func=self._event_value_name,
277
+ comment_func=self._generate_event_comment,
278
+ none_value="NONE",
279
+ none_comment="completion transition",
280
+ ))
281
+
282
+ parts.append(T['max_value'].substitute(name=self._event_max_name()))
283
+ parts.append(T['enum_end'].substitute(type_name=self._event_type_name()))
284
+
285
+ result = ''.join(parts)
286
+ self._log_debug(f"=== generate_event_enum END ===")
287
+ return result
288
+
289
+ def generate_flag_enum(self, flags: List[EventFlag]) -> str:
290
+ if not flags:
291
+ return ''
292
+
293
+ self._log_debug(f"=== generate_flag_enum START: {len(flags)} flags ===")
294
+ T = self.ENUM_TEMPLATES
295
+ parts = []
296
+
297
+ parts.append(T['section_comment'].substitute(description="Event flag definitions"))
298
+ parts.append(T['enum_start'])
299
+
300
+ parts.append(self._generate_enum_values(
301
+ items=flags,
302
+ value_name_func=self._flag_value_name,
303
+ comment_func=self._generate_flag_comment,
304
+ none_value=None,
305
+ ))
306
+
307
+ parts.append(T['max_value'].substitute(name=self._flag_max_name()))
308
+ parts.append(T['enum_end'].substitute(type_name=self._flag_type_name()))
309
+
310
+ result = ''.join(parts)
311
+ self._log_debug(f"=== generate_flag_enum END ===")
312
+ return result
313
+
314
+ def generate_all_enums(self, states: List[State], events: List[Event],
315
+ flags: List[EventFlag] = None) -> str:
316
+ self._log_debug(f"=== generate_all_enums START: "
317
+ f"{len(states)} states, {len(events)} events, "
318
+ f"{len(flags) if flags else 0} flags ===")
319
+ parts = []
320
+
321
+ state_enum = self.generate_state_enum(states)
322
+ if state_enum:
323
+ parts.append(state_enum)
324
+ parts.append("")
325
+
326
+ event_enum = self.generate_event_enum(events)
327
+ if event_enum:
328
+ parts.append(event_enum)
329
+ parts.append("")
330
+
331
+ if flags:
332
+ flag_enum = self.generate_flag_enum(flags)
333
+ if flag_enum:
334
+ parts.append(flag_enum)
335
+
336
+ result = '\n'.join(parts)
337
+ self._log_debug(f"=== generate_all_enums END: {len(result)} chars ===")
338
+ return result
339
+
340
+ def generate_bit_mask_enum(self, flags: List[EventFlag]) -> str:
341
+ if not flags:
342
+ return ''
343
+
344
+ self._log_debug(f"=== generate_bit_mask_enum START: {len(flags)} flags ===")
345
+ T = self.ENUM_TEMPLATES
346
+ parts = []
347
+
348
+ parts.append('/* Event flag bitmask definitions */\n')
349
+ parts.append('/* Used when managing flags as individual bits */\n')
350
+ parts.append(T['enum_start'])
351
+
352
+ for i, flag in enumerate(flags):
353
+ bit_value = 1 << i
354
+ upper = self.naming.to_upper_snake(getattr(flag, 'name', 'unnamed'))
355
+ name = f"FLAG_MASK_{upper}"
356
+ comment = self._generate_flag_comment(flag)
357
+ if comment:
358
+ parts.append(f" {name} = 0x{bit_value:02X}, /* {comment} */\n")
359
+ else:
360
+ parts.append(f" {name} = 0x{bit_value:02X},\n")
361
+
362
+ parts.append(T['enum_end'].substitute(type_name="FLAG_MASK_t"))
363
+
364
+ result = ''.join(parts)
365
+ self._log_debug(f"=== generate_bit_mask_enum END ===")
366
+ return result
367
+
368
+ def generate_enum(self, enum_type: str, items: List[Any]) -> str:
369
+ if enum_type == 'state':
370
+ return self.generate_state_enum(items)
371
+ elif enum_type == 'event':
372
+ return self.generate_event_enum(items)
373
+ elif enum_type == 'flag':
374
+ return self.generate_flag_enum(items)
375
+ else:
376
+ logger.warning(f"Unknown enum_type: {enum_type}")
377
+ return ""
@@ -0,0 +1,303 @@
1
+ # codegen/event_queue_generator.py
2
+ """\nEvent queue code generation module (fully data-driven)\n"""
3
+
4
+ import sys
5
+ import os
6
+ import logging
7
+ from typing import Dict, Callable, List, Any
8
+
9
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
10
+
11
+ from statable.global_defs import EventQueueDef, GlobalDefinitions
12
+
13
+ try:
14
+ from .type_mapper import CTypeMapper
15
+ from .naming_convention import CNamingConvention
16
+ from .code_templates import CodeTemplates
17
+ except ImportError:
18
+ from type_mapper import CTypeMapper
19
+ from naming_convention import CNamingConvention
20
+ from code_templates import CodeTemplates
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ class EventQueueGenerator:
26
+ """Event queue code generation class (fully data-driven)"""
27
+
28
+ def __init__(self):
29
+ self.mapper = CTypeMapper()
30
+ self.naming = CNamingConvention()
31
+ self.templates = CodeTemplates()
32
+ self.strings = self.templates.STRINGS
33
+ self.formats = self.templates.FORMATS
34
+
35
+ # Generation step definition
36
+ self.struct_steps = [
37
+ {'action': 'comment'},
38
+ {'action': 'struct_start'},
39
+ {'action': 'members'},
40
+ {'action': 'struct_end'},
41
+ ]
42
+
43
+ self.enqueue_steps = [
44
+ {'action': 'comment'},
45
+ {'action': 'signature'},
46
+ {'action': 'open'},
47
+ {'action': 'null_check'},
48
+ {'action': 'full_check'},
49
+ {'action': 'enqueue_body'},
50
+ {'action': 'close'},
51
+ ]
52
+
53
+ self.dequeue_steps = [
54
+ {'action': 'comment'},
55
+ {'action': 'signature'},
56
+ {'action': 'open'},
57
+ {'action': 'null_check'},
58
+ {'action': 'empty_check'},
59
+ {'action': 'dequeue_body'},
60
+ {'action': 'close'},
61
+ ]
62
+
63
+ # Step execution dictionary
64
+ self.struct_executors: Dict[str, Callable] = {
65
+ 'comment': self._execute_struct_comment,
66
+ 'struct_start': self._execute_struct_start,
67
+ 'members': self._execute_members,
68
+ 'struct_end': self._execute_struct_end,
69
+ }
70
+
71
+ self.enqueue_executors: Dict[str, Callable] = {
72
+ 'comment': self._execute_enqueue_comment,
73
+ 'signature': self._execute_enqueue_signature,
74
+ 'open': self._execute_open,
75
+ 'null_check': self._execute_null_check,
76
+ 'full_check': self._execute_full_check,
77
+ 'enqueue_body': self._execute_enqueue_body,
78
+ 'close': self._execute_close,
79
+ }
80
+
81
+ self.dequeue_executors: Dict[str, Callable] = {
82
+ 'comment': self._execute_dequeue_comment,
83
+ 'signature': self._execute_dequeue_signature,
84
+ 'open': self._execute_open,
85
+ 'null_check': self._execute_null_check,
86
+ 'empty_check': self._execute_empty_check,
87
+ 'dequeue_body': self._execute_dequeue_body,
88
+ 'close': self._execute_close,
89
+ }
90
+
91
+ def _log_debug(self, message, level='debug'):
92
+ log_func = getattr(logger, level, logger.debug)
93
+ log_func(message)
94
+
95
+ # ===== Name generation =====
96
+ def _generate_struct_name(self, queue):
97
+ return self.naming.create_type_name(getattr(queue, 'name', 'EventQueue'))
98
+
99
+ def _generate_func_prefix(self, queue):
100
+ return f"EventQueue_{self.naming.to_pascal_case(getattr(queue, 'name', ''))}"
101
+
102
+ # ===== Struct generation step =====
103
+ def _execute_struct_comment(self, step, context):
104
+ queue = context.get('queue')
105
+ name = getattr(queue, 'name', 'unknown')
106
+ desc = getattr(queue, 'description', '')
107
+ lines = [f"/* Event queue: {name} */"]
108
+ if desc:
109
+ lines.append(f"/* {desc} */")
110
+ return lines
111
+
112
+ def _execute_struct_start(self, step, context):
113
+ return ["typedef struct {"]
114
+
115
+ def _execute_members(self, step, context):
116
+ queue = context.get('queue')
117
+ indent = self.strings['indent_1']
118
+ size = getattr(queue, 'size', 0)
119
+ element_type = self.mapper.map_type(getattr(queue, 'element_type', 'EVENT_t'))
120
+
121
+ lines = []
122
+ lines.append(f"{indent}{element_type} buffer[{size}];")
123
+ lines.append(f"{indent}uint8_t head;")
124
+ lines.append(f"{indent}uint8_t tail;")
125
+ lines.append(f"{indent}uint8_t count;")
126
+
127
+ if getattr(queue, 'interrupt_safe', False):
128
+ lines.append(f"{indent}bool interrupt_safe;")
129
+
130
+ if getattr(queue, 'rtos_enabled', False):
131
+ lines.append(f"{indent}bool rtos_enabled;")
132
+
133
+ return lines
134
+
135
+ def _execute_struct_end(self, step, context):
136
+ queue = context.get('queue')
137
+ type_name = self._generate_struct_name(queue)
138
+ return [f"}} {type_name};"]
139
+
140
+ # ===== Enqueue generation step =====
141
+ def _execute_enqueue_comment(self, step, context):
142
+ queue = context.get('queue')
143
+ name = getattr(queue, 'name', 'unknown')
144
+ return [
145
+ "/**",
146
+ f" * @brief Enqueue event ({name})",
147
+ " * @param queue Queue",
148
+ " * @param event Event",
149
+ " * @return success: true, failure: false",
150
+ " */",
151
+ ]
152
+
153
+ def _execute_enqueue_signature(self, step, context):
154
+ queue = context.get('queue')
155
+ type_name = self._generate_struct_name(queue)
156
+ func_name = self._generate_func_prefix(queue) + "_Enqueue"
157
+ return [f"bool {func_name}({type_name} *queue, EVENT_t event)"]
158
+
159
+ def _execute_dequeue_comment(self, step, context):
160
+ queue = context.get('queue')
161
+ name = getattr(queue, 'name', 'unknown')
162
+ return [
163
+ "/**",
164
+ f" * @brief Dequeue event ({name})",
165
+ " * @param queue Queue",
166
+ " * @param event Dequeued event",
167
+ " * @return success: true, failure: false",
168
+ " */",
169
+ ]
170
+
171
+ def _execute_dequeue_signature(self, step, context):
172
+ queue = context.get('queue')
173
+ type_name = self._generate_struct_name(queue)
174
+ func_name = self._generate_func_prefix(queue) + "_Dequeue"
175
+ return [f"bool {func_name}({type_name} *queue, EVENT_t *event)"]
176
+
177
+ def _execute_open(self, step, context):
178
+ return ["{"]
179
+
180
+ def _execute_close(self, step, context):
181
+ return ["}"]
182
+
183
+ def _execute_null_check(self, step, context):
184
+ indent = self.strings['indent_1']
185
+ lines = []
186
+ lines.append(f"{indent}if (queue == NULL) {{")
187
+ lines.append(f"{indent}{indent}return false;")
188
+ lines.append(f"{indent}}}")
189
+ return lines
190
+
191
+ def _execute_full_check(self, step, context):
192
+ queue = context.get('queue')
193
+ size = getattr(queue, 'size', 0)
194
+ indent = self.strings['indent_1']
195
+ lines = []
196
+ lines.append(f"{indent}if (queue->count >= {size}) {{")
197
+ lines.append(f"{indent}{indent}return false; /* Queue full */")
198
+ lines.append(f"{indent}}}")
199
+ return lines
200
+
201
+ def _execute_empty_check(self, step, context):
202
+ indent = self.strings['indent_1']
203
+ lines = []
204
+ lines.append(f"{indent}if (queue->count == 0) {{")
205
+ lines.append(f"{indent}{indent}return false; /* Queue empty */")
206
+ lines.append(f"{indent}}}")
207
+ return lines
208
+
209
+ def _execute_enqueue_body(self, step, context):
210
+ queue = context.get('queue')
211
+ size = getattr(queue, 'size', 0)
212
+ indent = self.strings['indent_1']
213
+ lines = []
214
+ lines.append(f"{indent}queue->buffer[queue->tail] = event;")
215
+ lines.append(f"{indent}queue->tail = (queue->tail + 1) % {size};")
216
+ lines.append(f"{indent}queue->count++;")
217
+ lines.append(f"{indent}return true;")
218
+ return lines
219
+
220
+ def _execute_dequeue_body(self, step, context):
221
+ queue = context.get('queue')
222
+ size = getattr(queue, 'size', 0)
223
+ indent = self.strings['indent_1']
224
+ lines = []
225
+ lines.append(f"{indent}if (event == NULL) {{")
226
+ lines.append(f"{indent}{indent}return false;")
227
+ lines.append(f"{indent}}}")
228
+ lines.append(f"{indent}*event = queue->buffer[queue->head];")
229
+ lines.append(f"{indent}queue->head = (queue->head + 1) % {size};")
230
+ lines.append(f"{indent}queue->count--;")
231
+ lines.append(f"{indent}return true;")
232
+ return lines
233
+
234
+ # ===== Public methods =====
235
+ def generate_struct(self, queue: EventQueueDef) -> str:
236
+ """Event queue struct generation"""
237
+ self._log_debug(f"Generating struct for: {getattr(queue, 'name', 'unknown')}")
238
+ context = {'queue': queue}
239
+ lines = []
240
+ for step in self.struct_steps:
241
+ executor = self.struct_executors.get(step['action'])
242
+ if executor:
243
+ lines.extend(executor(step, context))
244
+ return '\n'.join(lines)
245
+
246
+ def generate_enqueue_function(self, queue: EventQueueDef) -> str:
247
+ """Enqueue function generation"""
248
+ self._log_debug(f"Generating enqueue for: {getattr(queue, 'name', 'unknown')}")
249
+ context = {'queue': queue}
250
+ lines = []
251
+ for step in self.enqueue_steps:
252
+ executor = self.enqueue_executors.get(step['action'])
253
+ if executor:
254
+ lines.extend(executor(step, context))
255
+ return '\n'.join(lines)
256
+
257
+ def generate_dequeue_function(self, queue: EventQueueDef) -> str:
258
+ """Dequeue function generation"""
259
+ self._log_debug(f"Generating dequeue for: {getattr(queue, 'name', 'unknown')}")
260
+ context = {'queue': queue}
261
+ lines = []
262
+ for step in self.dequeue_steps:
263
+ executor = self.dequeue_executors.get(step['action'])
264
+ if executor:
265
+ lines.extend(executor(step, context))
266
+ return '\n'.join(lines)
267
+
268
+ def generate_all_code(self, queue: EventQueueDef) -> str:
269
+ """Generate all event queue code"""
270
+ self._log_debug(f"Generating all code for: {getattr(queue, 'name', 'unknown')}")
271
+ lines = []
272
+ lines.append(self.generate_struct(queue))
273
+ lines.append("")
274
+ lines.append(self.generate_enqueue_function(queue))
275
+ lines.append("")
276
+ lines.append(self.generate_dequeue_function(queue))
277
+ return '\n'.join(lines)
278
+
279
+ def generate_all_structs(self, global_defs: GlobalDefinitions) -> str:
280
+ """Generate all event queue structs"""
281
+ lines = []
282
+ for queue in getattr(global_defs, 'event_queues', []):
283
+ lines.append(self.generate_struct(queue))
284
+ lines.append("")
285
+ return '\n'.join(lines)
286
+
287
+ def generate_all_functions(self, global_defs: GlobalDefinitions) -> str:
288
+ """Generate all event queue functions"""
289
+ lines = []
290
+ for queue in getattr(global_defs, 'event_queues', []):
291
+ lines.append(self.generate_enqueue_function(queue))
292
+ lines.append("")
293
+ lines.append(self.generate_dequeue_function(queue))
294
+ lines.append("")
295
+ return '\n'.join(lines)
296
+
297
+ def generate_all(self, global_defs: GlobalDefinitions) -> str:
298
+ """Generate all event queue code"""
299
+ lines = []
300
+ for queue in getattr(global_defs, 'event_queues', []):
301
+ lines.append(self.generate_all_code(queue))
302
+ lines.append("")
303
+ return '\n'.join(lines)