LCOV - code coverage report
Current view: top level - src/tools/kdb/gen/highlevel - structs.cpp (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 110 286 38.5 %
Date: 2019-09-12 12:28:41 Functions: 11 19 57.9 %

          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 : }

Generated by: LCOV version 1.13