changeset 519:17106b29ed6d bgo-commands-codegen

Changed the metadata system for structs. A __handler entry is now required (with "cpp", "ts" or both: ["cpp","ts"]). Changed the enumerations to string-based values. Adapted the integrated wasm test.
author Benjamin Golinvaux <bgo@osimis.io>
date Tue, 12 Mar 2019 13:11:18 +0100
parents 40bb5eb247a5
children 7a16fb9a4ba5 700aa66f2f29
files Resources/CodeGeneration/stonegentool.py Resources/CodeGeneration/template.in.h.j2 Resources/CodeGeneration/template.in.ts.j2 Resources/CodeGeneration/testWasmIntegrated/CMakeLists.txt Resources/CodeGeneration/testWasmIntegrated/testWasmIntegrated.ts Resources/CodeGeneration/testWasmIntegrated/testWasmIntegratedCpp_api.yaml
diffstat 6 files changed, 88 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/Resources/CodeGeneration/stonegentool.py	Tue Mar 12 09:19:06 2019 +0100
+++ b/Resources/CodeGeneration/stonegentool.py	Tue Mar 12 13:11:18 2019 +0100
@@ -211,8 +211,8 @@
         return (True, m.group(1), listOfDependentTypes)
 
 def GetStructFields(struct):
-  """This filters out the __meta__ key from the struct fields"""
-  return [k for k in struct.keys() if k != '__meta__']
+  """This filters out the special metadata key from the struct fields"""
+  return [k for k in struct.keys() if k != '__handler']
 
 def ComputeOrderFromTypeTree(
   ancestors, 
@@ -350,39 +350,49 @@
   return genOrder
 
 def GetStructFields(fieldDict):
-  """Returns the regular (non __meta__) struct fields"""
+  """Returns the regular (non __handler) struct fields"""
   # the following happens for empty structs
   if fieldDict == None:
     return fieldDict
   ret = {}
   for k,v in fieldDict.items():
-    if k != "__meta__":
+    if k != "__handler":
       ret[k] = v
+    if k.startswith("__") and k != "__handler":
+      raise RuntimeError("Fields starting with __ (double underscore) are reserved names!")
   return ret
 
 def GetStructMetadata(fieldDict):
-  """Returns the __meta__ struct fields (there are default values that
+  """Returns the __handler struct fields (there are default values that
      can be overridden by entries in the schema
-     Not tested because it's a fail-safe: if something is broken in meta, 
+     Not tested because it's a fail-safe: if something is broken in this, 
      dependent projects will not build."""
   metadataDict = {}
-  metadataDict['handleInCpp'] = True
-  metadataDict['handleInTypescript'] = True
+  metadataDict['handleInCpp'] = False
+  metadataDict['handleInTypescript'] = False
   
-  # Empty types are allowed
   if fieldDict != None:
     for k,v in fieldDict.items():
-      if k == "__meta__":
-        # let's examine the various metadata entries
-        for metaKey,metaValue in v.items():
-          # we only accept overriding EXISTING entries
-          if metaKey in metadataDict:
-            # simple check, valid for now
-            if type(metaValue) != bool:
-              raise RuntimeError("Wrong value for metadata key")
-            metadataDict[metaKey] = metaValue
+      if k.startswith("__") and k != "__handler":
+        raise RuntimeError("Fields starting with __ (double underscore) are reserved names")
+      if k == "__handler":
+        if type(v) == list:
+          for i in v:
+            if i == "cpp":
+              metadataDict['handleInCpp'] = True
+            elif i == "ts":
+              metadataDict['handleInTypescript'] = True
+            else:
+              raise RuntimeError("Error in schema. Allowed values for __handler are \"cpp\" or \"ts\"")
+        elif type(v) == str:
+          if v == "cpp":
+            metadataDict['handleInCpp'] = True
+          elif v == "ts":
+            metadataDict['handleInTypescript'] = True
           else:
-            raise RuntimeError("Wrong key \"{metaKey}\" in metadata. Allowed keys are \"{metadataDict.keys()}\"")
+            raise RuntimeError("Error in schema. Allowed values for __handler are \"cpp\" or \"ts\" (or a list of both)")
+        else:
+            raise RuntimeError("Error in schema. Allowed values for __handler are \"cpp\" or \"ts\" (or a list of both)")
   return metadataDict
 
 def ProcessSchema(schema, genOrder):
@@ -465,7 +475,7 @@
       if ch == ':':
         if not (nextCh == ' ' or nextCh == '\n'):
           lineNumber = schemaText.count("\n",0,i) + 1
-          raise RuntimeError(f"Error at line {lineNumber} in the schema: colons must be followed by a space or a newline!")
+          raise RuntimeError("Error at line " + str(lineNumber) + " in the schema: colons must be followed by a space or a newline!")
     schema = yaml.load(schemaText)
   return schema
 
--- a/Resources/CodeGeneration/template.in.h.j2	Tue Mar 12 09:19:06 2019 +0100
+++ b/Resources/CodeGeneration/template.in.h.j2	Tue Mar 12 13:11:18 2019 +0100
@@ -232,17 +232,6 @@
 {% for key in enum['fields']%}    {{enum['name']}}_{{key}},
 {%endfor%}  };
 
-  inline void _StoneDeserializeValue(
-    {{enum['name']}}& destValue, const Json::Value& jsonValue)
-  {
-    destValue = static_cast<{{enum['name']}}>(jsonValue.asInt64());
-  }
-
-  inline Json::Value _StoneSerializeValue(const {{enum['name']}}& value)
-  {
-    return Json::Value(static_cast<int64_t>(value));
-  }
-
   inline std::string ToString(const {{enum['name']}}& value)
   {
 {% for key in enum['fields']%}    if( value == {{enum['name']}}_{{key}})
@@ -262,14 +251,28 @@
 {% for key in enum['fields']%}    if( strValue == std::string("{{key}}") )
     {
       value = {{enum['name']}}_{{key}};
+      return;
     }
 {%endfor%}
     std::stringstream ss;
-    ss << "String \"" << strValue << "\" cannot be converted to {{enum['name']}}. Possible values are: {% for key in enum['fields']%}{{key}}{% endfor %}";
+    ss << "String \"" << strValue << "\" cannot be converted to {{enum['name']}}. Possible values are: {% for key in enum['fields']%}{{key}} {% endfor %}";
     std::string msg = ss.str();
     throw std::runtime_error(msg);
   }
 
+
+  inline void _StoneDeserializeValue(
+    {{enum['name']}}& destValue, const Json::Value& jsonValue)
+  {
+    FromString(destValue, jsonValue.asString());
+  }
+
+  inline Json::Value _StoneSerializeValue(const {{enum['name']}}& value)
+  {
+    std::string strValue = ToString(value);
+    return Json::Value(strValue);
+  }
+
   inline std::ostream& StoneDumpValue(std::ostream& out, const {{enum['name']}}& value, int indent = 0)
   {
 {% for key in enum['fields']%}    if( value == {{enum['name']}}_{{key}})
--- a/Resources/CodeGeneration/template.in.ts.j2	Tue Mar 12 09:19:06 2019 +0100
+++ b/Resources/CodeGeneration/template.in.ts.j2	Tue Mar 12 13:11:18 2019 +0100
@@ -39,10 +39,37 @@
 // end of generic methods
 {% for enum in enums%}
 export enum {{enum['name']}} {
-  {% for key in enum['fields']%}{{key}},
-  {%endfor%}
-};
+{% for key in enum['fields']%}  {{key}} = "{{key}}"{% if not loop.last %},{%endif%}
+{%endfor%}};
+
+export function {{enum['name']}}_FromString(strValue:string) : {{enum['name']}}
+{
+{% for key in enum['fields'] %}  if( strValue == "{{key}}" )
+  {
+    return {{enum['name']}}.{{key}};
+  }
 {%endfor%}
+  let msg : string =  `String ${strValue} cannot be converted to {{enum['name']}}. Possible values are: {% for key in enum['fields']%}{{key}}{% if not loop.last %}, {%endif%}{% endfor %}`;
+  throw new Error(msg);
+}
+
+export function {{enum['name']}}_ToString(value:{{enum['name']}}) : string
+{
+{% for key in enum['fields'] %}  if( value == {{enum['name']}}.{{key}} )
+  {
+    return "{{key}}";
+  }
+{%endfor%}
+  let msg : string = `Value ${value} cannot be converted to {{enum['name']}}. Possible values are: `;
+{% for key in enum['fields']%}  {
+    let _{{key}}_enumValue : string = {{enum['name']}}.{{key}}; // enums are strings in stonecodegen, so this will work.
+    let msg_{{key}} : string = `{{key}} (${_{{key}}_enumValue}){% if not loop.last %}, {%endif%}`;
+    msg = msg + msg_{{key}};
+  }
+{%endfor%}  throw new Error(msg);
+}
+{%endfor%}
+
 
 {% for struct in structs%}export class {{struct['name']}} {
 {% if struct %}{% if struct['fields'] %}{% for key in struct['fields']%}  {{key}}:{{CanonToTs(struct['fields'][key])}};
--- a/Resources/CodeGeneration/testWasmIntegrated/CMakeLists.txt	Tue Mar 12 09:19:06 2019 +0100
+++ b/Resources/CodeGeneration/testWasmIntegrated/CMakeLists.txt	Tue Mar 12 13:11:18 2019 +0100
@@ -23,7 +23,7 @@
 add_custom_command(
     OUTPUT  ${CMAKE_CURRENT_BINARY_DIR}/testWasmIntegratedCpp_generated.hpp ${CMAKE_CURRENT_BINARY_DIR}/testWasmIntegratedCpp_generated.ts
     COMMAND python3 ${CMAKE_CURRENT_LIST_DIR}/../stonegentool.py -o ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/testWasmIntegratedCpp_api.yaml
-    DEPENDS ${testCppHandler_Codegen_Deps}
+    DEPENDS ${testCppHandler_Codegen_Deps} ${CMAKE_CURRENT_LIST_DIR}/testWasmIntegratedCpp_api.yaml 
 )
 
 add_executable(testWasmIntegratedCpp
--- a/Resources/CodeGeneration/testWasmIntegrated/testWasmIntegrated.ts	Tue Mar 12 09:19:06 2019 +0100
+++ b/Resources/CodeGeneration/testWasmIntegrated/testWasmIntegrated.ts	Tue Mar 12 13:11:18 2019 +0100
@@ -108,14 +108,14 @@
       {
         "a" : 43,
         "b" : "Sandrine",
-        "c" : 2,
+        "c" : "March",
         "d" : true
       },
       "55" : 
       {
         "a" : 42,
         "b" : "Benjamin",
-        "c" : 0,
+        "c" : "January",
         "d" : false
       }
     },
@@ -124,13 +124,13 @@
       {
         "a" : 42,
         "b" : "Benjamin",
-        "c" : 0,
+        "c" : "March",
         "d" : false
       },
       {
         "a" : 43,
         "b" : "Sandrine",
-        "c" : 2,
+        "c" : "January",
         "d" : false
       }
     ],
--- a/Resources/CodeGeneration/testWasmIntegrated/testWasmIntegratedCpp_api.yaml	Tue Mar 12 09:19:06 2019 +0100
+++ b/Resources/CodeGeneration/testWasmIntegrated/testWasmIntegratedCpp_api.yaml	Tue Mar 12 13:11:18 2019 +0100
@@ -42,10 +42,17 @@
 enum CrispType:
   - SaltAndPepper
   - CreamAndChives
+  - Barbecue
   - Paprika
-  - Barbecue
 
 enum EnumMonth0:
   - January
   - February
   - March
+
+enum Tata:
+  - Lolo
+  - Rrrrrrrrrrrr
+
+
+