struct-frame 0.0.29__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.
@@ -0,0 +1,11 @@
1
+ from .base import version, NamingStyleC, CamelToSnakeCase, pascalCase
2
+
3
+ from .c_gen import FileCGen
4
+ from .ts_gen import FileTsGen
5
+ from .py_gen import FilePyGen
6
+ from .gql_gen import FileGqlGen
7
+
8
+ from .generate import main
9
+
10
+ __all__ = ["main", "FileCGen", "FileTsGen", "FilePyGen", "FileGqlGen", "version",
11
+ "NamingStyleC", "CamelToSnakeCase", "pascalCase"]
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env python3
2
+ # kate: replace-tabs on; indent-width 4;
3
+
4
+
5
+ from struct_frame import main
6
+
7
+ if __name__ == '__main__':
8
+ main()
struct_frame/base.py ADDED
@@ -0,0 +1,85 @@
1
+
2
+ import re
3
+
4
+ version = "0.0.1"
5
+
6
+
7
+ class NamingStyle:
8
+ def enum_name(self, name):
9
+ return "_%s" % (name)
10
+
11
+ def struct_name(self, name):
12
+ return "_%s" % (name)
13
+
14
+ def union_name(self, name):
15
+ return "_%s" % (name)
16
+
17
+ def type_name(self, name):
18
+ return "%s" % (name)
19
+
20
+ def define_name(self, name):
21
+ return "%s" % (name)
22
+
23
+ def var_name(self, name):
24
+ return "%s" % (name)
25
+
26
+ def enum_entry(self, name):
27
+ return "%s" % (name)
28
+
29
+ def func_name(self, name):
30
+ return "%s" % (name)
31
+
32
+ def bytes_type(self, struct_name, name):
33
+ return "%s_%s_t" % (struct_name, name)
34
+
35
+
36
+ class NamingStyleC(NamingStyle):
37
+ def enum_name(self, name):
38
+ return self.underscore(name)
39
+
40
+ def struct_name(self, name):
41
+ return self.underscore(name)
42
+
43
+ def union_name(self, name):
44
+ return self.underscore(name)
45
+
46
+ def type_name(self, name):
47
+ return "%s_t" % self.underscore(name)
48
+
49
+ def define_name(self, name):
50
+ return self.underscore(name).upper()
51
+
52
+ def var_name(self, name):
53
+ return self.underscore(name)
54
+
55
+ def enum_entry(self, name):
56
+ return name.upper()
57
+
58
+ def func_name(self, name):
59
+ return self.underscore(name)
60
+
61
+ def bytes_type(self, struct_name, name):
62
+ return "%s_%s_t" % (self.underscore(struct_name), self.underscore(name))
63
+
64
+ def underscore(self, word):
65
+ word = str(word)
66
+ word = re.sub(r"([A-Z]+)([A-Z][a-z])", r'\1_\2', word)
67
+ word = re.sub(r"([a-z\d])([A-Z])", r'\1_\2', word)
68
+ word = word.replace("-", "_")
69
+ return word.lower()
70
+
71
+
72
+ def camelCase(st):
73
+ output = ''.join(x for x in st.title() if x.isalnum())
74
+ return output[0].lower() + output[1:]
75
+
76
+
77
+ def pascalCase(st):
78
+ return ''.join(x for x in st.title() if x.isalnum())
79
+
80
+
81
+ pattern = re.compile(r'(?<!^)(?=[A-Z])')
82
+
83
+
84
+ def CamelToSnakeCase(data):
85
+ return pattern.sub('_', data).lower()
struct_frame/c_gen.py ADDED
@@ -0,0 +1,252 @@
1
+ #!/usr/bin/env python3
2
+ # kate: replace-tabs on; indent-width 4;
3
+
4
+ from struct_frame import version, NamingStyleC, CamelToSnakeCase, pascalCase
5
+ import time
6
+
7
+ StyleC = NamingStyleC()
8
+
9
+ c_types = {"uint8": "uint8_t",
10
+ "int8": "int8_t",
11
+ "uint16": "uint16_t",
12
+ "int16": "int16_t",
13
+ "uint32": "uint32_t",
14
+ "int32": "int32_t",
15
+ "bool": "bool",
16
+ "float": "float",
17
+ "double": "double",
18
+ "uint64": 'uint64_t',
19
+ "int64": 'int64_t',
20
+ "string": "char", # Add string type support
21
+ }
22
+
23
+
24
+ class EnumCGen():
25
+ @staticmethod
26
+ def generate(field):
27
+ leading_comment = field.comments
28
+
29
+ result = ''
30
+ if leading_comment:
31
+ for c in leading_comment:
32
+ result = '%s\n' % c
33
+
34
+ enumName = '%s%s' % (pascalCase(field.package), field.name)
35
+ result += 'typedef enum %s' % (enumName)
36
+
37
+ result += ' {\n'
38
+
39
+ enum_length = len(field.data)
40
+ enum_values = []
41
+ for index, (d) in enumerate(field.data):
42
+ leading_comment = field.data[d][1]
43
+
44
+ if leading_comment:
45
+ for c in leading_comment:
46
+ enum_values.append(c)
47
+
48
+ comma = ","
49
+ if index == enum_length - 1:
50
+ # last enum member should not end with a comma
51
+ comma = ""
52
+
53
+ enum_value = " %s_%s = %d%s" % (CamelToSnakeCase(
54
+ field.name).upper(), StyleC.enum_entry(d), field.data[d][0], comma)
55
+
56
+ enum_values.append(enum_value)
57
+
58
+ result += '\n'.join(enum_values)
59
+ result += '\n}'
60
+
61
+ result += ' %s;\n' % (enumName)
62
+
63
+ result += 'typedef uint8_t %s_t;' % (enumName)
64
+
65
+ # Add module-prefixed enum constants for compatibility
66
+ result += '\n\n/* Enum constants with module prefix */\n'
67
+ module_prefix = CamelToSnakeCase(field.package).upper()
68
+ for d in field.data:
69
+ # Use the already correct enum constant name
70
+ enum_constant = f"{CamelToSnakeCase(field.name).upper()}_{StyleC.enum_entry(d)}"
71
+ module_constant = f"{module_prefix}_{enum_constant}"
72
+ result += f'#define {module_constant:<35} {enum_constant}\n'
73
+
74
+ return result
75
+
76
+
77
+ class FieldCGen():
78
+ @staticmethod
79
+ def generate(field):
80
+ result = ''
81
+ var_name = field.name
82
+ type_name = field.fieldType
83
+
84
+ # Handle basic type resolution
85
+ if type_name in c_types:
86
+ base_type = c_types[type_name]
87
+ else:
88
+ if field.isEnum:
89
+ base_type = '%s%s_t' % (pascalCase(field.package), type_name)
90
+ else:
91
+ base_type = '%s%s' % (pascalCase(field.package), type_name)
92
+
93
+ # Handle arrays
94
+ if field.is_array:
95
+ if field.fieldType == "string":
96
+ # String arrays need both array size and individual string size
97
+ if field.size_option is not None:
98
+ # Fixed string array: size_option strings, each element_size chars
99
+ declaration = f"char {var_name}[{field.size_option}][{field.element_size}];"
100
+ comment = f" // Fixed string array: {field.size_option} strings, each max {field.element_size} chars"
101
+ elif field.max_size is not None:
102
+ # Variable string array: count byte + max_size strings of element_size chars each
103
+ declaration = f"struct {{ uint8_t count; char data[{field.max_size}][{field.element_size}]; }} {var_name};"
104
+ comment = f" // Variable string array: up to {field.max_size} strings, each max {field.element_size} chars"
105
+ else:
106
+ declaration = f"char {var_name}[1][1];" # Fallback
107
+ comment = " // String array (error in size specification)"
108
+ else:
109
+ # Non-string arrays
110
+ if field.size_option is not None:
111
+ # Fixed array: always exact size
112
+ declaration = f"{base_type} {var_name}[{field.size_option}];"
113
+ comment = f" // Fixed array: always {field.size_option} elements"
114
+ elif field.max_size is not None:
115
+ # Variable array: count byte + max elements
116
+ declaration = f"struct {{ uint8_t count; {base_type} data[{field.max_size}]; }} {var_name};"
117
+ comment = f" // Variable array: up to {field.max_size} elements"
118
+ else:
119
+ declaration = f"{base_type} {var_name}[1];" # Fallback
120
+ comment = " // Array (error in size specification)"
121
+
122
+ result += f" {declaration}{comment}"
123
+
124
+ # Handle regular strings
125
+ elif field.fieldType == "string":
126
+ if field.size_option is not None:
127
+ # Fixed string: exactly size_option characters
128
+ declaration = f"char {var_name}[{field.size_option}];"
129
+ comment = f" // Fixed string: exactly {field.size_option} chars"
130
+ elif field.max_size is not None:
131
+ # Variable string: length byte + max characters
132
+ declaration = f"struct {{ uint8_t length; char data[{field.max_size}]; }} {var_name};"
133
+ comment = f" // Variable string: up to {field.max_size} chars"
134
+ else:
135
+ declaration = f"char {var_name}[1];" # Fallback
136
+ comment = " // String (error in size specification)"
137
+
138
+ result += f" {declaration}{comment}"
139
+
140
+ # Handle regular fields
141
+ else:
142
+ result += f" {base_type} {var_name};"
143
+
144
+ # Add leading comments
145
+ leading_comment = field.comments
146
+ if leading_comment:
147
+ for c in leading_comment:
148
+ result = c + "\n" + result
149
+
150
+ return result
151
+
152
+
153
+ class MessageCGen():
154
+ @staticmethod
155
+ def generate(msg):
156
+ leading_comment = msg.comments
157
+
158
+ result = ''
159
+ if leading_comment:
160
+ for c in msg.comments:
161
+ result = '%s\n' % c
162
+
163
+ structName = '%s%s' % (pascalCase(msg.package), msg.name)
164
+ result += 'typedef struct %s {' % structName
165
+
166
+ result += '\n'
167
+
168
+ size = 1
169
+ if not msg.fields:
170
+ # Empty structs are not allowed in C standard.
171
+ # Therefore add a dummy field if an empty message occurs.
172
+ result += ' char dummy_field;'
173
+ else:
174
+ size = msg.size
175
+
176
+ result += '\n'.join([FieldCGen.generate(f)
177
+ for key, f in msg.fields.items()])
178
+ result += '\n}'
179
+ result += ' %s;\n\n' % structName
180
+
181
+ defineName = '%s_%s' % (CamelToSnakeCase(
182
+ msg.package).upper(), CamelToSnakeCase(msg.name).upper())
183
+ result += '#define %s_MAX_SIZE %d\n' % (defineName, size)
184
+
185
+ if msg.id:
186
+ result += '#define %s_MSG_ID %d\n' % (defineName, msg.id)
187
+
188
+ funcName = defineName.lower()
189
+ if msg.id:
190
+ result += 'MESSAGE_HELPER(%s, %s, %d, %d);\n\n' % (funcName, structName,
191
+ size, msg.id)
192
+
193
+ return result + '\n'
194
+
195
+ @staticmethod
196
+ def get_initializer(msg, null_init):
197
+ if not msg.fields:
198
+ return '{0}'
199
+
200
+ parts = []
201
+ for field in msg.fields:
202
+ parts.append(field.get_initializer(null_init))
203
+ return '{' + ', '.join(parts) + '}'
204
+
205
+
206
+ class FileCGen():
207
+ @staticmethod
208
+ def generate(package):
209
+ yield '/* Automatically generated struct frame header */\n'
210
+ yield '/* Generated by %s at %s. */\n\n' % (version, time.asctime())
211
+
212
+ yield '#pragma once\n'
213
+ yield '#pragma pack(1)\n'
214
+
215
+ yield '#include "struct_frame.h"\n'
216
+
217
+ # include additional header files if available in the future
218
+
219
+ if package.enums:
220
+ yield '/* Enum definitions */\n'
221
+ for key, enum in package.enums.items():
222
+ yield EnumCGen.generate(enum) + '\n\n'
223
+
224
+ if package.messages:
225
+ yield '/* Struct definitions */\n'
226
+ # Need to sort messages to make sure dependecies are properly met
227
+
228
+ for key, msg in package.sortedMessages().items():
229
+ yield MessageCGen.generate(msg) + '\n'
230
+ yield '\n'
231
+
232
+ # Add default initializers if needed
233
+ # if package.messages:
234
+ # yield '/* Initializer values for message structs */\n'
235
+ # for key, msg in package.messages.items():
236
+ # identifier = '%s_%s_init_default' % (package.name, StyleC.struct_name(msg.name))
237
+ # yield '#define %-40s %s\n' % (identifier, MessageCGen.get_initializer(msg, False))
238
+ # for key, msg in package.messages.items():
239
+ # identifier = '%s_%s_init_zero' % (package.name, StyleC.struct_name(msg.name))
240
+ # yield '#define %-40s %s\n' % (identifier, msg.get_initializer(True))
241
+ # yield '\n'
242
+
243
+ if package.messages:
244
+ yield 'bool get_message_length(size_t msg_id, size_t* size){\n switch (msg_id)\n {\n'
245
+ for key, msg in package.sortedMessages().items():
246
+ name = '%s_%s' % (CamelToSnakeCase(
247
+ msg.package).upper(), CamelToSnakeCase(msg.name).upper())
248
+ if msg.id:
249
+ yield ' case %s_MSG_ID: *size = %s_MAX_SIZE; return true;\n' % (name, name)
250
+
251
+ yield ' default: break;\n } return false;\n}'
252
+ yield '\n'