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.
- codegen/__init__.py +38 -0
- codegen/c_code_generator.py +1752 -0
- codegen/code_merger.py +371 -0
- codegen/code_templates.py +509 -0
- codegen/config.py +167 -0
- codegen/enum_generator.py +377 -0
- codegen/event_queue_generator.py +303 -0
- codegen/interrupt_generator.py +345 -0
- codegen/naming_convention.py +171 -0
- codegen/osal_generator.py +282 -0
- codegen/role_function_generator.py +1244 -0
- codegen/sample_data.py +269 -0
- codegen/state_actions_generator.py +395 -0
- codegen/struct_generator.py +721 -0
- codegen/timer_generator.py +299 -0
- codegen/transition_generator.py +907 -0
- codegen/type_mapper.py +69 -0
- codegen/validate/__init__.py +38 -0
- codegen/validate/change_actions.py +90 -0
- codegen/validate/change_applier.py +416 -0
- codegen/validate/clipboard_manager.py +47 -0
- codegen/validate/data/__init__.py +30 -0
- codegen/validate/data/action_definitions.py +200 -0
- codegen/validate/data/keywords.py +46 -0
- codegen/validate/data/prompt_templates.py +176 -0
- codegen/validate/data/validation_rules.py +205 -0
- codegen/validate/items/__init__.py +30 -0
- codegen/validate/items/base_validator.py +25 -0
- codegen/validate/items/cell_validator.py +275 -0
- codegen/validate/items/custom_type_validator.py +75 -0
- codegen/validate/items/event_validator.py +78 -0
- codegen/validate/items/flag_validator.py +74 -0
- codegen/validate/items/interrupt_validator.py +75 -0
- codegen/validate/items/queue_validator.py +73 -0
- codegen/validate/items/role_function_validator.py +175 -0
- codegen/validate/items/state_validator.py +88 -0
- codegen/validate/items/timer_validator.py +120 -0
- codegen/validate/items/transition_validator.py +113 -0
- codegen/validate/items/variable_validator.py +132 -0
- codegen/validate/logger.py +52 -0
- codegen/validate/models.py +177 -0
- codegen/validate/prompt_generator.py +724 -0
- codegen/validate/response_parser.py +154 -0
- codegen/validate/response_validator.py +275 -0
- codegen/validate/validation_dialog.py +322 -0
- codegen/validate/validator.py +94 -0
- codegen/variable_generator.py +419 -0
- statable/__init__.py +71 -0
- statable/__main__.py +49 -0
- statable/cli.py +251 -0
- statable/global_defs.py +256 -0
- statable/mermaid_gen.py +144 -0
- statable/model.py +426 -0
- statable/parser.py +64 -0
- statable/sample_data.py +435 -0
- statable/shared/__init__.py +24 -0
- statable/shared/condition_library.py +63 -0
- statable/shared/literal_library.py +66 -0
- statable/shared/role_function_library.py +150 -0
- statable/state_machine.py +121 -0
- statable/xml_io.py +1164 -0
- statable-3.1.0.dist-info/METADATA +151 -0
- statable-3.1.0.dist-info/RECORD +117 -0
- statable-3.1.0.dist-info/WHEEL +5 -0
- statable-3.1.0.dist-info/entry_points.txt +2 -0
- statable-3.1.0.dist-info/top_level.txt +3 -0
- statable_gui/__init__.py +23 -0
- statable_gui/action_edit_dialog.py +214 -0
- statable_gui/code_generation_dialog.py +486 -0
- statable_gui/code_generation_settings_dialog.py +522 -0
- statable_gui/common_widgets.py +537 -0
- statable_gui/condition_builder_dialog.py +500 -0
- statable_gui/condition_edit_dialog.py +123 -0
- statable_gui/condition_template_dialog.py +58 -0
- statable_gui/config.py +21 -0
- statable_gui/dialogs.py +439 -0
- statable_gui/event_definition_dialog.py +605 -0
- statable_gui/event_delivery_settings_dialog.py +191 -0
- statable_gui/event_queue_dialog.py +245 -0
- statable_gui/global_defs.py +167 -0
- statable_gui/global_defs_dialog.py +796 -0
- statable_gui/i18n/__init__.py +118 -0
- statable_gui/interrupt_handler_edit_dialog.py +810 -0
- statable_gui/layer_settings_dialog.py +180 -0
- statable_gui/libcntrl/__init__.py +23 -0
- statable_gui/libcntrl/condition_library.py +13 -0
- statable_gui/libcntrl/literal_library.py +13 -0
- statable_gui/libcntrl/literal_management_dialog.py +185 -0
- statable_gui/libcntrl/role_function_edit_dialog.py +145 -0
- statable_gui/libcntrl/role_function_library.py +13 -0
- statable_gui/literal_definition_dialog.py +62 -0
- statable_gui/logger.py +83 -0
- statable_gui/main_window.py +1380 -0
- statable_gui/matrix_table.py +413 -0
- statable_gui/preference_keys.py +18 -0
- statable_gui/preferences.py +74 -0
- statable_gui/role_function_dialog.py +244 -0
- statable_gui/sample_data.py +11 -0
- statable_gui/state_actions_dialog.py +398 -0
- statable_gui/symbol_picker.py +170 -0
- statable_gui/traceball.py +37 -0
- statable_gui/transition_editor_direct/__init__.py +15 -0
- statable_gui/transition_editor_direct/actions_tab.py +856 -0
- statable_gui/transition_editor_direct/code_widget.py +344 -0
- statable_gui/transition_editor_direct/coverage_analyzer.py +163 -0
- statable_gui/transition_editor_direct/dialog.py +335 -0
- statable_gui/transition_editor_direct/draft.py +270 -0
- statable_gui/transition_editor_direct/edit_dialogs.py +160 -0
- statable_gui/transition_editor_direct/overview_tab.py +173 -0
- statable_gui/transition_editor_direct/palette_widget.py +233 -0
- statable_gui/transition_editor_direct/relations_edit_dialog.py +156 -0
- statable_gui/transition_editor_direct/relations_tab.py +230 -0
- statable_gui/transition_editor_direct/system_global_dialog.py +52 -0
- statable_gui/transition_editor_direct/transition_actions_dialog.py +109 -0
- statable_gui/transition_editor_direct/transitions_tab.py +620 -0
- statable_gui/validation_dialog.py +285 -0
- statable_gui/widgets.py +1315 -0
|
@@ -0,0 +1,1752 @@
|
|
|
1
|
+
# codegen/c_code_generator.py
|
|
2
|
+
"""
|
|
3
|
+
C code generation main class
|
|
4
|
+
(step-table driven / 13-file support / multi-layer support / by_layer / ISR)
|
|
5
|
+
|
|
6
|
+
Version: 2.2.9 (2026-09-20 / MISRA 17.3 fix)
|
|
7
|
+
- Fix (MISRA C:2012 Rule 17.3): statable_transitions_<Layer>.c now
|
|
8
|
+
directly includes statable_types_common.h so that LOG_* macros
|
|
9
|
+
(LOG_ERROR / LOG_DEBUG / ...) are visible in the file scope.
|
|
10
|
+
Previously they were reachable only via a deep include chain
|
|
11
|
+
(transitions.h -> types.h -> types_common.h); cppcheck did not
|
|
12
|
+
follow the chain and treated LOG_ERROR as an implicit declaration
|
|
13
|
+
(3 hits, one per layer).
|
|
14
|
+
|
|
15
|
+
Version: 2.2.8 (2026-09-20 / get_next_event emission)
|
|
16
|
+
Version: 2.2.7 (2026-09-20 / MISRA 17.3 LOG macros + GetNextEvent prototypes)
|
|
17
|
+
Version: 2.2.6 (2026-09-20 / MISRA 17.3 cross-layer include)
|
|
18
|
+
Version: 2.2.5 (2026-09-19)
|
|
19
|
+
Version: 2.1 (2026-09-13 / Stage 3: ISR context support)
|
|
20
|
+
Version: 1.6 (by_layer suffix / common types)
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import sys
|
|
24
|
+
import os
|
|
25
|
+
import logging
|
|
26
|
+
from typing import Dict, Callable, List, Any, Optional, Tuple
|
|
27
|
+
from datetime import datetime
|
|
28
|
+
|
|
29
|
+
sys.path.append(
|
|
30
|
+
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from statable.state_machine import StateMachine
|
|
34
|
+
from statable.global_defs import GlobalDefinitions
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
from .type_mapper import CTypeMapper
|
|
38
|
+
from .naming_convention import CNamingConvention
|
|
39
|
+
from .struct_generator import CStructGenerator
|
|
40
|
+
from .enum_generator import CEnumGenerator
|
|
41
|
+
from .transition_generator import TransitionGenerator
|
|
42
|
+
from .role_function_generator import RoleFunctionGenerator
|
|
43
|
+
from .variable_generator import VariableGenerator
|
|
44
|
+
from .event_queue_generator import EventQueueGenerator
|
|
45
|
+
from .interrupt_generator import InterruptGenerator
|
|
46
|
+
from .timer_generator import TimerGenerator
|
|
47
|
+
from .osal_generator import OSALGenerator
|
|
48
|
+
from .state_actions_generator import StateActionsGenerator
|
|
49
|
+
from .code_templates import CodeTemplates
|
|
50
|
+
from .code_merger import CodeMerger
|
|
51
|
+
from .config import CodeGenerationConfig, ConfigManager
|
|
52
|
+
except ImportError:
|
|
53
|
+
from type_mapper import CTypeMapper
|
|
54
|
+
from naming_convention import CNamingConvention
|
|
55
|
+
from struct_generator import CStructGenerator
|
|
56
|
+
from enum_generator import CEnumGenerator
|
|
57
|
+
from transition_generator import TransitionGenerator
|
|
58
|
+
from role_function_generator import RoleFunctionGenerator
|
|
59
|
+
from variable_generator import VariableGenerator
|
|
60
|
+
from event_queue_generator import EventQueueGenerator
|
|
61
|
+
from interrupt_generator import InterruptGenerator
|
|
62
|
+
from timer_generator import TimerGenerator
|
|
63
|
+
from osal_generator import OSALGenerator
|
|
64
|
+
from code_templates import CodeTemplates
|
|
65
|
+
from code_merger import CodeMerger
|
|
66
|
+
from config import CodeGenerationConfig, ConfigManager
|
|
67
|
+
|
|
68
|
+
logger = logging.getLogger(__name__)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class CCodeGenerator:
|
|
72
|
+
"""C code generation main class
|
|
73
|
+
(step-table driven / 13-file support / multi-layer support)"""
|
|
74
|
+
|
|
75
|
+
# ================================================================
|
|
76
|
+
# [Table 1] Per-file step definitions
|
|
77
|
+
# ================================================================
|
|
78
|
+
FILE_STEPS: Dict[str, List[Dict[str, Any]]] = {
|
|
79
|
+
'statable_types_common.h': [
|
|
80
|
+
{'action': 'file_header',
|
|
81
|
+
'filename': 'statable_types_common.h'},
|
|
82
|
+
{'action': 'blank'},
|
|
83
|
+
{'action': 'guard_start'},
|
|
84
|
+
{'action': 'include_section', 'key': 'types'},
|
|
85
|
+
{'action': 'section_header', 'key': 'type_defs'},
|
|
86
|
+
{'action': 'blank'},
|
|
87
|
+
{'action': 'enums_common'},
|
|
88
|
+
{'action': 'blank'},
|
|
89
|
+
{'action': 'custom_types',
|
|
90
|
+
'when': lambda c: bool(c['global_defs'].custom_types)},
|
|
91
|
+
# [C-52] EventQueueState_t must be declared BEFORE
|
|
92
|
+
# SystemContext_t, which embeds it by value.
|
|
93
|
+
{'action': 'struct', 'kind': 'layer_queue_types'},
|
|
94
|
+
{'action': 'blank'},
|
|
95
|
+
{'action': 'section_header', 'key': 'system_structs'},
|
|
96
|
+
{'action': 'blank'},
|
|
97
|
+
{'action': 'struct', 'kind': 'system_data'},
|
|
98
|
+
{'action': 'blank'},
|
|
99
|
+
{'action': 'struct', 'kind': 'event_flags'},
|
|
100
|
+
{'action': 'blank'},
|
|
101
|
+
{'action': 'struct', 'kind': 'system_context'},
|
|
102
|
+
{'action': 'blank'},
|
|
103
|
+
{'action': 'struct', 'kind': 'common_transition_context'},
|
|
104
|
+
{'action': 'blank'},
|
|
105
|
+
{'action': 'struct', 'kind': 'pending_event_macros'},
|
|
106
|
+
{'action': 'blank'},
|
|
107
|
+
# [C-52] per-layer queue macros (FIRE_EVENT_QUEUE_<Layer>)
|
|
108
|
+
{'action': 'struct', 'kind': 'layer_queue_macros'},
|
|
109
|
+
{'action': 'blank'},
|
|
110
|
+
{'action': 'section_header', 'key': 'var_macros'},
|
|
111
|
+
{'action': 'blank'},
|
|
112
|
+
{'action': 'var_macros'},
|
|
113
|
+
{'action': 'blank'},
|
|
114
|
+
{'action': 'section_header', 'key': 'common_function_decls'},
|
|
115
|
+
{'action': 'blank'},
|
|
116
|
+
{'action': 'common_function_decls'},
|
|
117
|
+
{'action': 'blank'},
|
|
118
|
+
{'action': 'guard_end'},
|
|
119
|
+
],
|
|
120
|
+
'statable_types.h': [
|
|
121
|
+
{'action': 'file_header',
|
|
122
|
+
'filename': 'statable_types.h'},
|
|
123
|
+
{'action': 'blank'},
|
|
124
|
+
{'action': 'guard_start'},
|
|
125
|
+
{'action': 'include_section', 'key': 'types_layer'},
|
|
126
|
+
{'action': 'section_header', 'key': 'type_defs'},
|
|
127
|
+
{'action': 'blank'},
|
|
128
|
+
{'action': 'enums'},
|
|
129
|
+
{'action': 'blank'},
|
|
130
|
+
{'action': 'layer_transition_context'},
|
|
131
|
+
{'action': 'blank'},
|
|
132
|
+
{'action': 'guard_end'},
|
|
133
|
+
],
|
|
134
|
+
'statable_transitions.h': [
|
|
135
|
+
{'action': 'file_header',
|
|
136
|
+
'filename': 'statable_transitions.h'},
|
|
137
|
+
{'action': 'blank'},
|
|
138
|
+
{'action': 'guard_start'},
|
|
139
|
+
{'action': 'include_section',
|
|
140
|
+
'key': 'transitions_h'},
|
|
141
|
+
{'action': 'section_header',
|
|
142
|
+
'key': 'function_decls'},
|
|
143
|
+
{'action': 'blank'},
|
|
144
|
+
{'action': 'state_machine_decl'},
|
|
145
|
+
{'action': 'blank'},
|
|
146
|
+
{'action': 'guard_end'},
|
|
147
|
+
],
|
|
148
|
+
'statable_transitions.c': [
|
|
149
|
+
{'action': 'file_header',
|
|
150
|
+
'filename': 'statable_transitions.c'},
|
|
151
|
+
{'action': 'blank'},
|
|
152
|
+
{'action': 'include_section',
|
|
153
|
+
'key': 'transitions_c'},
|
|
154
|
+
{'action': 'section_header',
|
|
155
|
+
'key': 'transition_table'},
|
|
156
|
+
{'action': 'blank'},
|
|
157
|
+
{'action': 'cell_prototypes'},
|
|
158
|
+
{'action': 'blank'},
|
|
159
|
+
{'action': 'transition_table'},
|
|
160
|
+
{'action': 'blank'},
|
|
161
|
+
{'action': 'cell_functions'},
|
|
162
|
+
{'action': 'blank'},
|
|
163
|
+
{'action': 'section_header',
|
|
164
|
+
'key': 'transition_func'},
|
|
165
|
+
{'action': 'blank'},
|
|
166
|
+
{'action': 'process_func'},
|
|
167
|
+
{'action': 'blank'},
|
|
168
|
+
{'action': 'section_header',
|
|
169
|
+
'key': 'get_next_event'},
|
|
170
|
+
{'action': 'blank'},
|
|
171
|
+
{'action': 'get_next_event'},
|
|
172
|
+
],
|
|
173
|
+
'statable_role_functions.h': [
|
|
174
|
+
{'action': 'file_header',
|
|
175
|
+
'filename': 'statable_role_functions.h'},
|
|
176
|
+
{'action': 'blank'},
|
|
177
|
+
{'action': 'guard_start'},
|
|
178
|
+
{'action': 'include_section',
|
|
179
|
+
'key': 'role_functions_h'},
|
|
180
|
+
{'action': 'section_header',
|
|
181
|
+
'key': 'role_functions'},
|
|
182
|
+
{'action': 'blank'},
|
|
183
|
+
{'action': 'role_decls'},
|
|
184
|
+
{'action': 'blank'},
|
|
185
|
+
{'action': 'guard_end'},
|
|
186
|
+
],
|
|
187
|
+
'statable_role_functions.c': [
|
|
188
|
+
{'action': 'file_header',
|
|
189
|
+
'filename': 'statable_role_functions.c'},
|
|
190
|
+
{'action': 'blank'},
|
|
191
|
+
{'action': 'include_section',
|
|
192
|
+
'key': 'role_functions_c'},
|
|
193
|
+
{'action': 'section_header', 'key': 'role_impl'},
|
|
194
|
+
{'action': 'blank'},
|
|
195
|
+
{'action': 'role_impls'},
|
|
196
|
+
],
|
|
197
|
+
'statable_state_actions.h': [
|
|
198
|
+
{'action': 'file_header',
|
|
199
|
+
'filename': 'statable_state_actions.h'},
|
|
200
|
+
{'action': 'blank'},
|
|
201
|
+
{'action': 'guard_start'},
|
|
202
|
+
{'action': 'include_section', 'key': 'state_actions_h'},
|
|
203
|
+
{'action': 'section_header', 'key': 'state_actions'},
|
|
204
|
+
{'action': 'blank'},
|
|
205
|
+
{'action': 'state_actions_decls'},
|
|
206
|
+
{'action': 'blank'},
|
|
207
|
+
{'action': 'guard_end'},
|
|
208
|
+
],
|
|
209
|
+
'statable_state_actions.c': [
|
|
210
|
+
{'action': 'file_header',
|
|
211
|
+
'filename': 'statable_state_actions.c'},
|
|
212
|
+
{'action': 'blank'},
|
|
213
|
+
{'action': 'include_section', 'key': 'state_actions_c'},
|
|
214
|
+
{'action': 'section_header', 'key': 'state_actions'},
|
|
215
|
+
{'action': 'blank'},
|
|
216
|
+
{'action': 'state_actions_impls'},
|
|
217
|
+
],
|
|
218
|
+
'statable_init.c': [
|
|
219
|
+
{'action': 'file_header',
|
|
220
|
+
'filename': 'statable_init.c'},
|
|
221
|
+
{'action': 'blank'},
|
|
222
|
+
{'action': 'include_section', 'key': 'init_c'},
|
|
223
|
+
{'action': 'section_header', 'key': 'init_func'},
|
|
224
|
+
{'action': 'blank'},
|
|
225
|
+
{'action': 'init_func'},
|
|
226
|
+
{'action': 'blank'},
|
|
227
|
+
# [C-52] per-layer queue initialization
|
|
228
|
+
{'action': 'init_queues'},
|
|
229
|
+
],
|
|
230
|
+
'statable_event_queue.c': [
|
|
231
|
+
{'action': 'file_header',
|
|
232
|
+
'filename': 'statable_event_queue.c'},
|
|
233
|
+
{'action': 'blank'},
|
|
234
|
+
{'action': 'include_section',
|
|
235
|
+
'key': 'event_queue_c'},
|
|
236
|
+
{'action': 'event_queues'},
|
|
237
|
+
],
|
|
238
|
+
'statable_interrupt.c': [
|
|
239
|
+
{'action': 'file_header',
|
|
240
|
+
'filename': 'statable_interrupt.c'},
|
|
241
|
+
{'action': 'blank'},
|
|
242
|
+
{'action': 'include_section',
|
|
243
|
+
'key': 'interrupt_c'},
|
|
244
|
+
{'action': 'interrupts'},
|
|
245
|
+
],
|
|
246
|
+
'statable_timer.c': [
|
|
247
|
+
{'action': 'file_header',
|
|
248
|
+
'filename': 'statable_timer.c'},
|
|
249
|
+
{'action': 'blank'},
|
|
250
|
+
{'action': 'include_section', 'key': 'timer_c'},
|
|
251
|
+
{'action': 'section_header', 'key': 'type_defs'},
|
|
252
|
+
{'action': 'blank'},
|
|
253
|
+
{'action': 'timer_struct'},
|
|
254
|
+
{'action': 'blank'},
|
|
255
|
+
{'action': 'section_header', 'key': 'init_func'},
|
|
256
|
+
{'action': 'blank'},
|
|
257
|
+
{'action': 'timer_init'},
|
|
258
|
+
{'action': 'blank'},
|
|
259
|
+
{'action': 'section_header',
|
|
260
|
+
'key': 'transition_func'},
|
|
261
|
+
{'action': 'blank'},
|
|
262
|
+
{'action': 'timer_update'},
|
|
263
|
+
],
|
|
264
|
+
'osal.h': [
|
|
265
|
+
{'action': 'osal_header'},
|
|
266
|
+
],
|
|
267
|
+
'osal.c': [
|
|
268
|
+
{'action': 'osal_source'},
|
|
269
|
+
],
|
|
270
|
+
'statable_all.h': [
|
|
271
|
+
{'action': 'super_include_header'},
|
|
272
|
+
{'action': 'blank'},
|
|
273
|
+
{'action': 'super_include_guard_start'},
|
|
274
|
+
{'action': 'blank'},
|
|
275
|
+
{'action': 'super_include_common'},
|
|
276
|
+
{'action': 'blank'},
|
|
277
|
+
{'action': 'super_include_layer'},
|
|
278
|
+
{'action': 'blank'},
|
|
279
|
+
{'action': 'super_include_project'},
|
|
280
|
+
{'action': 'blank'},
|
|
281
|
+
{'action': 'super_include_extern_vars'},
|
|
282
|
+
{'action': 'blank'},
|
|
283
|
+
{'action': 'super_include_extern_funcs'},
|
|
284
|
+
{'action': 'blank'},
|
|
285
|
+
{'action': 'super_include_external',
|
|
286
|
+
'when': lambda c: (
|
|
287
|
+
c['config'].external_includes_in_super
|
|
288
|
+
and bool(c['config'].external_includes)
|
|
289
|
+
)},
|
|
290
|
+
{'action': 'blank',
|
|
291
|
+
'when': lambda c: (
|
|
292
|
+
c['config'].external_includes_in_super
|
|
293
|
+
and bool(c['config'].external_includes)
|
|
294
|
+
)},
|
|
295
|
+
{'action': 'super_include_user'},
|
|
296
|
+
{'action': 'blank'},
|
|
297
|
+
{'action': 'super_include_guard_end'},
|
|
298
|
+
],
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
STRUCT_KIND_DISPATCH: Dict[str, str] = {
|
|
302
|
+
'system_data': 'system_data',
|
|
303
|
+
'event_flags': 'event_flags',
|
|
304
|
+
'system_context': 'system_context',
|
|
305
|
+
'common_transition_context': 'common_transition_context',
|
|
306
|
+
'pending_event_macros': 'pending_event_macros',
|
|
307
|
+
# [C-52]
|
|
308
|
+
'layer_queue_types': 'layer_queue_types',
|
|
309
|
+
'layer_queue_macros': 'layer_queue_macros',
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
FILE_DISPATCH: Dict[str, str] = {
|
|
313
|
+
'statable_types_common.h': '_generate_types_common_header',
|
|
314
|
+
'statable_types.h': '_generate_types_header',
|
|
315
|
+
'statable_transitions.h': '_generate_transitions_header',
|
|
316
|
+
'statable_transitions.c': '_generate_transitions_source',
|
|
317
|
+
'statable_role_functions.h': '_generate_role_functions_header',
|
|
318
|
+
'statable_role_functions.c': '_generate_role_functions_source',
|
|
319
|
+
'statable_state_actions.h': '_generate_state_actions_header',
|
|
320
|
+
'statable_state_actions.c': '_generate_state_actions_source',
|
|
321
|
+
'statable_init.c': '_generate_init_source',
|
|
322
|
+
'statable_event_queue.c': '_generate_event_queue_source',
|
|
323
|
+
'statable_interrupt.c': '_generate_interrupt_source',
|
|
324
|
+
'statable_timer.c': '_generate_timer_source',
|
|
325
|
+
'osal.h': '_generate_osal_header',
|
|
326
|
+
'osal.c': '_generate_osal_source',
|
|
327
|
+
'statable_all.h': '_generate_super_include',
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
FILE_CATEGORY: Dict[str, str] = {
|
|
331
|
+
'statable_types_common.h': 'include',
|
|
332
|
+
'statable_types.h': 'include',
|
|
333
|
+
'statable_transitions.h': 'include',
|
|
334
|
+
'statable_role_functions.h': 'include',
|
|
335
|
+
'statable_state_actions.h': 'include',
|
|
336
|
+
'statable_state_actions.c': 'src',
|
|
337
|
+
'statable_transitions.c': 'src',
|
|
338
|
+
'statable_role_functions.c': 'src',
|
|
339
|
+
'statable_init.c': 'src',
|
|
340
|
+
'statable_event_queue.c': 'src',
|
|
341
|
+
'statable_interrupt.c': 'src',
|
|
342
|
+
'statable_timer.c': 'src',
|
|
343
|
+
'osal.h': 'common',
|
|
344
|
+
'osal.c': 'common',
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
FOLDER_STRUCTURE_RESOLVERS: Dict[str, str] = {
|
|
348
|
+
'flat': '_resolve_path_flat',
|
|
349
|
+
'by_type': '_resolve_path_by_type',
|
|
350
|
+
'by_layer': '_resolve_path_by_layer',
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
LAYER_SPECIFIC_FILES = {
|
|
354
|
+
'statable_types.h',
|
|
355
|
+
'statable_transitions.h',
|
|
356
|
+
'statable_transitions.c',
|
|
357
|
+
'statable_role_functions.h',
|
|
358
|
+
'statable_role_functions.c',
|
|
359
|
+
'statable_state_actions.h',
|
|
360
|
+
'statable_state_actions.c',
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
COMMON_FILES = {
|
|
364
|
+
'statable_types_common.h',
|
|
365
|
+
'statable_init.c',
|
|
366
|
+
'statable_event_queue.c',
|
|
367
|
+
'statable_interrupt.c',
|
|
368
|
+
'statable_timer.c',
|
|
369
|
+
'osal.h',
|
|
370
|
+
'osal.c',
|
|
371
|
+
'statable_all.h',
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
def __init__(self,
|
|
375
|
+
config: Optional[CodeGenerationConfig] = None):
|
|
376
|
+
self.mapper = CTypeMapper()
|
|
377
|
+
self.naming = CNamingConvention()
|
|
378
|
+
self.struct_gen = CStructGenerator()
|
|
379
|
+
self.enum_gen = CEnumGenerator()
|
|
380
|
+
self.transition_gen = TransitionGenerator()
|
|
381
|
+
self.role_func_gen = RoleFunctionGenerator()
|
|
382
|
+
self.variable_gen = VariableGenerator()
|
|
383
|
+
self.event_queue_gen = EventQueueGenerator()
|
|
384
|
+
self.interrupt_gen = InterruptGenerator()
|
|
385
|
+
self.timer_gen = TimerGenerator()
|
|
386
|
+
self.osal_gen = OSALGenerator()
|
|
387
|
+
self.state_actions_gen = StateActionsGenerator()
|
|
388
|
+
self.templates = CodeTemplates()
|
|
389
|
+
self.strings = self.templates.STRINGS
|
|
390
|
+
self.formats = self.templates.FORMATS
|
|
391
|
+
self.merger = CodeMerger()
|
|
392
|
+
|
|
393
|
+
self.config_manager = ConfigManager()
|
|
394
|
+
if config:
|
|
395
|
+
self.config_manager.set_config(config)
|
|
396
|
+
self.config = self.config_manager.get_config()
|
|
397
|
+
|
|
398
|
+
self.generation_date = (
|
|
399
|
+
datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
self._current_role_function_library = None
|
|
403
|
+
|
|
404
|
+
self._all_layers_for_includes: Optional[
|
|
405
|
+
List[Tuple[str, StateMachine]]
|
|
406
|
+
] = None
|
|
407
|
+
|
|
408
|
+
self.super_loop_filename = (
|
|
409
|
+
f"{self.config.project_name}_run.c"
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
self.FILE_STEPS = dict(self.__class__.FILE_STEPS)
|
|
413
|
+
self.FILE_DISPATCH = dict(self.__class__.FILE_DISPATCH)
|
|
414
|
+
self.FILE_CATEGORY = dict(self.__class__.FILE_CATEGORY)
|
|
415
|
+
|
|
416
|
+
self.FILE_STEPS[self.super_loop_filename] = [
|
|
417
|
+
{'action': 'super_loop_header'},
|
|
418
|
+
{'action': 'blank'},
|
|
419
|
+
{'action': 'super_loop_include'},
|
|
420
|
+
{'action': 'blank'},
|
|
421
|
+
{'action': 'super_loop_context_var'},
|
|
422
|
+
{'action': 'blank'},
|
|
423
|
+
{'action': 'super_loop_state_var'},
|
|
424
|
+
{'action': 'blank'},
|
|
425
|
+
{'action': 'super_loop_init_func'},
|
|
426
|
+
{'action': 'blank'},
|
|
427
|
+
{'action': 'super_loop_run_func'},
|
|
428
|
+
]
|
|
429
|
+
self.FILE_DISPATCH[self.super_loop_filename] = \
|
|
430
|
+
'_generate_super_loop'
|
|
431
|
+
self.FILE_CATEGORY[self.super_loop_filename] = 'src'
|
|
432
|
+
|
|
433
|
+
self.file_generators: Dict[str, Dict] = {
|
|
434
|
+
'statable_types_common.h': {
|
|
435
|
+
'description': 'Common type definitions for state transition system',
|
|
436
|
+
'guard_name': 'STATABLE_TYPES_COMMON_H',
|
|
437
|
+
},
|
|
438
|
+
'statable_types.h': {
|
|
439
|
+
'description': 'Layer-specific type definitions (enum)',
|
|
440
|
+
'guard_name': 'STATABLE_TYPES_H',
|
|
441
|
+
},
|
|
442
|
+
'statable_transitions.h': {
|
|
443
|
+
'description': 'State transition function declarations',
|
|
444
|
+
'guard_name': 'STATABLE_TRANSITIONS_H',
|
|
445
|
+
},
|
|
446
|
+
'statable_transitions.c': {
|
|
447
|
+
'description': 'State transition logic',
|
|
448
|
+
'guard_name': None,
|
|
449
|
+
},
|
|
450
|
+
'statable_role_functions.h': {
|
|
451
|
+
'description': 'Role function declarations',
|
|
452
|
+
'guard_name': 'STATABLE_ROLE_FUNCTIONS_H',
|
|
453
|
+
},
|
|
454
|
+
'statable_role_functions.c': {
|
|
455
|
+
'description': 'Role function implementations',
|
|
456
|
+
'guard_name': None,
|
|
457
|
+
},
|
|
458
|
+
'statable_state_actions.h': {
|
|
459
|
+
'description': 'State actions (Entry / Exit / Do) declarations',
|
|
460
|
+
'guard_name': 'STATABLE_STATE_ACTIONS_H',
|
|
461
|
+
},
|
|
462
|
+
'statable_state_actions.c': {
|
|
463
|
+
'description': 'State actions (Entry / Exit / Do) implementations',
|
|
464
|
+
'guard_name': None,
|
|
465
|
+
},
|
|
466
|
+
'statable_init.c': {
|
|
467
|
+
'description': 'Initialization processing',
|
|
468
|
+
'guard_name': None,
|
|
469
|
+
},
|
|
470
|
+
'statable_event_queue.c': {
|
|
471
|
+
'description': 'Event queue implementation',
|
|
472
|
+
'guard_name': None,
|
|
473
|
+
},
|
|
474
|
+
'statable_interrupt.c': {
|
|
475
|
+
'description': 'Interrupt handler ISR',
|
|
476
|
+
'guard_name': None,
|
|
477
|
+
},
|
|
478
|
+
'statable_timer.c': {
|
|
479
|
+
'description': 'Timer processing',
|
|
480
|
+
'guard_name': None,
|
|
481
|
+
},
|
|
482
|
+
'osal.h': {
|
|
483
|
+
'description': 'OSAL header',
|
|
484
|
+
'guard_name': 'OSAL_H',
|
|
485
|
+
},
|
|
486
|
+
'osal.c': {
|
|
487
|
+
'description': 'OSAL source',
|
|
488
|
+
'guard_name': None,
|
|
489
|
+
},
|
|
490
|
+
'statable_all.h': {
|
|
491
|
+
'description': 'StaTable super include',
|
|
492
|
+
'guard_name': 'STATABLE_ALL_H',
|
|
493
|
+
},
|
|
494
|
+
self.super_loop_filename: {
|
|
495
|
+
'description': 'State machine super loop',
|
|
496
|
+
'guard_name': None,
|
|
497
|
+
},
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
# [v2.2.9 / MISRA 17.3 fix] statable_types_common.h added to
|
|
501
|
+
# transitions_c so LOG_* macros are visible in file scope.
|
|
502
|
+
self.include_headers: Dict[str, List[str]] = {
|
|
503
|
+
'types': [
|
|
504
|
+
'#include <stdint.h>',
|
|
505
|
+
'#include <stdbool.h>',
|
|
506
|
+
'#include <string.h>',
|
|
507
|
+
],
|
|
508
|
+
'types_layer': [
|
|
509
|
+
'#include "statable_types_common.h"',
|
|
510
|
+
],
|
|
511
|
+
'transitions_h': [
|
|
512
|
+
'#include "statable_types{layer_suffix}.h"',
|
|
513
|
+
],
|
|
514
|
+
'transitions_c': [
|
|
515
|
+
'#include "statable_transitions{layer_suffix}.h"',
|
|
516
|
+
'#include "statable_role_functions{layer_suffix}.h"',
|
|
517
|
+
'#include "statable_state_actions{layer_suffix}.h"',
|
|
518
|
+
'#include "statable_types_common.h"',
|
|
519
|
+
],
|
|
520
|
+
'role_functions_h': [
|
|
521
|
+
'#include "statable_types{layer_suffix}.h"',
|
|
522
|
+
],
|
|
523
|
+
'role_functions_c': [
|
|
524
|
+
'#include "statable_role_functions{layer_suffix}.h"',
|
|
525
|
+
],
|
|
526
|
+
'state_actions_h': [
|
|
527
|
+
'#include "statable_types_common.h"',
|
|
528
|
+
'#include "statable_types{layer_suffix}.h"',
|
|
529
|
+
],
|
|
530
|
+
'state_actions_c': [
|
|
531
|
+
'#include "statable_state_actions{layer_suffix}.h"',
|
|
532
|
+
'#include "statable_role_functions{layer_suffix}.h"',
|
|
533
|
+
'#include "statable_types_common.h"',
|
|
534
|
+
],
|
|
535
|
+
'init_c': ['#include "statable_types_common.h"'],
|
|
536
|
+
'event_queue_c': ['#include "statable_types_common.h"'],
|
|
537
|
+
'interrupt_c': [
|
|
538
|
+
'#include "statable_types_common.h"',
|
|
539
|
+
'#include "statable_all.h"',
|
|
540
|
+
],
|
|
541
|
+
'timer_c': ['#include "statable_types_common.h"'],
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
self.step_executors: Dict[str, Callable] = {
|
|
545
|
+
'file_header': self._step_file_header,
|
|
546
|
+
'blank': self._step_blank,
|
|
547
|
+
'guard_start': self._step_guard_start,
|
|
548
|
+
'guard_end': self._step_guard_end,
|
|
549
|
+
'include_section': self._step_include_section,
|
|
550
|
+
'section_header': self._step_section_header,
|
|
551
|
+
'enums': self._step_enums,
|
|
552
|
+
'enums_common': self._step_enums_common,
|
|
553
|
+
'layer_transition_context': self._step_layer_transition_context,
|
|
554
|
+
'common_function_decls': self._step_common_function_decls,
|
|
555
|
+
'custom_types': self._step_custom_types,
|
|
556
|
+
'struct': self._step_struct,
|
|
557
|
+
'var_macros': self._step_var_macros,
|
|
558
|
+
'state_machine_decl': self._step_state_machine_decl,
|
|
559
|
+
'cell_prototypes': self._step_cell_prototypes,
|
|
560
|
+
'transition_table': self._step_transition_table,
|
|
561
|
+
'cell_functions': self._step_cell_functions,
|
|
562
|
+
'process_func': self._step_process_func,
|
|
563
|
+
'get_next_event': self._step_get_next_event,
|
|
564
|
+
'role_decls': self._step_role_decls,
|
|
565
|
+
'role_impls': self._step_role_impls,
|
|
566
|
+
'state_actions_decls': self._step_state_actions_decls,
|
|
567
|
+
'state_actions_impls': self._step_state_actions_impls,
|
|
568
|
+
'init_func': self._step_init_func,
|
|
569
|
+
'init_queues': self._step_init_queues,
|
|
570
|
+
'event_queues': self._step_event_queues,
|
|
571
|
+
'interrupts': self._step_interrupts,
|
|
572
|
+
'timer_struct': self._step_timer_struct,
|
|
573
|
+
'timer_init': self._step_timer_init,
|
|
574
|
+
'timer_update': self._step_timer_update,
|
|
575
|
+
'osal_header': self._step_osal_header,
|
|
576
|
+
'osal_source': self._step_osal_source,
|
|
577
|
+
'super_include_header': self._step_super_include_header,
|
|
578
|
+
'super_include_guard_start': self._step_super_include_guard_start,
|
|
579
|
+
'super_include_common': self._step_super_include_common,
|
|
580
|
+
'super_include_layer': self._step_super_include_layer,
|
|
581
|
+
'super_include_project': self._step_super_include_project,
|
|
582
|
+
'super_include_extern_vars': self._step_super_include_extern_vars,
|
|
583
|
+
'super_include_extern_funcs': self._step_super_include_extern_funcs,
|
|
584
|
+
'super_include_external': self._step_super_include_external,
|
|
585
|
+
'super_include_user': self._step_super_include_user,
|
|
586
|
+
'super_include_guard_end': self._step_super_include_guard_end,
|
|
587
|
+
'super_loop_header': self._step_super_loop_header,
|
|
588
|
+
'super_loop_include': self._step_super_loop_include,
|
|
589
|
+
'super_loop_context_var': self._step_super_loop_context_var,
|
|
590
|
+
'super_loop_state_var': self._step_super_loop_state_var,
|
|
591
|
+
'super_loop_init_func': self._step_super_loop_init_func,
|
|
592
|
+
'super_loop_run_func': self._step_super_loop_run_func,
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
def _log_debug(self, message, level='debug'):
|
|
596
|
+
log_func = getattr(logger, level, logger.debug)
|
|
597
|
+
log_func(message)
|
|
598
|
+
|
|
599
|
+
def get_config(self) -> CodeGenerationConfig:
|
|
600
|
+
return self.config
|
|
601
|
+
|
|
602
|
+
def set_config(self, config: CodeGenerationConfig):
|
|
603
|
+
self.config_manager.set_config(config)
|
|
604
|
+
self.config = self.config_manager.get_config()
|
|
605
|
+
|
|
606
|
+
def update_config(self, **kwargs):
|
|
607
|
+
self.config_manager.update(**kwargs)
|
|
608
|
+
self.config = self.config_manager.get_config()
|
|
609
|
+
|
|
610
|
+
def reset_config(self):
|
|
611
|
+
self.config_manager.reset()
|
|
612
|
+
self.config = self.config_manager.get_config()
|
|
613
|
+
|
|
614
|
+
def _get_states_list(self, state_machine):
|
|
615
|
+
return list(state_machine.states.values())
|
|
616
|
+
|
|
617
|
+
def _get_events_list(self, state_machine):
|
|
618
|
+
return list(state_machine.events.values())
|
|
619
|
+
|
|
620
|
+
def _get_role_functions_list(self, state_machine):
|
|
621
|
+
funcs = dict(state_machine.role_functions)
|
|
622
|
+
lib = self._current_role_function_library
|
|
623
|
+
if lib is not None:
|
|
624
|
+
for rf in lib.list_all():
|
|
625
|
+
name = getattr(rf, 'name', None)
|
|
626
|
+
if name and name not in funcs:
|
|
627
|
+
funcs[name] = rf
|
|
628
|
+
return list(funcs.values())
|
|
629
|
+
|
|
630
|
+
def _get_layer_name(self, state_machine) -> str:
|
|
631
|
+
return getattr(state_machine, 'layer_name', '') or ''
|
|
632
|
+
|
|
633
|
+
def _get_initial_state(self, state_machine) -> str:
|
|
634
|
+
initial = getattr(state_machine, 'initial_state', None)
|
|
635
|
+
if not initial:
|
|
636
|
+
initial = getattr(state_machine, 'initial', None)
|
|
637
|
+
return initial or 'Idle'
|
|
638
|
+
|
|
639
|
+
def _generate_section_header(self, section_key):
|
|
640
|
+
start = self.strings['section_line_start']
|
|
641
|
+
end = self.strings['section_line_end']
|
|
642
|
+
title = self.templates.SECTION_HEADERS.get(section_key, '')
|
|
643
|
+
return f"{start}\n * {title}\n{end}"
|
|
644
|
+
|
|
645
|
+
def _generate_file_header(self, filename, description=""):
|
|
646
|
+
return (
|
|
647
|
+
f"/**\n"
|
|
648
|
+
f" * @file {filename}\n"
|
|
649
|
+
f" * @brief {description}\n"
|
|
650
|
+
f" *\n"
|
|
651
|
+
f" * @note {self.strings['auto_generated']}\n"
|
|
652
|
+
f" * - {self.strings['no_edit']}\n"
|
|
653
|
+
f" * - {self.strings['edit_in_statable']}\n"
|
|
654
|
+
f" *\n"
|
|
655
|
+
f" * @date {self.generation_date}\n"
|
|
656
|
+
f" */"
|
|
657
|
+
)
|
|
658
|
+
|
|
659
|
+
def _generate_include_guard_start(self, guard_name):
|
|
660
|
+
return f"#ifndef {guard_name}\n#define {guard_name}\n"
|
|
661
|
+
|
|
662
|
+
def _generate_include_guard_end(self, guard_name):
|
|
663
|
+
return f"#endif /* {guard_name} */"
|
|
664
|
+
|
|
665
|
+
def _generate_include_section(self, include_key, layer_suffix=''):
|
|
666
|
+
lines = [self._generate_section_header('include'), ""]
|
|
667
|
+
for header in self.include_headers.get(include_key, []):
|
|
668
|
+
header = header.replace('{layer_suffix}', layer_suffix)
|
|
669
|
+
lines.append(header)
|
|
670
|
+
lines.append("")
|
|
671
|
+
return '\n'.join(lines)
|
|
672
|
+
|
|
673
|
+
def _layer_filename(self, filename: str, layer_name: str) -> str:
|
|
674
|
+
if not layer_name:
|
|
675
|
+
return filename
|
|
676
|
+
if filename not in self.LAYER_SPECIFIC_FILES:
|
|
677
|
+
return filename
|
|
678
|
+
stem, ext = os.path.splitext(filename)
|
|
679
|
+
return f"{stem}_{layer_name}{ext}"
|
|
680
|
+
|
|
681
|
+
def _layer_suffix(self, layer_name: str) -> str:
|
|
682
|
+
return f"_{layer_name}" if layer_name else ""
|
|
683
|
+
|
|
684
|
+
def _normalize_layers(self, layers) -> List[Tuple[str, StateMachine]]:
|
|
685
|
+
if layers is None:
|
|
686
|
+
return []
|
|
687
|
+
if isinstance(layers, StateMachine):
|
|
688
|
+
name = self._get_layer_name(layers)
|
|
689
|
+
return [(name, layers)]
|
|
690
|
+
result = []
|
|
691
|
+
for item in layers:
|
|
692
|
+
if isinstance(item, tuple) and len(item) == 2:
|
|
693
|
+
name, sm = item
|
|
694
|
+
elif isinstance(item, StateMachine):
|
|
695
|
+
name = self._get_layer_name(item)
|
|
696
|
+
sm = item
|
|
697
|
+
else:
|
|
698
|
+
continue
|
|
699
|
+
if not self._get_layer_name(sm) and name:
|
|
700
|
+
sm.layer_name = name
|
|
701
|
+
result.append((name, sm))
|
|
702
|
+
result.sort(key=lambda x: getattr(x[1], 'layer_priority', 5))
|
|
703
|
+
return result
|
|
704
|
+
|
|
705
|
+
def _setup_layer_generators(self, state_machine):
|
|
706
|
+
layer_name = self._get_layer_name(state_machine)
|
|
707
|
+
for name, gen in [
|
|
708
|
+
('enum_gen', self.enum_gen),
|
|
709
|
+
('transition_gen', self.transition_gen),
|
|
710
|
+
('role_func_gen', self.role_func_gen),
|
|
711
|
+
('state_actions_gen', self.state_actions_gen),
|
|
712
|
+
('struct_gen', self.struct_gen),
|
|
713
|
+
('interrupt_gen', self.interrupt_gen),
|
|
714
|
+
]:
|
|
715
|
+
if hasattr(gen, 'set_layer'):
|
|
716
|
+
gen.set_layer(layer_name)
|
|
717
|
+
|
|
718
|
+
def _resolve_output_path(self, filename: str,
|
|
719
|
+
layer_name: str = '') -> str:
|
|
720
|
+
if '/' in filename or '\\' in filename:
|
|
721
|
+
return filename
|
|
722
|
+
if filename == 'statable_all.h':
|
|
723
|
+
return self._resolve_super_include_path(layer_name)
|
|
724
|
+
structure = self.config.folder_structure
|
|
725
|
+
resolver_name = self.FOLDER_STRUCTURE_RESOLVERS.get(
|
|
726
|
+
structure, '_resolve_path_flat'
|
|
727
|
+
)
|
|
728
|
+
resolver = getattr(self, resolver_name,
|
|
729
|
+
self._resolve_path_flat)
|
|
730
|
+
return resolver(filename, layer_name)
|
|
731
|
+
|
|
732
|
+
def _resolve_super_include_path(self, layer_name: str = '') -> str:
|
|
733
|
+
fname = self.config.super_include_file
|
|
734
|
+
structure = self.config.folder_structure
|
|
735
|
+
if structure == 'flat':
|
|
736
|
+
return fname
|
|
737
|
+
elif structure == 'by_type':
|
|
738
|
+
return os.path.join(
|
|
739
|
+
self.config.super_include_dir, fname
|
|
740
|
+
)
|
|
741
|
+
elif structure == 'by_layer':
|
|
742
|
+
if layer_name:
|
|
743
|
+
return os.path.join(layer_name, fname)
|
|
744
|
+
return fname
|
|
745
|
+
return fname
|
|
746
|
+
|
|
747
|
+
def _resolve_path_flat(self, filename: str,
|
|
748
|
+
layer_name: str = '') -> str:
|
|
749
|
+
return filename
|
|
750
|
+
|
|
751
|
+
def _resolve_path_by_type(self, filename: str,
|
|
752
|
+
layer_name: str = '') -> str:
|
|
753
|
+
category = self.FILE_CATEGORY.get(filename, '')
|
|
754
|
+
if category == 'include':
|
|
755
|
+
return os.path.join(
|
|
756
|
+
self.config.include_dir_name, filename
|
|
757
|
+
)
|
|
758
|
+
elif category == 'src':
|
|
759
|
+
return os.path.join(
|
|
760
|
+
self.config.source_dir_name, filename
|
|
761
|
+
)
|
|
762
|
+
elif category == 'common':
|
|
763
|
+
return os.path.join(
|
|
764
|
+
self.config.common_dir_name, filename
|
|
765
|
+
)
|
|
766
|
+
return filename
|
|
767
|
+
|
|
768
|
+
def _resolve_path_by_layer(self, filename: str,
|
|
769
|
+
layer_name: str = '') -> str:
|
|
770
|
+
if not layer_name:
|
|
771
|
+
return filename
|
|
772
|
+
if filename in self.LAYER_SPECIFIC_FILES:
|
|
773
|
+
fname = self._layer_filename(filename, layer_name)
|
|
774
|
+
return os.path.join(layer_name, fname)
|
|
775
|
+
return filename
|
|
776
|
+
|
|
777
|
+
def _run_steps(self, filename,
|
|
778
|
+
state_machine, global_defs) -> str:
|
|
779
|
+
return self._run_steps_multi(
|
|
780
|
+
filename,
|
|
781
|
+
[(self._get_layer_name(state_machine), state_machine)],
|
|
782
|
+
global_defs
|
|
783
|
+
)
|
|
784
|
+
|
|
785
|
+
def _run_steps_multi(self, filename,
|
|
786
|
+
layers: List[Tuple[str, StateMachine]],
|
|
787
|
+
global_defs) -> str:
|
|
788
|
+
if not layers:
|
|
789
|
+
return ""
|
|
790
|
+
file_config = self.file_generators[filename]
|
|
791
|
+
steps = self.FILE_STEPS.get(filename, [])
|
|
792
|
+
context = {
|
|
793
|
+
'layers': layers,
|
|
794
|
+
'state_machine': layers[0][1],
|
|
795
|
+
'global_defs': global_defs,
|
|
796
|
+
'file_config': file_config,
|
|
797
|
+
'filename': filename,
|
|
798
|
+
'config': self.config,
|
|
799
|
+
'is_multi': len(layers) > 1,
|
|
800
|
+
}
|
|
801
|
+
parts: List[str] = []
|
|
802
|
+
for step in steps:
|
|
803
|
+
when = step.get('when')
|
|
804
|
+
if when is not None and not when(context):
|
|
805
|
+
continue
|
|
806
|
+
action = step.get('action', '')
|
|
807
|
+
executor = self.step_executors.get(action)
|
|
808
|
+
if executor is None:
|
|
809
|
+
self._log_debug(
|
|
810
|
+
f"Unknown step action: {action}", 'warning'
|
|
811
|
+
)
|
|
812
|
+
continue
|
|
813
|
+
result = executor(step, context)
|
|
814
|
+
if result is None:
|
|
815
|
+
continue
|
|
816
|
+
if isinstance(result, list):
|
|
817
|
+
parts.extend(result)
|
|
818
|
+
else:
|
|
819
|
+
parts.append(result)
|
|
820
|
+
return '\n'.join(parts)
|
|
821
|
+
|
|
822
|
+
def _step_file_header(self, step, ctx):
|
|
823
|
+
filename = step.get('filename', ctx['filename'])
|
|
824
|
+
layers = ctx.get('layers', [])
|
|
825
|
+
if (filename in self.LAYER_SPECIFIC_FILES and layers):
|
|
826
|
+
layer_name = self._get_layer_name(layers[0][1])
|
|
827
|
+
filename = self._layer_filename(filename, layer_name)
|
|
828
|
+
desc = ctx['file_config'].get('description', '')
|
|
829
|
+
return [self._generate_file_header(filename, desc)]
|
|
830
|
+
|
|
831
|
+
def _step_blank(self, step, ctx):
|
|
832
|
+
return [""]
|
|
833
|
+
|
|
834
|
+
def _step_guard_start(self, step, ctx):
|
|
835
|
+
guard = ctx['file_config'].get('guard_name')
|
|
836
|
+
if not guard:
|
|
837
|
+
return []
|
|
838
|
+
filename = ctx.get('filename', '')
|
|
839
|
+
layers = ctx.get('layers', [])
|
|
840
|
+
if filename in self.LAYER_SPECIFIC_FILES and layers:
|
|
841
|
+
layer_name = self._get_layer_name(layers[0][1])
|
|
842
|
+
if layer_name:
|
|
843
|
+
guard = f"{guard}_{layer_name.upper()}"
|
|
844
|
+
return [self._generate_include_guard_start(guard)]
|
|
845
|
+
|
|
846
|
+
def _step_guard_end(self, step, ctx):
|
|
847
|
+
guard = ctx['file_config'].get('guard_name')
|
|
848
|
+
if not guard:
|
|
849
|
+
return []
|
|
850
|
+
filename = ctx.get('filename', '')
|
|
851
|
+
layers = ctx.get('layers', [])
|
|
852
|
+
if filename in self.LAYER_SPECIFIC_FILES and layers:
|
|
853
|
+
layer_name = self._get_layer_name(layers[0][1])
|
|
854
|
+
if layer_name:
|
|
855
|
+
guard = f"{guard}_{layer_name.upper()}"
|
|
856
|
+
return [self._generate_include_guard_end(guard)]
|
|
857
|
+
|
|
858
|
+
def _step_include_section(self, step, ctx):
|
|
859
|
+
key = step.get('key', '')
|
|
860
|
+
filename = ctx.get('filename', '')
|
|
861
|
+
layers = ctx.get('layers', [])
|
|
862
|
+
structure = ctx['config'].folder_structure
|
|
863
|
+
|
|
864
|
+
if filename in self.LAYER_SPECIFIC_FILES and layers:
|
|
865
|
+
layer_name = self._get_layer_name(layers[0][1])
|
|
866
|
+
suffix = self._layer_suffix(layer_name)
|
|
867
|
+
|
|
868
|
+
if (structure == 'by_layer'
|
|
869
|
+
and filename in ('statable_transitions.c',
|
|
870
|
+
'statable_role_functions.c',
|
|
871
|
+
'statable_state_actions.c')):
|
|
872
|
+
lines = [self._generate_section_header('include'), ""]
|
|
873
|
+
for header in self.include_headers.get(key, []):
|
|
874
|
+
header = header.replace('{layer_suffix}', suffix)
|
|
875
|
+
lines.append(header)
|
|
876
|
+
all_layers = (self._all_layers_for_includes
|
|
877
|
+
or layers)
|
|
878
|
+
for other_name, other_sm in all_layers:
|
|
879
|
+
other_layer = self._get_layer_name(other_sm)
|
|
880
|
+
if not other_layer or other_layer == layer_name:
|
|
881
|
+
continue
|
|
882
|
+
lines.append(
|
|
883
|
+
f'#include "{other_layer}/'
|
|
884
|
+
f'statable_role_functions_{other_layer}.h"'
|
|
885
|
+
)
|
|
886
|
+
lines.append("")
|
|
887
|
+
return ['\n'.join(lines)]
|
|
888
|
+
|
|
889
|
+
return [self._generate_include_section(
|
|
890
|
+
key, layer_suffix=suffix
|
|
891
|
+
)]
|
|
892
|
+
|
|
893
|
+
if structure == 'by_layer' and filename in (
|
|
894
|
+
'statable_init.c',
|
|
895
|
+
'statable_event_queue.c',
|
|
896
|
+
'statable_interrupt.c',
|
|
897
|
+
'statable_timer.c'):
|
|
898
|
+
lines = [self._generate_section_header('include'), ""]
|
|
899
|
+
if filename == 'statable_interrupt.c':
|
|
900
|
+
lines.append('#include "statable_all.h"')
|
|
901
|
+
else:
|
|
902
|
+
lines.append('#include "statable_types_common.h"')
|
|
903
|
+
for layer_name, sm in layers:
|
|
904
|
+
layer = self._get_layer_name(sm)
|
|
905
|
+
if layer:
|
|
906
|
+
lines.append(
|
|
907
|
+
f'#include "{layer}/'
|
|
908
|
+
f'statable_types_{layer}.h"'
|
|
909
|
+
)
|
|
910
|
+
lines.append("")
|
|
911
|
+
return ['\n'.join(lines)]
|
|
912
|
+
|
|
913
|
+
return [self._generate_include_section(key)]
|
|
914
|
+
|
|
915
|
+
def _step_section_header(self, step, ctx):
|
|
916
|
+
return [self._generate_section_header(
|
|
917
|
+
step.get('key', '')
|
|
918
|
+
)]
|
|
919
|
+
|
|
920
|
+
def _step_enums(self, step, ctx):
|
|
921
|
+
gd = ctx['global_defs']
|
|
922
|
+
layers = ctx['layers']
|
|
923
|
+
results = []
|
|
924
|
+
for layer_name, sm in layers:
|
|
925
|
+
self._setup_layer_generators(sm)
|
|
926
|
+
enum_code = self.enum_gen.generate_all_enums(
|
|
927
|
+
self._get_states_list(sm),
|
|
928
|
+
self._get_events_list(sm),
|
|
929
|
+
None,
|
|
930
|
+
)
|
|
931
|
+
if enum_code:
|
|
932
|
+
results.append(enum_code)
|
|
933
|
+
if not results:
|
|
934
|
+
return ['']
|
|
935
|
+
return ['\n'.join(results)]
|
|
936
|
+
|
|
937
|
+
def _step_enums_common(self, step, ctx):
|
|
938
|
+
gd = ctx['global_defs']
|
|
939
|
+
flags = getattr(gd, 'flags', []) or []
|
|
940
|
+
if not flags:
|
|
941
|
+
return ['']
|
|
942
|
+
self.enum_gen.set_layer("")
|
|
943
|
+
code = self.enum_gen.generate_flag_enum(flags)
|
|
944
|
+
return [code] if code else ['']
|
|
945
|
+
|
|
946
|
+
def _step_layer_transition_context(self, step, ctx):
|
|
947
|
+
layers = ctx['layers']
|
|
948
|
+
results = []
|
|
949
|
+
for layer_name, sm in layers:
|
|
950
|
+
layer = self._get_layer_name(sm)
|
|
951
|
+
if not layer:
|
|
952
|
+
continue
|
|
953
|
+
self.struct_gen.set_layer(layer)
|
|
954
|
+
state_type = f"STATE_{layer}_t"
|
|
955
|
+
event_type = f"EVENT_{layer}_t"
|
|
956
|
+
code = self.struct_gen.generate_layer_transition_context(
|
|
957
|
+
state_type, event_type,
|
|
958
|
+
)
|
|
959
|
+
if code:
|
|
960
|
+
results.append(code)
|
|
961
|
+
return ['\n\n'.join(results)] if results else ['']
|
|
962
|
+
|
|
963
|
+
def _step_common_function_decls(self, step, ctx):
|
|
964
|
+
return [
|
|
965
|
+
'/* ---- Logging macros (default: no-op) ---- */',
|
|
966
|
+
'/*',
|
|
967
|
+
' * These are safe defaults. To enable real logging,',
|
|
968
|
+
' * define the macros before including this header.',
|
|
969
|
+
' */',
|
|
970
|
+
'#ifndef LOG_DEBUG',
|
|
971
|
+
'#define LOG_DEBUG(...) ((void)0)',
|
|
972
|
+
'#endif',
|
|
973
|
+
'',
|
|
974
|
+
'#ifndef LOG_INFO',
|
|
975
|
+
'#define LOG_INFO(...) ((void)0)',
|
|
976
|
+
'#endif',
|
|
977
|
+
'',
|
|
978
|
+
'#ifndef LOG_WARNING',
|
|
979
|
+
'#define LOG_WARNING(...) ((void)0)',
|
|
980
|
+
'#endif',
|
|
981
|
+
'',
|
|
982
|
+
'#ifndef LOG_ERROR',
|
|
983
|
+
'#define LOG_ERROR(...) ((void)0)',
|
|
984
|
+
'#endif',
|
|
985
|
+
'',
|
|
986
|
+
'/**',
|
|
987
|
+
' * @brief Initialize SystemContext_t (implemented in statable_init.c)',
|
|
988
|
+
' * @param ctx System context pointer',
|
|
989
|
+
' */',
|
|
990
|
+
'void SystemContext_Init(SystemContext_t *ctx);',
|
|
991
|
+
'',
|
|
992
|
+
'/**',
|
|
993
|
+
' * @brief Initialize per-layer event queues (C-52)',
|
|
994
|
+
' * @param ctx System context pointer',
|
|
995
|
+
' */',
|
|
996
|
+
'void SystemContext_InitQueues(SystemContext_t *ctx);',
|
|
997
|
+
'',
|
|
998
|
+
'/**',
|
|
999
|
+
' * @brief Initialize timer variables (implemented in statable_timer.c)',
|
|
1000
|
+
' * @param ctx System context pointer',
|
|
1001
|
+
' */',
|
|
1002
|
+
'void Timer_Init(SystemContext_t *ctx);',
|
|
1003
|
+
'',
|
|
1004
|
+
'/**',
|
|
1005
|
+
' * @brief Update derived timer variables (implemented in statable_timer.c)',
|
|
1006
|
+
' * @param ctx System context pointer',
|
|
1007
|
+
' */',
|
|
1008
|
+
'void Timer_Update(SystemContext_t *ctx);',
|
|
1009
|
+
]
|
|
1010
|
+
|
|
1011
|
+
def _step_custom_types(self, step, ctx):
|
|
1012
|
+
gd = ctx['global_defs']
|
|
1013
|
+
result: List[str] = [
|
|
1014
|
+
self._generate_section_header('custom_types'),
|
|
1015
|
+
"",
|
|
1016
|
+
]
|
|
1017
|
+
for custom_type in gd.custom_types:
|
|
1018
|
+
result.append(self.struct_gen.generate_struct(
|
|
1019
|
+
'custom_type', custom_type
|
|
1020
|
+
))
|
|
1021
|
+
result.append("")
|
|
1022
|
+
return result
|
|
1023
|
+
|
|
1024
|
+
def _step_struct(self, step, ctx):
|
|
1025
|
+
kind = step.get('kind', '')
|
|
1026
|
+
method_name = self.STRUCT_KIND_DISPATCH.get(kind)
|
|
1027
|
+
if method_name is None:
|
|
1028
|
+
return []
|
|
1029
|
+
# [C-52] propagate layer list for queue members/macros
|
|
1030
|
+
self.struct_gen.set_layers(ctx.get('layers', []))
|
|
1031
|
+
return [self.struct_gen.generate_struct(
|
|
1032
|
+
kind, ctx['global_defs']
|
|
1033
|
+
)]
|
|
1034
|
+
|
|
1035
|
+
def _step_var_macros(self, step, ctx):
|
|
1036
|
+
return [self.variable_gen.generate_all_macros(
|
|
1037
|
+
ctx['global_defs']
|
|
1038
|
+
)]
|
|
1039
|
+
|
|
1040
|
+
def _step_state_machine_decl(self, step, ctx):
|
|
1041
|
+
layers = ctx['layers']
|
|
1042
|
+
results = []
|
|
1043
|
+
for layer_name, sm in layers:
|
|
1044
|
+
layer = self._get_layer_name(sm)
|
|
1045
|
+
if layer:
|
|
1046
|
+
state_type = f"STATE_{layer}_t"
|
|
1047
|
+
event_type = f"EVENT_{layer}_t"
|
|
1048
|
+
process_name = f"StateMachine_Process_{layer}"
|
|
1049
|
+
get_evt_name = f"StateMachine_GetNextEvent_{layer}"
|
|
1050
|
+
event_none = f"EVENT_{layer}_NONE"
|
|
1051
|
+
else:
|
|
1052
|
+
state_type = "STATE_t"
|
|
1053
|
+
event_type = "EVENT_t"
|
|
1054
|
+
process_name = "StateMachine_Process"
|
|
1055
|
+
get_evt_name = "StateMachine_GetNextEvent"
|
|
1056
|
+
event_none = "EVENT_NONE"
|
|
1057
|
+
|
|
1058
|
+
results.append('\n'.join([
|
|
1059
|
+
"/**",
|
|
1060
|
+
" * @brief State transition processing",
|
|
1061
|
+
" * @param current_state Current state",
|
|
1062
|
+
" * @param event Event that occurred",
|
|
1063
|
+
" * @param ctx System context pointer",
|
|
1064
|
+
" * @return State after transition",
|
|
1065
|
+
" */",
|
|
1066
|
+
f"{state_type} {process_name}(",
|
|
1067
|
+
f" {state_type} current_state,",
|
|
1068
|
+
f" {event_type} event,",
|
|
1069
|
+
" SystemContext_t *ctx",
|
|
1070
|
+
");",
|
|
1071
|
+
"",
|
|
1072
|
+
"/**",
|
|
1073
|
+
" * @brief Get next event for this layer",
|
|
1074
|
+
" * @param ctx System context pointer",
|
|
1075
|
+
f" * @return Next event ({event_none} if none pending)",
|
|
1076
|
+
" */",
|
|
1077
|
+
f"{event_type} {get_evt_name}(SystemContext_t *ctx);",
|
|
1078
|
+
]))
|
|
1079
|
+
return ['\n'.join(results)] if results else ['']
|
|
1080
|
+
|
|
1081
|
+
def _step_cell_prototypes(self, step, ctx):
|
|
1082
|
+
layers = ctx['layers']
|
|
1083
|
+
results = []
|
|
1084
|
+
for layer_name, sm in layers:
|
|
1085
|
+
self._setup_layer_generators(sm)
|
|
1086
|
+
proto = (self.transition_gen
|
|
1087
|
+
.generate_transition_cell_prototypes(sm))
|
|
1088
|
+
if proto:
|
|
1089
|
+
results.append(proto)
|
|
1090
|
+
return ['\n'.join(results)] if results else ['']
|
|
1091
|
+
|
|
1092
|
+
def _step_transition_table(self, step, ctx):
|
|
1093
|
+
layers = ctx['layers']
|
|
1094
|
+
results = []
|
|
1095
|
+
for layer_name, sm in layers:
|
|
1096
|
+
self._setup_layer_generators(sm)
|
|
1097
|
+
tbl = self.transition_gen.generate_transition_table(
|
|
1098
|
+
sm, table_type=ctx['config'].table_type,
|
|
1099
|
+
)
|
|
1100
|
+
if tbl:
|
|
1101
|
+
results.append(tbl)
|
|
1102
|
+
return ['\n'.join(results)] if results else ['']
|
|
1103
|
+
|
|
1104
|
+
def _step_cell_functions(self, step, ctx):
|
|
1105
|
+
layers = ctx['layers']
|
|
1106
|
+
results = []
|
|
1107
|
+
for layer_name, sm in layers:
|
|
1108
|
+
self._setup_layer_generators(sm)
|
|
1109
|
+
funcs = (self.transition_gen
|
|
1110
|
+
.generate_transition_cell_functions(sm))
|
|
1111
|
+
if funcs:
|
|
1112
|
+
results.append(funcs)
|
|
1113
|
+
return ['\n'.join(results)] if results else ['']
|
|
1114
|
+
|
|
1115
|
+
def _step_process_func(self, step, ctx):
|
|
1116
|
+
layers = ctx['layers']
|
|
1117
|
+
results = []
|
|
1118
|
+
for layer_name, sm in layers:
|
|
1119
|
+
self._setup_layer_generators(sm)
|
|
1120
|
+
func = self.transition_gen.generate_process_function(
|
|
1121
|
+
sm,
|
|
1122
|
+
generation_style=ctx['config'].generation_style,
|
|
1123
|
+
)
|
|
1124
|
+
if func:
|
|
1125
|
+
results.append(func)
|
|
1126
|
+
return ['\n'.join(results)] if results else ['']
|
|
1127
|
+
|
|
1128
|
+
def _step_get_next_event(self, step, ctx):
|
|
1129
|
+
layers = ctx['layers']
|
|
1130
|
+
results = []
|
|
1131
|
+
for layer_name, sm in layers:
|
|
1132
|
+
self._setup_layer_generators(sm)
|
|
1133
|
+
func = self.transition_gen.generate_get_next_event_function(sm)
|
|
1134
|
+
if func:
|
|
1135
|
+
results.append(func)
|
|
1136
|
+
return ['\n'.join(results)] if results else ['']
|
|
1137
|
+
|
|
1138
|
+
def _step_role_decls(self, step, ctx):
|
|
1139
|
+
layers = ctx['layers']
|
|
1140
|
+
results = []
|
|
1141
|
+
for layer_name, sm in layers:
|
|
1142
|
+
self._setup_layer_generators(sm)
|
|
1143
|
+
decls = (self.role_func_gen
|
|
1144
|
+
.generate_all_declarations(
|
|
1145
|
+
self._get_role_functions_list(sm),
|
|
1146
|
+
state_machine=sm))
|
|
1147
|
+
if decls:
|
|
1148
|
+
results.append(decls)
|
|
1149
|
+
return ['\n'.join(results)] if results else ['']
|
|
1150
|
+
|
|
1151
|
+
def _step_state_actions_decls(self, step, ctx):
|
|
1152
|
+
"""[v2.7.0] Emit declarations for statable_state_actions_<Layer>.h."""
|
|
1153
|
+
layers = ctx['layers']
|
|
1154
|
+
results = []
|
|
1155
|
+
for layer_name, sm in layers:
|
|
1156
|
+
layer = self._get_layer_name(sm) or layer_name
|
|
1157
|
+
if not layer:
|
|
1158
|
+
continue
|
|
1159
|
+
self.state_actions_gen.set_layer(layer)
|
|
1160
|
+
decls = (
|
|
1161
|
+
f"void {layer}_Entry(STATE_{layer}_t state, SystemContext_t *ctx);\n"
|
|
1162
|
+
f"void {layer}_Exit (STATE_{layer}_t state, SystemContext_t *ctx);\n"
|
|
1163
|
+
f"void {layer}_Do (STATE_{layer}_t state, SystemContext_t *ctx);"
|
|
1164
|
+
)
|
|
1165
|
+
results.append(decls)
|
|
1166
|
+
return ['\n'.join(results)] if results else ['']
|
|
1167
|
+
|
|
1168
|
+
def _step_state_actions_impls(self, step, ctx):
|
|
1169
|
+
"""[v2.7.0] Emit implementations for statable_state_actions_<Layer>.c."""
|
|
1170
|
+
layers = ctx['layers']
|
|
1171
|
+
results = []
|
|
1172
|
+
for layer_name, sm in layers:
|
|
1173
|
+
layer = self._get_layer_name(sm) or layer_name
|
|
1174
|
+
if not layer:
|
|
1175
|
+
continue
|
|
1176
|
+
self.state_actions_gen.set_layer(layer)
|
|
1177
|
+
body = self._generate_state_actions_body(sm, layer)
|
|
1178
|
+
results.append(body)
|
|
1179
|
+
return ['\n'.join(results)] if results else ['']
|
|
1180
|
+
|
|
1181
|
+
def _generate_state_actions_body(self, sm, layer: str) -> str:
|
|
1182
|
+
"""Body of statable_state_actions_<Layer>.c (no header/include)."""
|
|
1183
|
+
gen = self.state_actions_gen
|
|
1184
|
+
parts = []
|
|
1185
|
+
parts.append(f"typedef void (*{layer}_StateFunc_t)(SystemContext_t *ctx);")
|
|
1186
|
+
parts.append("")
|
|
1187
|
+
parts.append(gen._generate_forward_decls(sm))
|
|
1188
|
+
parts.append("")
|
|
1189
|
+
for kind in ("Entry", "Exit", "Do"):
|
|
1190
|
+
parts.append(f"/* ---- {kind} dispatch table ---- */")
|
|
1191
|
+
parts.append(gen._generate_table(kind, sm))
|
|
1192
|
+
parts.append("")
|
|
1193
|
+
for kind in ("Entry", "Exit", "Do"):
|
|
1194
|
+
parts.append(f"/* ---- {kind} dispatcher ---- */")
|
|
1195
|
+
parts.append(gen._generate_dispatcher(kind, sm))
|
|
1196
|
+
parts.append("")
|
|
1197
|
+
for kind in ("Entry", "Exit", "Do"):
|
|
1198
|
+
actions_by_state = gen._collect_actions_by_kind(sm, kind)
|
|
1199
|
+
parts.append(f"/* ---- {kind} functions (user-editable) ---- */")
|
|
1200
|
+
for state in sm.states.values():
|
|
1201
|
+
parts.append(gen._generate_state_func(
|
|
1202
|
+
kind, state, actions_by_state.get(state.name, [])))
|
|
1203
|
+
parts.append("")
|
|
1204
|
+
return "\n".join(parts)
|
|
1205
|
+
|
|
1206
|
+
def _generate_state_actions_header(self, sm, gd):
|
|
1207
|
+
"""[v2.7.0] statable_state_actions_<Layer>.h generation."""
|
|
1208
|
+
return self._run_steps('statable_state_actions.h', sm, gd)
|
|
1209
|
+
|
|
1210
|
+
def _generate_state_actions_source(self, sm, gd):
|
|
1211
|
+
"""[v2.7.0] statable_state_actions_<Layer>.c generation."""
|
|
1212
|
+
return self._run_steps('statable_state_actions.c', sm, gd)
|
|
1213
|
+
|
|
1214
|
+
def _step_role_impls(self, step, ctx):
|
|
1215
|
+
layers = ctx['layers']
|
|
1216
|
+
results = []
|
|
1217
|
+
for layer_name, sm in layers:
|
|
1218
|
+
self._setup_layer_generators(sm)
|
|
1219
|
+
impls = (self.role_func_gen
|
|
1220
|
+
.generate_all_implementations(
|
|
1221
|
+
self._get_role_functions_list(sm),
|
|
1222
|
+
state_machine=sm,
|
|
1223
|
+
global_defs=ctx['global_defs'],
|
|
1224
|
+
))
|
|
1225
|
+
if impls:
|
|
1226
|
+
results.append(impls)
|
|
1227
|
+
return ['\n'.join(results)] if results else ['']
|
|
1228
|
+
|
|
1229
|
+
def _step_init_func(self, step, ctx):
|
|
1230
|
+
return [self.variable_gen.generate_init_function(
|
|
1231
|
+
ctx['global_defs']
|
|
1232
|
+
)]
|
|
1233
|
+
|
|
1234
|
+
def _step_init_queues(self, step, ctx):
|
|
1235
|
+
"""[C-52] Emit SystemContext_InitQueues()."""
|
|
1236
|
+
layers = ctx.get('layers', [])
|
|
1237
|
+
if not layers:
|
|
1238
|
+
return ['']
|
|
1239
|
+
parts = [
|
|
1240
|
+
'/**',
|
|
1241
|
+
' * @brief Initialize per-layer event queues (C-52)',
|
|
1242
|
+
' * @param ctx System context pointer',
|
|
1243
|
+
' */',
|
|
1244
|
+
'void SystemContext_InitQueues(SystemContext_t *ctx)',
|
|
1245
|
+
'{',
|
|
1246
|
+
' if (ctx == NULL) {',
|
|
1247
|
+
' return;',
|
|
1248
|
+
' }',
|
|
1249
|
+
]
|
|
1250
|
+
seen = set()
|
|
1251
|
+
for layer_name, sm in layers:
|
|
1252
|
+
layer = self._get_layer_name(sm) or layer_name
|
|
1253
|
+
if not layer or layer in seen:
|
|
1254
|
+
continue
|
|
1255
|
+
seen.add(layer)
|
|
1256
|
+
# [F-3 Step 2] reset per-layer pending slot
|
|
1257
|
+
parts.append(f' ctx->pending_event_{layer} = 0U;')
|
|
1258
|
+
parts.append(f' ctx->pending_event_valid_{layer} = false;')
|
|
1259
|
+
parts.append(f' INIT_EVENT_QUEUE_{layer}(ctx);')
|
|
1260
|
+
parts.append('}')
|
|
1261
|
+
return ['\n'.join(parts)]
|
|
1262
|
+
|
|
1263
|
+
def _step_event_queues(self, step, ctx):
|
|
1264
|
+
gd = ctx['global_defs']
|
|
1265
|
+
queues = getattr(gd, 'event_queues', [])
|
|
1266
|
+
if not queues:
|
|
1267
|
+
return ["/* No event queue definitions */"]
|
|
1268
|
+
result: List[str] = [
|
|
1269
|
+
self._generate_section_header('type_defs'),
|
|
1270
|
+
"",
|
|
1271
|
+
]
|
|
1272
|
+
for queue in queues:
|
|
1273
|
+
result.append(
|
|
1274
|
+
self.event_queue_gen.generate_all_code(queue)
|
|
1275
|
+
)
|
|
1276
|
+
result.append("")
|
|
1277
|
+
return result
|
|
1278
|
+
|
|
1279
|
+
def _step_interrupts(self, step, ctx):
|
|
1280
|
+
gd = ctx['global_defs']
|
|
1281
|
+
interrupts = getattr(gd, 'interrupts', [])
|
|
1282
|
+
if not interrupts:
|
|
1283
|
+
return ["/* No interrupt handler definitions */"]
|
|
1284
|
+
result: List[str] = [
|
|
1285
|
+
self._generate_section_header('transition_func'),
|
|
1286
|
+
"",
|
|
1287
|
+
]
|
|
1288
|
+
for handler in interrupts:
|
|
1289
|
+
try:
|
|
1290
|
+
self.interrupt_gen.update_handler_symbols(handler)
|
|
1291
|
+
except Exception as e:
|
|
1292
|
+
self._log_debug(
|
|
1293
|
+
f"update_handler_symbols failed for "
|
|
1294
|
+
f"'{getattr(handler, 'name', '?')}': {e}",
|
|
1295
|
+
'warning',
|
|
1296
|
+
)
|
|
1297
|
+
result.append(
|
|
1298
|
+
self.interrupt_gen.generate_isr(handler)
|
|
1299
|
+
)
|
|
1300
|
+
result.append("")
|
|
1301
|
+
return result
|
|
1302
|
+
|
|
1303
|
+
def _step_timer_struct(self, step, ctx):
|
|
1304
|
+
return [self.timer_gen.generate_struct(
|
|
1305
|
+
ctx['global_defs']
|
|
1306
|
+
)]
|
|
1307
|
+
|
|
1308
|
+
def _step_timer_init(self, step, ctx):
|
|
1309
|
+
return [self.timer_gen.generate_init_function(
|
|
1310
|
+
ctx['global_defs']
|
|
1311
|
+
)]
|
|
1312
|
+
|
|
1313
|
+
def _step_timer_update(self, step, ctx):
|
|
1314
|
+
return [self.timer_gen.generate_update_function(
|
|
1315
|
+
ctx['global_defs']
|
|
1316
|
+
)]
|
|
1317
|
+
|
|
1318
|
+
def _step_osal_header(self, step, ctx):
|
|
1319
|
+
return [self.osal_gen.generate_header(
|
|
1320
|
+
self.config.os_type
|
|
1321
|
+
)]
|
|
1322
|
+
|
|
1323
|
+
def _step_osal_source(self, step, ctx):
|
|
1324
|
+
return [self.osal_gen.generate_source(
|
|
1325
|
+
self.config.os_type
|
|
1326
|
+
)]
|
|
1327
|
+
|
|
1328
|
+
def _step_super_include_header(self, step, ctx):
|
|
1329
|
+
T = self.templates.SUPER_INCLUDE_TEMPLATES
|
|
1330
|
+
fname = self.config.super_include_file
|
|
1331
|
+
return [T['file_comment'].format(filename=fname)]
|
|
1332
|
+
|
|
1333
|
+
def _step_super_include_guard_start(self, step, ctx):
|
|
1334
|
+
T = self.templates.SUPER_INCLUDE_TEMPLATES
|
|
1335
|
+
return [T['guard_start'].rstrip('\n')]
|
|
1336
|
+
|
|
1337
|
+
def _step_super_include_guard_end(self, step, ctx):
|
|
1338
|
+
T = self.templates.SUPER_INCLUDE_TEMPLATES
|
|
1339
|
+
return [T['guard_end']]
|
|
1340
|
+
|
|
1341
|
+
def _step_super_include_common(self, step, ctx):
|
|
1342
|
+
T = self.templates.SUPER_INCLUDE_TEMPLATES
|
|
1343
|
+
layers = ctx['layers']
|
|
1344
|
+
structure = self.config.folder_structure
|
|
1345
|
+
parts = [T['common_section']]
|
|
1346
|
+
if structure == 'by_layer':
|
|
1347
|
+
parts.append('#include "statable_types_common.h"')
|
|
1348
|
+
for layer_name, sm in layers:
|
|
1349
|
+
layer = self._get_layer_name(sm)
|
|
1350
|
+
if layer:
|
|
1351
|
+
parts.append(
|
|
1352
|
+
f'#include "{layer}/'
|
|
1353
|
+
f'statable_types_{layer}.h"'
|
|
1354
|
+
)
|
|
1355
|
+
else:
|
|
1356
|
+
parts.append('#include "statable_types_common.h"')
|
|
1357
|
+
parts.append('#include "statable_types.h"')
|
|
1358
|
+
return parts
|
|
1359
|
+
|
|
1360
|
+
def _step_super_include_layer(self, step, ctx):
|
|
1361
|
+
T = self.templates.SUPER_INCLUDE_TEMPLATES
|
|
1362
|
+
layers = ctx['layers']
|
|
1363
|
+
structure = self.config.folder_structure
|
|
1364
|
+
parts = [T['layer_section']]
|
|
1365
|
+
if structure == 'by_layer':
|
|
1366
|
+
for layer_name, sm in layers:
|
|
1367
|
+
layer = self._get_layer_name(sm)
|
|
1368
|
+
if layer:
|
|
1369
|
+
parts.append(
|
|
1370
|
+
f'#include "{layer}/'
|
|
1371
|
+
f'statable_transitions_{layer}.h"'
|
|
1372
|
+
)
|
|
1373
|
+
parts.append(
|
|
1374
|
+
f'#include "{layer}/'
|
|
1375
|
+
f'statable_role_functions_{layer}.h"'
|
|
1376
|
+
)
|
|
1377
|
+
parts.append(
|
|
1378
|
+
f'#include "{layer}/'
|
|
1379
|
+
f'statable_state_actions_{layer}.h"'
|
|
1380
|
+
)
|
|
1381
|
+
else:
|
|
1382
|
+
parts.append('#include "statable_transitions.h"')
|
|
1383
|
+
parts.append('#include "statable_role_functions.h"')
|
|
1384
|
+
parts.append('#include "statable_state_actions.h"')
|
|
1385
|
+
return parts
|
|
1386
|
+
|
|
1387
|
+
def _step_super_include_project(self, step, ctx):
|
|
1388
|
+
T = self.templates.SUPER_INCLUDE_TEMPLATES
|
|
1389
|
+
return [
|
|
1390
|
+
T['project_section'],
|
|
1391
|
+
'#include "osal.h"',
|
|
1392
|
+
]
|
|
1393
|
+
|
|
1394
|
+
def _step_super_include_extern_vars(self, step, ctx):
|
|
1395
|
+
T = self.templates.SUPER_INCLUDE_TEMPLATES
|
|
1396
|
+
layers = ctx['layers']
|
|
1397
|
+
parts = [T['extern_var_section'], T['extern_context']]
|
|
1398
|
+
for layer_name, sm in layers:
|
|
1399
|
+
layer = self._get_layer_name(sm)
|
|
1400
|
+
if layer:
|
|
1401
|
+
parts.append(T['extern_state'].format(layer=layer))
|
|
1402
|
+
else:
|
|
1403
|
+
parts.append(T['extern_state_nolayer'])
|
|
1404
|
+
return parts
|
|
1405
|
+
|
|
1406
|
+
def _step_super_include_extern_funcs(self, step, ctx):
|
|
1407
|
+
T = self.templates.SUPER_INCLUDE_TEMPLATES
|
|
1408
|
+
project = self.config.project_name
|
|
1409
|
+
parts = [
|
|
1410
|
+
T['extern_func_section'],
|
|
1411
|
+
T['extern_init'].format(project_name=project),
|
|
1412
|
+
T['extern_run'].format(project_name=project),
|
|
1413
|
+
]
|
|
1414
|
+
gd = ctx['global_defs']
|
|
1415
|
+
interrupts = getattr(gd, 'interrupts', []) or []
|
|
1416
|
+
if interrupts:
|
|
1417
|
+
parts.append("")
|
|
1418
|
+
parts.append("/* ---- Interrupt handlers (extern) ---- */")
|
|
1419
|
+
for handler in interrupts:
|
|
1420
|
+
try:
|
|
1421
|
+
isr_name = self.interrupt_gen._get_isr_function_name(handler)
|
|
1422
|
+
except Exception:
|
|
1423
|
+
name = getattr(handler, 'name', '') or ''
|
|
1424
|
+
if not name:
|
|
1425
|
+
continue
|
|
1426
|
+
isr_name = f"ISR_{self.naming.to_pascal_case(name)}"
|
|
1427
|
+
parts.append(f"void {isr_name}(void);")
|
|
1428
|
+
return parts
|
|
1429
|
+
|
|
1430
|
+
def _step_super_include_external(self, step, ctx):
|
|
1431
|
+
T = self.templates.SUPER_INCLUDE_TEMPLATES
|
|
1432
|
+
result = [T['external_section']]
|
|
1433
|
+
for inc in self.config.external_includes:
|
|
1434
|
+
inc = inc.strip()
|
|
1435
|
+
if not inc:
|
|
1436
|
+
continue
|
|
1437
|
+
if inc.startswith('#include'):
|
|
1438
|
+
result.append(inc)
|
|
1439
|
+
else:
|
|
1440
|
+
result.append(f'#include "{inc}"')
|
|
1441
|
+
return result
|
|
1442
|
+
|
|
1443
|
+
def _step_super_include_user(self, step, ctx):
|
|
1444
|
+
T = self.templates.SUPER_INCLUDE_TEMPLATES
|
|
1445
|
+
return [
|
|
1446
|
+
T['user_section'],
|
|
1447
|
+
T['user_marker_start'],
|
|
1448
|
+
T['user_marker_end'],
|
|
1449
|
+
]
|
|
1450
|
+
|
|
1451
|
+
def _step_super_loop_header(self, step, ctx):
|
|
1452
|
+
T = self.templates.SUPER_LOOP_TEMPLATES
|
|
1453
|
+
project = self.config.project_name
|
|
1454
|
+
return [T['file_comment'].format(project_name=project)]
|
|
1455
|
+
|
|
1456
|
+
def _step_super_loop_include(self, step, ctx):
|
|
1457
|
+
return [self.templates.SUPER_LOOP_TEMPLATES['include']]
|
|
1458
|
+
|
|
1459
|
+
def _step_super_loop_context_var(self, step, ctx):
|
|
1460
|
+
return [self.templates.SUPER_LOOP_TEMPLATES['context_var']]
|
|
1461
|
+
|
|
1462
|
+
def _step_super_loop_state_var(self, step, ctx):
|
|
1463
|
+
layers = ctx['layers']
|
|
1464
|
+
T = self.templates.SUPER_LOOP_TEMPLATES
|
|
1465
|
+
parts = []
|
|
1466
|
+
for layer_name, sm in layers:
|
|
1467
|
+
layer = self._get_layer_name(sm)
|
|
1468
|
+
if layer:
|
|
1469
|
+
parts.append(T['state_var'].format(layer=layer))
|
|
1470
|
+
else:
|
|
1471
|
+
parts.append(T['state_var_nolayer'])
|
|
1472
|
+
return parts
|
|
1473
|
+
|
|
1474
|
+
def _step_super_loop_init_func(self, step, ctx):
|
|
1475
|
+
layers = ctx['layers']
|
|
1476
|
+
project = self.config.project_name
|
|
1477
|
+
T = self.templates.SUPER_LOOP_TEMPLATES
|
|
1478
|
+
parts = [
|
|
1479
|
+
T['init_func_comment'],
|
|
1480
|
+
T['init_func_signature'].format(project_name=project),
|
|
1481
|
+
T['init_func_open'],
|
|
1482
|
+
T['init_context'],
|
|
1483
|
+
]
|
|
1484
|
+
for layer_name, sm in layers:
|
|
1485
|
+
layer = self._get_layer_name(sm)
|
|
1486
|
+
initial = self._get_initial_state(sm)
|
|
1487
|
+
if layer:
|
|
1488
|
+
parts.append(T['init_state'].format(
|
|
1489
|
+
layer=layer, initial=initial,
|
|
1490
|
+
))
|
|
1491
|
+
else:
|
|
1492
|
+
parts.append(T['init_state_nolayer'].format(
|
|
1493
|
+
initial=initial,
|
|
1494
|
+
))
|
|
1495
|
+
parts.append(T['init_func_close'])
|
|
1496
|
+
return parts
|
|
1497
|
+
|
|
1498
|
+
def _step_super_loop_run_func(self, step, ctx):
|
|
1499
|
+
layers = ctx['layers']
|
|
1500
|
+
project = self.config.project_name
|
|
1501
|
+
T = self.templates.SUPER_LOOP_TEMPLATES
|
|
1502
|
+
parts = [
|
|
1503
|
+
T['run_func_comment'],
|
|
1504
|
+
T['run_func_signature'].format(project_name=project),
|
|
1505
|
+
T['run_func_open'],
|
|
1506
|
+
T['run_while'],
|
|
1507
|
+
]
|
|
1508
|
+
# [v2.7.0] State actions (Entry / Exit / Do) - Do at loop top
|
|
1509
|
+
parts.append(" /* [v2.7.0] State actions (Do) */")
|
|
1510
|
+
for layer_name, sm in layers:
|
|
1511
|
+
layer = self._get_layer_name(sm)
|
|
1512
|
+
if layer:
|
|
1513
|
+
parts.append(
|
|
1514
|
+
f" {layer}_Do(g_{layer}_state, &g_ctx);"
|
|
1515
|
+
)
|
|
1516
|
+
parts.append("")
|
|
1517
|
+
|
|
1518
|
+
for layer_name, sm in layers:
|
|
1519
|
+
layer = self._get_layer_name(sm)
|
|
1520
|
+
priority = getattr(sm, 'layer_priority', 5)
|
|
1521
|
+
if layer:
|
|
1522
|
+
block = T['run_block'].format(
|
|
1523
|
+
layer=layer,
|
|
1524
|
+
priority=priority,
|
|
1525
|
+
)
|
|
1526
|
+
else:
|
|
1527
|
+
block = T['run_block_nolayer']
|
|
1528
|
+
indented = ' ' + block.replace(
|
|
1529
|
+
'\n', '\n ')
|
|
1530
|
+
parts.append(indented)
|
|
1531
|
+
parts.append(T['run_while_close'])
|
|
1532
|
+
parts.append(T['run_func_close'])
|
|
1533
|
+
return parts
|
|
1534
|
+
|
|
1535
|
+
def _generate_types_common_header(self, sm, gd):
|
|
1536
|
+
return self._run_steps('statable_types_common.h', sm, gd)
|
|
1537
|
+
|
|
1538
|
+
def _generate_types_header(self, sm, gd):
|
|
1539
|
+
return self._run_steps('statable_types.h', sm, gd)
|
|
1540
|
+
|
|
1541
|
+
def _generate_transitions_header(self, sm, gd):
|
|
1542
|
+
return self._run_steps('statable_transitions.h', sm, gd)
|
|
1543
|
+
|
|
1544
|
+
def _generate_transitions_source(self, sm, gd):
|
|
1545
|
+
return self._run_steps('statable_transitions.c', sm, gd)
|
|
1546
|
+
|
|
1547
|
+
def _generate_role_functions_header(self, sm, gd):
|
|
1548
|
+
return self._run_steps('statable_role_functions.h', sm, gd)
|
|
1549
|
+
|
|
1550
|
+
def _generate_role_functions_source(self, sm, gd):
|
|
1551
|
+
return self._run_steps('statable_role_functions.c', sm, gd)
|
|
1552
|
+
|
|
1553
|
+
def _generate_init_source(self, sm, gd):
|
|
1554
|
+
return self._run_steps('statable_init.c', sm, gd)
|
|
1555
|
+
|
|
1556
|
+
def _generate_event_queue_source(self, sm, gd):
|
|
1557
|
+
return self._run_steps('statable_event_queue.c', sm, gd)
|
|
1558
|
+
|
|
1559
|
+
def _generate_interrupt_source(self, sm, gd):
|
|
1560
|
+
return self._run_steps('statable_interrupt.c', sm, gd)
|
|
1561
|
+
|
|
1562
|
+
def _generate_timer_source(self, sm, gd):
|
|
1563
|
+
return self._run_steps('statable_timer.c', sm, gd)
|
|
1564
|
+
|
|
1565
|
+
def _generate_osal_header(self, sm, gd):
|
|
1566
|
+
return self._run_steps('osal.h', sm, gd)
|
|
1567
|
+
|
|
1568
|
+
def _generate_osal_source(self, sm, gd):
|
|
1569
|
+
return self._run_steps('osal.c', sm, gd)
|
|
1570
|
+
|
|
1571
|
+
def _generate_super_include(self, sm, gd):
|
|
1572
|
+
return self._run_steps('statable_all.h', sm, gd)
|
|
1573
|
+
|
|
1574
|
+
def _generate_super_loop(self, sm, gd):
|
|
1575
|
+
return self._run_steps(self.super_loop_filename, sm, gd)
|
|
1576
|
+
|
|
1577
|
+
def generate_all(self, state_machine, global_defs,
|
|
1578
|
+
role_function_library=None):
|
|
1579
|
+
self._setup_layer_generators(state_machine)
|
|
1580
|
+
prev = self._current_role_function_library
|
|
1581
|
+
self._current_role_function_library = role_function_library
|
|
1582
|
+
try:
|
|
1583
|
+
generated_files = {}
|
|
1584
|
+
for filename in self.file_generators.keys():
|
|
1585
|
+
if (filename == 'statable_all.h'
|
|
1586
|
+
and not self.config.generate_super_include):
|
|
1587
|
+
continue
|
|
1588
|
+
method_name = self.FILE_DISPATCH.get(filename)
|
|
1589
|
+
if method_name is None:
|
|
1590
|
+
continue
|
|
1591
|
+
method = getattr(self, method_name, None)
|
|
1592
|
+
if method is None:
|
|
1593
|
+
continue
|
|
1594
|
+
generated_files[filename] = method(
|
|
1595
|
+
state_machine, global_defs
|
|
1596
|
+
)
|
|
1597
|
+
return generated_files
|
|
1598
|
+
finally:
|
|
1599
|
+
self._current_role_function_library = prev
|
|
1600
|
+
|
|
1601
|
+
def generate_file(self, filename, state_machine, global_defs,
|
|
1602
|
+
role_function_library=None):
|
|
1603
|
+
self._setup_layer_generators(state_machine)
|
|
1604
|
+
prev = self._current_role_function_library
|
|
1605
|
+
self._current_role_function_library = role_function_library
|
|
1606
|
+
try:
|
|
1607
|
+
if filename not in self.file_generators:
|
|
1608
|
+
raise ValueError(f"Unknown file: {filename}")
|
|
1609
|
+
return self._run_steps(
|
|
1610
|
+
filename, state_machine, global_defs
|
|
1611
|
+
)
|
|
1612
|
+
finally:
|
|
1613
|
+
self._current_role_function_library = prev
|
|
1614
|
+
|
|
1615
|
+
def generate_all_layers(self, layers, global_defs,
|
|
1616
|
+
role_function_library=None):
|
|
1617
|
+
norm_layers = self._normalize_layers(layers)
|
|
1618
|
+
if not norm_layers:
|
|
1619
|
+
return {}
|
|
1620
|
+
structure = self.config.folder_structure
|
|
1621
|
+
if structure == 'by_layer':
|
|
1622
|
+
return self._generate_all_by_layer(
|
|
1623
|
+
norm_layers, global_defs, role_function_library
|
|
1624
|
+
)
|
|
1625
|
+
primary_sm = norm_layers[0][1]
|
|
1626
|
+
self._setup_layer_generators(primary_sm)
|
|
1627
|
+
prev = self._current_role_function_library
|
|
1628
|
+
self._current_role_function_library = role_function_library
|
|
1629
|
+
try:
|
|
1630
|
+
generated_files = {}
|
|
1631
|
+
for filename in self.file_generators.keys():
|
|
1632
|
+
if (filename == 'statable_all.h'
|
|
1633
|
+
and not self.config.generate_super_include):
|
|
1634
|
+
continue
|
|
1635
|
+
generated_files[filename] = self._run_steps_multi(
|
|
1636
|
+
filename, norm_layers, global_defs
|
|
1637
|
+
)
|
|
1638
|
+
return generated_files
|
|
1639
|
+
finally:
|
|
1640
|
+
self._current_role_function_library = prev
|
|
1641
|
+
|
|
1642
|
+
def _generate_all_by_layer(self, layers, global_defs,
|
|
1643
|
+
role_function_library):
|
|
1644
|
+
self._log_debug(
|
|
1645
|
+
f"_generate_all_by_layer: {len(layers)} layers"
|
|
1646
|
+
)
|
|
1647
|
+
generated_files = {}
|
|
1648
|
+
prev = self._current_role_function_library
|
|
1649
|
+
self._current_role_function_library = role_function_library
|
|
1650
|
+
prev_layers = self._all_layers_for_includes
|
|
1651
|
+
self._all_layers_for_includes = list(layers)
|
|
1652
|
+
try:
|
|
1653
|
+
for layer_name, sm in layers:
|
|
1654
|
+
self._setup_layer_generators(sm)
|
|
1655
|
+
if not layer_name:
|
|
1656
|
+
for fname in self.LAYER_SPECIFIC_FILES:
|
|
1657
|
+
method_name = self.FILE_DISPATCH.get(fname)
|
|
1658
|
+
if method_name is None:
|
|
1659
|
+
continue
|
|
1660
|
+
method = getattr(self, method_name, None)
|
|
1661
|
+
if method is None:
|
|
1662
|
+
continue
|
|
1663
|
+
generated_files[fname] = method(
|
|
1664
|
+
sm, global_defs
|
|
1665
|
+
)
|
|
1666
|
+
continue
|
|
1667
|
+
for fname in self.LAYER_SPECIFIC_FILES:
|
|
1668
|
+
method_name = self.FILE_DISPATCH.get(fname)
|
|
1669
|
+
if method_name is None:
|
|
1670
|
+
continue
|
|
1671
|
+
method = getattr(self, method_name, None)
|
|
1672
|
+
if method is None:
|
|
1673
|
+
continue
|
|
1674
|
+
content = method(sm, global_defs)
|
|
1675
|
+
fname_with_layer = self._layer_filename(
|
|
1676
|
+
fname, layer_name
|
|
1677
|
+
)
|
|
1678
|
+
generated_files[
|
|
1679
|
+
f"{layer_name}/{fname_with_layer}"
|
|
1680
|
+
] = content
|
|
1681
|
+
common_names = list(self.COMMON_FILES) + [
|
|
1682
|
+
self.super_loop_filename
|
|
1683
|
+
]
|
|
1684
|
+
for fname in common_names:
|
|
1685
|
+
if (fname == 'statable_all.h'
|
|
1686
|
+
and not self.config.generate_super_include):
|
|
1687
|
+
continue
|
|
1688
|
+
content = self._run_steps_multi(
|
|
1689
|
+
fname, layers, global_defs
|
|
1690
|
+
)
|
|
1691
|
+
generated_files[fname] = content
|
|
1692
|
+
return generated_files
|
|
1693
|
+
finally:
|
|
1694
|
+
self._current_role_function_library = prev
|
|
1695
|
+
self._all_layers_for_includes = prev_layers
|
|
1696
|
+
|
|
1697
|
+
def save_generated_code(self, generated_files, output_dir,
|
|
1698
|
+
layer_name: str = ''):
|
|
1699
|
+
saved_files = []
|
|
1700
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
1701
|
+
for filename, content in generated_files.items():
|
|
1702
|
+
rel_path = self._resolve_output_path(
|
|
1703
|
+
filename, layer_name
|
|
1704
|
+
)
|
|
1705
|
+
filepath = os.path.join(output_dir, rel_path)
|
|
1706
|
+
parent = os.path.dirname(filepath)
|
|
1707
|
+
if parent:
|
|
1708
|
+
os.makedirs(parent, exist_ok=True)
|
|
1709
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
1710
|
+
f.write(content)
|
|
1711
|
+
saved_files.append(filepath)
|
|
1712
|
+
return saved_files
|
|
1713
|
+
|
|
1714
|
+
def save_generated_code_with_merge(self, generated_files,
|
|
1715
|
+
output_dir,
|
|
1716
|
+
layer_name: str = ''):
|
|
1717
|
+
merged_files = self.merger.merge_all_files(
|
|
1718
|
+
generated_files, output_dir,
|
|
1719
|
+
path_resolver=self._resolve_output_path,
|
|
1720
|
+
layer_name=layer_name,
|
|
1721
|
+
)
|
|
1722
|
+
return self.save_generated_code(
|
|
1723
|
+
merged_files, output_dir, layer_name
|
|
1724
|
+
)
|
|
1725
|
+
|
|
1726
|
+
def get_merge_summary(self, generated_files, output_dir,
|
|
1727
|
+
layer_name: str = ''):
|
|
1728
|
+
summary = {}
|
|
1729
|
+
for filename, content in generated_files.items():
|
|
1730
|
+
rel_path = self._resolve_output_path(
|
|
1731
|
+
filename, layer_name
|
|
1732
|
+
)
|
|
1733
|
+
existing_path = os.path.join(output_dir, rel_path)
|
|
1734
|
+
if os.path.exists(existing_path):
|
|
1735
|
+
with open(existing_path, 'r',
|
|
1736
|
+
encoding='utf-8') as f:
|
|
1737
|
+
existing_content = f.read()
|
|
1738
|
+
summary[filename] = (
|
|
1739
|
+
self.merger.get_user_code_summary(
|
|
1740
|
+
existing_content
|
|
1741
|
+
)
|
|
1742
|
+
)
|
|
1743
|
+
else:
|
|
1744
|
+
summary[filename] = {
|
|
1745
|
+
'file_user_code': 0,
|
|
1746
|
+
'func_user_codes': 0,
|
|
1747
|
+
'file_tail_user_code': 0,
|
|
1748
|
+
}
|
|
1749
|
+
return summary
|
|
1750
|
+
|
|
1751
|
+
def get_generated_file_list(self):
|
|
1752
|
+
return list(self.file_generators.keys())
|