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,282 @@
1
+ # codegen/osal_generator.py
2
+ """
3
+ OSAL (OS abstraction layer) code generation module (template-split version)
4
+
5
+ Version: 2.5 (2026-09-22 / ARM toolchain portability fix)
6
+ - The generated osal.c now includes <stddef.h> so that NULL is
7
+ defined. Required by ARM GNU Toolchain 14.x (strict C99).
8
+
9
+ Version: 2.2 (2026-09-20 / MISRA 17.3 fix)
10
+ - The generated osal.c now includes its own header "osal.h" first.
11
+ MISRA C:2012 Rule 17.3 requires that a function be declared before
12
+ its definition; including osal.h in osal.c satisfies this without
13
+ changing the function signatures.
14
+ """
15
+
16
+ import sys
17
+ import os
18
+ import logging
19
+ from typing import Dict, Callable, List, Any
20
+
21
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
22
+
23
+ try:
24
+ from .code_templates import CodeTemplates
25
+ from .naming_convention import CNamingConvention
26
+ except ImportError:
27
+ from code_templates import CodeTemplates
28
+ from naming_convention import CNamingConvention
29
+
30
+ logger = logging.getLogger(__name__)
31
+
32
+
33
+ class OSALGenerator:
34
+ """OSAL code generation class (template-split version)"""
35
+
36
+ def __init__(self):
37
+ self.templates = CodeTemplates()
38
+ self.strings = self.templates.STRINGS
39
+ self.formats = self.templates.FORMATS
40
+ self.osal_templates = self.templates.OSAL
41
+ self.naming = CNamingConvention()
42
+
43
+ # Header generation step
44
+ self.header_steps = [
45
+ {'action': 'file_comment'},
46
+ {'action': 'include_guard_start'},
47
+ {'action': 'includes'},
48
+ {'action': 'type_defs'},
49
+ {'action': 'mutex_decls'},
50
+ {'action': 'semaphore_decls'},
51
+ {'action': 'queue_decls'},
52
+ {'action': 'critical_decls'},
53
+ {'action': 'include_guard_end'},
54
+ ]
55
+
56
+ # Source generation step
57
+ self.source_steps = [
58
+ {'action': 'file_comment'},
59
+ {'action': 'includes'},
60
+ {'action': 'mutex_impl'},
61
+ {'action': 'semaphore_impl'},
62
+ {'action': 'queue_impl'},
63
+ {'action': 'critical_impl'},
64
+ ]
65
+
66
+ # Step execution dictionary
67
+ self.step_executors: Dict[str, Callable] = {
68
+ 'file_comment': self._execute_file_comment,
69
+ 'include_guard_start': self._execute_include_guard_start,
70
+ 'includes': self._execute_includes,
71
+ 'type_defs': self._execute_type_defs,
72
+ 'mutex_decls': self._execute_mutex_decls,
73
+ 'semaphore_decls': self._execute_semaphore_decls,
74
+ 'queue_decls': self._execute_queue_decls,
75
+ 'critical_decls': self._execute_critical_decls,
76
+ 'include_guard_end': self._execute_include_guard_end,
77
+ 'mutex_impl': self._execute_mutex_impl,
78
+ 'semaphore_impl': self._execute_semaphore_impl,
79
+ 'queue_impl': self._execute_queue_impl,
80
+ 'critical_impl': self._execute_critical_impl,
81
+ }
82
+
83
+ def _log_debug(self, message, level='debug'):
84
+ log_func = getattr(logger, level, logger.debug)
85
+ log_func(message)
86
+
87
+ # ===== Step execution function =====
88
+ def _execute_file_comment(self, step, context):
89
+ os_type = context.get('os_type', 'non_rtos')
90
+ os_info = self.osal_templates['os_types'].get(os_type, {})
91
+ filename = context.get('filename', 'osal.h')
92
+ os_name = os_info.get('name', 'NonRTOS')
93
+
94
+ template = self.osal_templates['header']['file_comment']
95
+ return [template.format(filename=filename, os_name=os_name)]
96
+
97
+ def _execute_include_guard_start(self, step, context):
98
+ guard_name = context.get('guard_name', 'OSAL_H')
99
+ return [self.osal_templates['header']['include_guard_start'].format(guard_name=guard_name)]
100
+
101
+ def _execute_includes(self, step, context):
102
+ """Emit include section.
103
+
104
+ [v2.2 / MISRA 17.3]
105
+ - Header (osal.h): only <stdint.h> / <stdbool.h> are needed.
106
+ - Source (osal.c): must include its own header "osal.h" FIRST,
107
+ so all OSAL function prototypes are visible before the
108
+ definitions (MISRA C:2012 Rule 17.3).
109
+
110
+ [v2.5 / ARM portability]
111
+ - Source additionally includes <stddef.h> to make NULL
112
+ available. Required by ARM GNU Toolchain 14.x, which
113
+ enforces C99 strictly. MinGW gcc accepts the code without
114
+ it, but the ARM build fails.
115
+ """
116
+ os_type = context.get('os_type', 'non_rtos')
117
+ is_header = 'guard_name' in context
118
+
119
+ lines: List[str] = []
120
+
121
+ if is_header:
122
+ lines.extend(["#include <stdint.h>", "#include <stdbool.h>", ""])
123
+ else:
124
+ # Source: include own header first (MISRA 17.3)
125
+ os_info = self.osal_templates['os_types'].get(os_type, {})
126
+ header_name = os_info.get('header', 'osal.h')
127
+ lines.append(f'#include "{header_name}"')
128
+ # [v2.5] <stddef.h> provides NULL. Required by ARM
129
+ # GNU Toolchain 14.x (strict C99).
130
+ lines.append("#include <stddef.h>")
131
+ lines.append("")
132
+
133
+ if os_type == 'freertos':
134
+ lines.append(self.osal_templates['header']['freertos_includes'])
135
+ lines.append("")
136
+ elif os_type == 'threadx':
137
+ lines.append(self.osal_templates['header']['threadx_includes'])
138
+ lines.append("")
139
+
140
+ return lines
141
+
142
+ def _execute_type_defs(self, step, context):
143
+ os_type = context.get('os_type', 'non_rtos')
144
+ lines = []
145
+
146
+ lines.append(self.osal_templates['header']['type_defs_comment'])
147
+ lines.append(self.osal_templates['header']['status_enum'])
148
+ lines.append("")
149
+
150
+ if os_type == 'non_rtos':
151
+ lines.append(self.osal_templates['header']['mutex_type_nonrtos'])
152
+ lines.append("")
153
+ lines.append(self.osal_templates['header']['semaphore_type_nonrtos'])
154
+ lines.append("")
155
+ lines.append(self.osal_templates['header']['queue_type_nonrtos'])
156
+ lines.append("")
157
+
158
+ return lines
159
+
160
+ def _execute_mutex_decls(self, step, context):
161
+ return [self.osal_templates['header']['mutex_decls'], ""]
162
+
163
+ def _execute_semaphore_decls(self, step, context):
164
+ return [self.osal_templates['header']['semaphore_decls'], ""]
165
+
166
+ def _execute_queue_decls(self, step, context):
167
+ return [self.osal_templates['header']['queue_decls'], ""]
168
+
169
+ def _execute_critical_decls(self, step, context):
170
+ return [self.osal_templates['header']['critical_decls'], ""]
171
+
172
+ def _execute_include_guard_end(self, step, context):
173
+ guard_name = context.get('guard_name', 'OSAL_H')
174
+ return [self.osal_templates['header']['include_guard_end'].format(guard_name=guard_name)]
175
+
176
+ def _execute_mutex_impl(self, step, context):
177
+ os_type = context.get('os_type', 'non_rtos')
178
+ lines = []
179
+
180
+ if os_type == 'non_rtos':
181
+ lines.append(self.osal_templates['source']['mutex_section_comment'])
182
+ lines.append(self.osal_templates['source']['mutex_create_nonrtos'])
183
+ lines.append("")
184
+ lines.append(self.osal_templates['source']['mutex_lock_nonrtos'])
185
+ lines.append("")
186
+ lines.append(self.osal_templates['source']['mutex_unlock_nonrtos'])
187
+ lines.append("")
188
+
189
+ return lines
190
+
191
+ def _execute_semaphore_impl(self, step, context):
192
+ os_type = context.get('os_type', 'non_rtos')
193
+ lines = []
194
+
195
+ if os_type == 'non_rtos':
196
+ lines.append(self.osal_templates['source']['semaphore_section_comment'])
197
+ lines.append(self.osal_templates['source']['semaphore_create_nonrtos'])
198
+ lines.append("")
199
+ lines.append(self.osal_templates['source']['semaphore_take_nonrtos'])
200
+ lines.append("")
201
+ lines.append(self.osal_templates['source']['semaphore_give_nonrtos'])
202
+ lines.append("")
203
+
204
+ return lines
205
+
206
+ def _execute_queue_impl(self, step, context):
207
+ os_type = context.get('os_type', 'non_rtos')
208
+ lines = []
209
+
210
+ if os_type == 'non_rtos':
211
+ lines.append(self.osal_templates['source']['queue_section_comment'])
212
+ lines.append(self.osal_templates['source']['queue_create_nonrtos'])
213
+ lines.append("")
214
+ lines.append(self.osal_templates['source']['queue_send_nonrtos'])
215
+ lines.append("")
216
+ lines.append(self.osal_templates['source']['queue_receive_nonrtos'])
217
+ lines.append("")
218
+
219
+ return lines
220
+
221
+ def _execute_critical_impl(self, step, context):
222
+ os_type = context.get('os_type', 'non_rtos')
223
+ lines = []
224
+
225
+ if os_type == 'non_rtos':
226
+ lines.append(self.osal_templates['source']['critical_section_comment'])
227
+ lines.append(self.osal_templates['source']['critical_enter_nonrtos'])
228
+ lines.append("")
229
+ lines.append(self.osal_templates['source']['critical_exit_nonrtos'])
230
+ lines.append("")
231
+
232
+ return lines
233
+
234
+ # ===== Public methods =====
235
+ def generate_header(self, os_type='non_rtos') -> str:
236
+ """OSAL header generation"""
237
+ self._log_debug(f"Generating OSAL header for: {os_type}")
238
+
239
+ os_info = self.osal_templates['os_types'].get(os_type, {})
240
+ context = {
241
+ 'filename': os_info.get('header', 'osal.h'),
242
+ 'os_type': os_type,
243
+ 'guard_name': 'OSAL_H',
244
+ }
245
+
246
+ lines = []
247
+ for step in self.header_steps:
248
+ executor = self.step_executors.get(step['action'])
249
+ if executor:
250
+ lines.extend(executor(step, context))
251
+
252
+ return '\n'.join(lines)
253
+
254
+ def generate_source(self, os_type='non_rtos') -> str:
255
+ """OSAL source generation"""
256
+ self._log_debug(f"Generating OSAL source for: {os_type}")
257
+
258
+ os_info = self.osal_templates['os_types'].get(os_type, {})
259
+ context = {
260
+ 'filename': os_info.get('source', 'osal.c'),
261
+ 'os_type': os_type,
262
+ }
263
+
264
+ lines = []
265
+ for step in self.source_steps:
266
+ executor = self.step_executors.get(step['action'])
267
+ if executor:
268
+ lines.extend(executor(step, context))
269
+
270
+ return '\n'.join(lines)
271
+
272
+ def generate_all(self, os_type='non_rtos') -> Dict[str, str]:
273
+ """Generate all OSAL code"""
274
+ os_info = self.osal_templates['os_types'].get(os_type, {})
275
+ return {
276
+ os_info.get('header', 'osal.h'): self.generate_header(os_type),
277
+ os_info.get('source', 'osal.c'): self.generate_source(os_type),
278
+ }
279
+
280
+ def get_available_os_types(self) -> Dict[str, str]:
281
+ """Get available OS types"""
282
+ return {key: value['description'] for key, value in self.osal_templates['os_types'].items()}