Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include "structs.hpp"
10 : #include "common.hpp"
11 : #include "enums.hpp"
12 : #include <command.hpp>
13 : #include <kdbease.h>
14 : #include <kdbhelper.h>
15 :
16 0 : bool StructFieldsProcessor::shouldGenerateUnion (const kdb::Key & key)
17 : {
18 0 : return !key.hasMeta ("gen/union/create") || key.getMeta<std::string> ("gen/union/create") == "1";
19 : }
20 :
21 0 : std::string StructFieldsProcessor::discriminatorField (const kdb::Key & key, const std::string & refFieldName)
22 : {
23 0 : auto result = key.hasMeta ("gen/reference/discriminator") ? key.getMeta<std::string> ("gen/reference/discriminator") :
24 0 : refFieldName + "Discriminator";
25 0 : escapeNonAlphaNum (result);
26 0 : return result;
27 : }
28 :
29 2 : std::string StructFieldsProcessor::arraySizeName (const kdb::Key & key, const std::string & arrayFieldName)
30 : {
31 6 : auto result = key.hasMeta ("gen/struct/array/sizefield") ? key.getMeta<std::string> ("gen/struct/array/sizefield") :
32 4 : arrayFieldName + "Size";
33 2 : escapeNonAlphaNum (result);
34 2 : return result;
35 : }
36 :
37 18 : std::string StructFieldsProcessor::getName (const kdb::Key & key, const std::string & fieldKeyName)
38 : {
39 94 : auto result = key.hasMeta ("gen/struct/field") ? key.getMeta<std::string> ("gen/struct/field") : fieldKeyName;
40 18 : escapeNonAlphaNum (result);
41 18 : return result;
42 : }
43 :
44 0 : std::string StructFieldsProcessor::discriminatorKey (const kdb::Key & key)
45 : {
46 0 : auto result = key.hasMeta ("gen/reference/discriminator/key") ? key.getMeta<std::string> ("gen/reference/discriminator/key") :
47 0 : "discriminator";
48 0 : escapeNonAlphaNum (result);
49 0 : return result;
50 : }
51 :
52 0 : std::string StructFieldsProcessor::discriminatorEnumType (const kdb::Key & key)
53 : {
54 0 : if (!key.hasMeta ("gen/reference/discriminator/enum"))
55 : {
56 0 : throw CommandAbortException ("To use alternative references, the key '" + key.getName () +
57 0 : "' must have gen/reference/enum set.");
58 : }
59 :
60 0 : auto result = key.getMeta<std::string> ("gen/reference/discriminator/enum");
61 0 : escapeNonAlphaNum (result);
62 0 : return result;
63 : }
64 :
65 0 : std::string StructFieldsProcessor::discriminatorUnionType (const kdb::Key & key)
66 : {
67 0 : if (!key.hasMeta ("gen/reference/discriminator/union"))
68 : {
69 0 : throw CommandAbortException ("To use alternative references, the key '" + key.getName () +
70 0 : "' must have gen/reference/union set.");
71 : }
72 :
73 0 : auto result = key.getMeta<std::string> ("gen/reference/discriminator/union");
74 0 : escapeNonAlphaNum (result);
75 0 : return result;
76 : }
77 :
78 6 : bool StructFieldsProcessor::processArrayStructRef (const kdb::Key & key, const kdb::Key & parentKey, const kdb::KeySet & allKeys,
79 : std::string & typeName, std::string & nativeType, bool & alloc, std::string & restrict)
80 : {
81 18 : kdb::Key arrayParent = key.dup ();
82 6 : arrayParent.delBaseName ();
83 :
84 18 : arrayParent = allKeys.lookup (arrayParent);
85 24 : if (!arrayParent.hasMeta ("check/reference/restrict"))
86 : {
87 : throw CommandAbortException (
88 : "For array keys with type struct_ref, the array parent (without /# at end) must define 'check/reference/restrict'. "
89 0 : "Key: '" +
90 0 : key.getName () + "'.");
91 : }
92 :
93 24 : if (arrayParent.hasMeta ("type"))
94 : {
95 : throw CommandAbortException (
96 : "For array keys with type struct_ref, the array parent (without /# at end) must NOT define 'type'. "
97 0 : "Key: '" +
98 0 : key.getName () + "'.");
99 : }
100 :
101 30 : restrict = arrayParent.getMeta<std::string> ("check/reference/restrict");
102 :
103 6 : if (ckdb::elektraArrayValidateBaseNameString (restrict.c_str ()) > 0)
104 : {
105 : return false;
106 : }
107 :
108 18 : char * rawResolved = ckdb::elektraResolveReference (restrict.c_str (), arrayParent.getKey (), parentKey.getKey ());
109 :
110 30 : auto restrictKey = allKeys.lookup (rawResolved);
111 6 : ckdb::elektraFree (rawResolved);
112 :
113 6 : if (!restrictKey)
114 : {
115 0 : throw CommandAbortException ("'check/reference/restrict' of array parent '" + arrayParent.getName () +
116 0 : "' resolves to an unspecified key.");
117 : }
118 :
119 36 : if (restrictKey.getMeta<std::string> ("type") != "struct")
120 : {
121 0 : throw CommandAbortException ("'check/reference/restrict' of array parent '" + arrayParent.getName () +
122 0 : "' resolves to a non-struct key.");
123 : }
124 :
125 : bool genType;
126 24 : auto structType = StructProcessor::getType (restrictKey, getTagName (restrictKey, parentKey.getName ()), genType);
127 12 : typeName = "Struct" + structType;
128 12 : nativeType = genType ? structType : "Elektra" + typeName;
129 6 : alloc = StructProcessor::shouldAllocate (restrictKey);
130 :
131 6 : return true;
132 : }
133 :
134 2 : kainjow::mustache::object StructFieldsProcessor::processArrayStructRef (const kdb::Key & key, const std::string & keyName,
135 : const std::string & fieldKeyName)
136 : {
137 4 : std::string typeName;
138 4 : std::string nativeType;
139 4 : std::string restrict;
140 2 : bool alloc = false;
141 :
142 2 : if (!processArrayStructRef (key, parentKey, allKeys, typeName, nativeType, alloc, restrict))
143 : {
144 0 : kdb::Key arrayParent = key.dup ();
145 0 : arrayParent.delBaseName ();
146 :
147 0 : arrayParent = allKeys.lookup (arrayParent);
148 0 : return processStructRefUnion (arrayParent, key, keyName, true, restrict, fieldKeyName);
149 : }
150 :
151 2 : auto name = getName (key, fieldKeyName);
152 4 : auto sizeName = arraySizeName (key, fieldKeyName);
153 :
154 20 : fields.emplace_back (kainjow::mustache::object{
155 10 : { "name", sizeName }, { "is_array_size?", true }, { "array_key", fieldKeyName }, { "native_type", "kdb_long_long_t" } });
156 :
157 : return kainjow::mustache::object{ { "name", name }, { "key_name", keyName }, { "native_type", nativeType },
158 : { "type_name", typeName }, { "alloc?", alloc }, { "is_array?", true },
159 14 : { "is_struct?", true }, { "size_field", sizeName } };
160 : }
161 :
162 0 : bool StructFieldsProcessor::processStructRef (const kdb::Key & key, const kdb::Key & parentKey, const kdb::KeySet & allKeys,
163 : std::string & typeName, std::string & nativeType, bool & alloc, std::string & restrict)
164 : {
165 0 : if (!key.hasMeta ("check/reference/restrict"))
166 : {
167 0 : throw CommandAbortException ("Keys with type struct_ref must also define 'check/reference/restrict'. Key: '" +
168 0 : key.getName () + "'.");
169 : }
170 :
171 0 : restrict = key.getMeta<std::string> ("check/reference/restrict");
172 :
173 0 : if (ckdb::elektraArrayValidateBaseNameString (restrict.c_str ()) > 0)
174 : {
175 : return false;
176 : }
177 :
178 :
179 0 : char * rawResolved = ckdb::elektraResolveReference (restrict.c_str (), key.getKey (), parentKey.getKey ());
180 :
181 0 : auto restrictKey = allKeys.lookup (rawResolved);
182 0 : ckdb::elektraFree (rawResolved);
183 :
184 0 : if (!restrictKey)
185 : {
186 0 : throw CommandAbortException ("'check/reference/restrict' of key '" + key.getName () + "' resolves to an unspecified key.");
187 : }
188 :
189 0 : if (restrictKey.getMeta<std::string> ("type") != "struct")
190 : {
191 0 : throw CommandAbortException ("'check/reference/restrict' of key '" + key.getName () + "' resolves to a non-struct key.");
192 : }
193 :
194 : bool genType;
195 0 : auto structType = StructProcessor::getType (restrictKey, getTagName (restrictKey, parentKey.getName ()), genType);
196 0 : typeName = "Struct" + structType;
197 0 : nativeType = genType ? structType : "Elektra" + typeName;
198 0 : alloc = StructProcessor::shouldAllocate (restrictKey);
199 :
200 0 : return true;
201 : }
202 :
203 0 : kainjow::mustache::object StructFieldsProcessor::processStructRefUnion (const kdb::Key & checkKey, const kdb::Key & genKey,
204 : const std::string & keyName, bool isArray, const std::string & end,
205 : const std::string & fieldKeyName)
206 : {
207 0 : auto discriminatorField = StructFieldsProcessor::discriminatorField (genKey, fieldKeyName);
208 0 : auto discriminatorKeyName = StructFieldsProcessor::discriminatorKey (genKey);
209 :
210 0 : std::string enumType = StructFieldsProcessor::discriminatorEnumType (genKey);
211 0 : auto enumPrefix = camelCaseToMacroCase (enumType);
212 :
213 0 : std::string unionType = StructFieldsProcessor::discriminatorUnionType (genKey);
214 0 : kainjow::mustache::list unionFields;
215 0 : bool generateUnion = shouldGenerateUnion (genKey);
216 :
217 0 : kdb::long_long_t i = 0;
218 0 : std::string cur = "#0";
219 0 : while (cur <= end)
220 : {
221 0 : if (checkKey.hasMeta ("check/reference/restrict/" + cur))
222 : {
223 0 : auto restrict = checkKey.getMeta<std::string> ("check/reference/restrict/" + cur);
224 0 : char * rawResolved = ckdb::elektraResolveReference (restrict.c_str (), checkKey.getKey (), parentKey.getKey ());
225 :
226 0 : auto restrictKey = allKeys.lookup (rawResolved);
227 0 : ckdb::elektraFree (rawResolved);
228 :
229 0 : if (!restrictKey)
230 : {
231 0 : throw CommandAbortException ("'check/reference/restrict' of key '" + checkKey.getName () +
232 0 : "' resolves to an unspecified key.");
233 : }
234 :
235 0 : if (restrictKey.getMeta<std::string> ("type") != "struct")
236 : {
237 0 : throw CommandAbortException ("'check/reference/restrict' of key '" + checkKey.getName () +
238 0 : "' resolves to a non-struct key.");
239 : }
240 :
241 0 : auto discriminatorRef = restrict + "/";
242 0 : discriminatorRef += discriminatorKeyName;
243 0 : rawResolved = ckdb::elektraResolveReference (discriminatorRef.c_str (), checkKey.getKey (), parentKey.getKey ());
244 :
245 0 : auto discriminatorKey = allKeys.lookup (rawResolved);
246 0 : ckdb::elektraFree (rawResolved);
247 :
248 0 : if (!discriminatorKey)
249 : {
250 0 : throw CommandAbortException ("'check/reference/restrict' of key '" + checkKey.getName () +
251 0 : "' resolves to an unspecified key.");
252 : }
253 :
254 0 : if (discriminatorKey.getMeta<std::string> ("type") != "discriminator" ||
255 0 : discriminatorKey.getMeta<std::string> ("check/type") != "enum")
256 : {
257 0 : throw CommandAbortException ("The discriminator key '" + discriminatorKey.getName () + "' for key '" +
258 0 : genKey.getName () + "' must have type 'discriminator' and check/type 'enum'.");
259 : }
260 :
261 0 : if (discriminatorKey.getMeta<std::string> ("gen/enum/type") != enumType)
262 : {
263 0 : throw CommandAbortException ("The discriminator key '" + discriminatorKey.getName () + "' for key '" +
264 0 : genKey.getName () + "' must have gen/enum/type set to '" + enumType + "'.");
265 : }
266 :
267 0 : if (!genKey.hasMeta ("gen/reference/restrict/" + cur + "/discriminator"))
268 : {
269 : throw CommandAbortException (
270 0 : "To use alternative references in key '" + genKey.getName () +
271 0 : "', you must set the gen/reference/restrict/#/value for each check/reference/restrict/# on key " +
272 0 : checkKey.getName ());
273 : }
274 :
275 0 : std::string enumValueString = genKey.getMeta<std::string> ("gen/reference/restrict/" + cur + "/discriminator");
276 :
277 0 : if (discriminatorKey.getMeta<std::string> ("check/enum/" + cur) != enumValueString)
278 : {
279 0 : std::string msg = "The discriminator key '" + discriminatorKey.getName ();
280 0 : msg += "' for key '" + genKey.getName () + "' must have check/enum/";
281 0 : msg += cur + " set to '";
282 0 : msg += enumValueString + "'.";
283 0 : throw CommandAbortException (msg);
284 : }
285 :
286 : bool genType;
287 0 : auto structType = StructProcessor::getType (restrictKey, getTagName (restrictKey, parentKey.getName ()), genType);
288 0 : auto typeName = "Struct" + structType;
289 0 : auto nativeType = genType ? structType : "Elektra" + typeName;
290 0 : auto alloc = StructProcessor::shouldAllocate (restrictKey);
291 :
292 0 : if (!alloc)
293 : {
294 : throw CommandAbortException (
295 : "All structs referenced by alternative references must be allocating (gen/struct/alloc = 1). "
296 0 : "Key: " +
297 0 : restrictKey.getName () + " referenced by:" + genKey.getName ());
298 : }
299 :
300 0 : std::string name = enumValueString;
301 0 : escapeNonAlphaNum (name);
302 :
303 0 : std::string enumValue = enumPrefix + "_";
304 0 : enumValue += camelCaseToMacroCase (enumValueString);
305 0 : escapeNonAlphaNum (enumValue);
306 :
307 0 : unionFields.emplace_back (kainjow::mustache::object{ { "name", name },
308 : { "native_type", nativeType },
309 : { "enum_value", enumValue },
310 : { "type_name", typeName },
311 0 : { "union_type", unionType } });
312 : }
313 0 : ++i;
314 0 : auto indexString = std::to_string (i);
315 0 : cur = "#" + std::string (indexString.length () - 1, '_') + std::to_string (i);
316 : }
317 :
318 0 : if (unionFields.empty ())
319 : {
320 0 : throw CommandAbortException ("Key with alternative references must have at least 1 alternative. Key: " + genKey.getName ());
321 : }
322 :
323 0 : auto name = getName (genKey, fieldKeyName);
324 :
325 : auto field = kainjow::mustache::object{ { "name", name },
326 : { "key_name", keyName },
327 : { "native_type", unionType },
328 0 : { "type_name", "Union" + unionType },
329 : { "is_array?", isArray },
330 : { "is_struct?", false },
331 : { "is_union?", true },
332 : { "discr_native_type", enumType },
333 0 : { "discr_type_name", "Enum" + enumType },
334 : { "discr_suffix", discriminatorKeyName },
335 0 : { "discr_field", discriminatorField } };
336 :
337 0 : if (isArray)
338 : {
339 0 : auto sizeName = arraySizeName (genKey, fieldKeyName);
340 :
341 0 : fields.emplace_back (kainjow::mustache::object{ { "name", sizeName },
342 : { "is_array_size?", true },
343 : { "array_key", fieldKeyName },
344 0 : { "native_type", "kdb_long_long_t" } });
345 :
346 0 : field["size_field"] = sizeName;
347 : }
348 :
349 0 : fields.emplace_back (kainjow::mustache::object{ { "name", discriminatorField },
350 : { "is_discriminator?", true },
351 : { "is_array?", isArray },
352 : { "union_key", fieldKeyName },
353 0 : { "native_type", enumType } });
354 :
355 0 : unions.emplace_back (kainjow::mustache::object{ { "native_type", unionType },
356 0 : { "type_name", "Union" + unionType },
357 : { "fields", unionFields },
358 : { "generate_typedef?", generateUnion },
359 : { "discr_native_type", enumType },
360 0 : { "default_type", unionFields[0]["native_type"] },
361 0 : { "generate_setters?", false } });
362 :
363 0 : return field;
364 : }
365 :
366 :
367 0 : kainjow::mustache::object StructFieldsProcessor::processStructRef (const kdb::Key & key, const std::string & keyName,
368 : const std::string & fieldKeyName)
369 : {
370 0 : std::string typeName;
371 0 : std::string nativeType;
372 0 : std::string restrict;
373 0 : bool alloc = false;
374 :
375 0 : if (!processStructRef (key, parentKey, allKeys, typeName, nativeType, alloc, restrict))
376 : {
377 0 : return processStructRefUnion (key, key, keyName, false, restrict, fieldKeyName);
378 : }
379 :
380 0 : auto name = getName (key, fieldKeyName);
381 :
382 : return kainjow::mustache::object{ { "name", name }, { "key_name", keyName }, { "native_type", nativeType },
383 : { "type_name", typeName }, { "alloc?", alloc }, { "is_array?", false },
384 0 : { "is_struct?", true } };
385 : }
386 :
387 6 : void StructFieldsProcessor::processAll ()
388 : {
389 : using namespace kainjow::mustache;
390 :
391 12 : std::stringstream ss;
392 :
393 12 : size_t baseParts = getKeyParts (structKey).size ();
394 :
395 6 : maxFieldNameLen = 0;
396 70 : for (const kdb::Key & key : structKeys)
397 : {
398 18 : if (!hasType (key))
399 : {
400 2 : continue;
401 : }
402 :
403 32 : auto parts = getKeyParts (key);
404 32 : auto isArray = parts.back () == "#";
405 :
406 34 : auto end = isArray ? parts.end () - 1 : parts.end ();
407 64 : std::string fieldKeyName = parts[baseParts];
408 82 : for (auto it = parts.begin () + baseParts + 1; it != end; ++it)
409 : {
410 6 : fieldKeyName += "_" + *it;
411 : }
412 32 : fieldKeyName = snakeCaseToCamelCase (fieldKeyName);
413 :
414 32 : const std::string & type = ::getType (key);
415 :
416 : std::unordered_set<std::string> allowedTypes = { "struct_ref", "enum", "string", "boolean",
417 : "char", "octet", "short", "unsigned_short",
418 : "long", "unsigned_long", "long_long", "unsigned_long_long",
419 608 : "float", "double", "long_double", "discriminator" };
420 :
421 16 : if (type == "struct")
422 : {
423 0 : auto msg = "The key '" + key.getName ();
424 0 : msg += "' has an unsupported type ('" + type + "')! Cannot have structs inside structs, please use struct_ref.";
425 0 : throw CommandAbortException (msg);
426 : }
427 :
428 48 : if (allowedTypes.find (type) == allowedTypes.end ())
429 : {
430 0 : auto msg = "The key '" + key.getName ();
431 0 : msg += "' has an unsupported type ('" + type + "')!";
432 0 : throw CommandAbortException (msg);
433 : }
434 :
435 16 : if (type == "discriminator")
436 : {
437 0 : continue;
438 : }
439 :
440 16 : auto isStruct = type == "struct_ref";
441 :
442 16 : if (!allocating && isStruct)
443 : {
444 0 : auto msg = "Cannot have struct_refs inside non-allocating structs. The key '" + key.getName ();
445 0 : msg += "' is a struct_ref appearing inside '" + structKey.getName () + ", which is a non-allocating struct.";
446 0 : throw CommandAbortException (msg);
447 : }
448 :
449 16 : if (!allocating && isArray)
450 : {
451 0 : auto msg = "Cannot have arrays inside non-allocating structs. The key '" + key.getName ();
452 0 : msg += "' is an array appearing inside '" + structKey.getName () + ", which is a non-allocating struct.";
453 0 : throw CommandAbortException (msg);
454 : }
455 :
456 32 : auto typeName = snakeCaseToPascalCase (type);
457 48 : auto nativeType = type == "string" ? "const char *" : "kdb_" + type + "_t";
458 :
459 32 : auto tagName = getTagName (key, specParentName);
460 :
461 16 : if (type == "enum")
462 : {
463 : bool genType;
464 0 : auto enumType = EnumProcessor::getType (key, tagName, genType);
465 :
466 0 : typeName = "Enum" + enumType;
467 0 : nativeType = genType ? enumType : "Elektra" + typeName;
468 : }
469 :
470 64 : auto keyName = key.getName ().substr (structKey.getName ().length () + 1);
471 :
472 32 : auto name = getName (key, fieldKeyName);
473 :
474 16 : if (isArray)
475 : {
476 4 : keyName = keyName.substr (0, keyName.length () - 2);
477 : }
478 :
479 32 : maxFieldNameLen = std::max (maxFieldNameLen, keyName.size ());
480 :
481 48 : ss << nativeType << " " << name << "\n";
482 :
483 16 : if (isStruct)
484 : {
485 2 : containsStructRef = true;
486 :
487 2 : if (isArray)
488 : {
489 6 : fields.push_back (processArrayStructRef (key, keyName, fieldKeyName));
490 : }
491 : else
492 : {
493 0 : fields.push_back (processStructRef (key, keyName, fieldKeyName));
494 : }
495 : }
496 : else
497 : {
498 :
499 : auto field = object{ { "name", name }, { "key_name", keyName }, { "native_type", nativeType },
500 : { "type_name", typeName }, { "alloc?", true }, { "is_array?", isArray },
501 112 : { "is_struct?", false } };
502 :
503 14 : if (isArray)
504 : {
505 0 : auto sizeName = arraySizeName (key, fieldKeyName);
506 :
507 0 : fields.emplace_back (object{ { "name", sizeName },
508 : { "is_array_size?", true },
509 : { "array_key", fieldKeyName },
510 0 : { "native_type", "kdb_long_long_t" } });
511 :
512 0 : field["size_field"] = sizeName;
513 : }
514 :
515 14 : fields.emplace_back (field);
516 : }
517 : }
518 :
519 12 : fieldsString = ss.str ();
520 6 : processed = true;
521 6 : }
522 :
523 12 : std::string StructProcessor::getType (const kdb::Key & key, const std::string & tagName, bool & genType)
524 : {
525 48 : genType = key.hasMeta ("gen/struct/type");
526 28 : return genType ? key.getMeta<std::string> ("gen/struct/type") : snakeCaseToPascalCase (tagName);
527 : }
528 :
529 6 : bool StructProcessor::shouldGenerateTypeDef (const kdb::Key & key)
530 : {
531 24 : return !key.hasMeta ("gen/struct/create") || key.getMeta<std::string> ("gen/struct/create") == "1";
532 : }
533 :
534 12 : bool StructProcessor::shouldAllocate (const kdb::Key & key)
535 : {
536 80 : return key.hasMeta ("gen/struct/alloc") && key.getMeta<std::string> ("gen/struct/alloc") == "1";
537 : }
538 :
539 18 : bool StructProcessor::isFieldIgnored (const kdb::Key & key)
540 : {
541 72 : return key.hasMeta ("gen/struct/field/ignore") && key.getMeta<std::string> ("gen/struct/field/ignore") == "1";
542 : }
543 :
544 6 : kainjow::mustache::object StructProcessor::process (const kdb::Key & key, const kdb::KeySet & subkeys, const std::string & tagName,
545 : const std::string & specParentName, kainjow::mustache::list & unions)
546 : {
547 : using namespace kainjow::mustache;
548 :
549 12 : auto name = key.getName ();
550 6 : name.erase (0, sizeof ("spec") - 1);
551 :
552 : bool genType;
553 12 : auto structType = getType (key, tagName, genType);
554 12 : auto typeName = "Struct" + structType;
555 :
556 16 : auto nativeType = genType ? structType : "Elektra" + typeName;
557 :
558 :
559 6 : auto allocate = shouldAllocate (key);
560 :
561 18 : StructFieldsProcessor fieldsProcessor (parentKey, allKeys, key, subkeys, allocate, specParentName);
562 12 : auto fields = fieldsProcessor.getFields ();
563 12 : std::string fieldsString = fieldsProcessor.getFieldsString ();
564 6 : size_t maxFieldNameLen = fieldsProcessor.getMaxFieldNameLen ();
565 12 : unions = fieldsProcessor.getUnions ();
566 6 : auto containsStructRef = fieldsProcessor.getContainsStructRef ();
567 :
568 6 : auto isNew = true;
569 6 : auto generateTypeDef = shouldGenerateTypeDef (key);
570 :
571 12 : auto other = structTypes.find (typeName);
572 12 : if (other != structTypes.end ())
573 : {
574 0 : auto otherFieldsString = other->second.second;
575 0 : if (otherFieldsString != fieldsString)
576 : {
577 0 : auto otherKey = other->second.first;
578 0 : auto msg = "The key '" + name;
579 0 : msg += "' uses the same 'gen/struct/type' as the key '" + otherKey + "', but their fields are different!";
580 0 : throw CommandAbortException (msg);
581 : }
582 :
583 0 : isNew = false;
584 : }
585 :
586 18 : structTypes[typeName] = std::make_pair (name, fieldsString);
587 :
588 : return object{ { "new", isNew },
589 : { "type_name", typeName },
590 : { "native_type", nativeType },
591 : { "generate_typedef?", generateTypeDef },
592 : { "fields", fields },
593 18 : { "max_field_len", std::to_string (maxFieldNameLen + 1) },
594 : { "alloc?", allocate },
595 54 : { "generate_setters?", !containsStructRef } };
596 7164 : }
|