sdbus++: use consistent typenames for properties

Previously, the generated code was assuming C++ names, but the example
(Calculator.interface.yaml) used an arbitrary name ('integer').  This
commit defines a consistent typename scheme and validates it when
interfaces are generated.

Use English typenames from the DBus protocol in interface files
rather than the C++ name or a single-letter DBus name.  Use
square-bracket ([]) to identify sub-types for containers.

Examples: 'int64', 'path', 'array[dict[string, byte]]'

Change-Id: I38abe84c9cd3d5f839968349d2d3cfa0b8796cd0
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/tools/example/net/poettering/Calculator.interface.yaml b/tools/example/net/poettering/Calculator.interface.yaml
index 2c288b6..4167c36 100644
--- a/tools/example/net/poettering/Calculator.interface.yaml
+++ b/tools/example/net/poettering/Calculator.interface.yaml
@@ -8,17 +8,17 @@
         Multiplies two integers 'x' and 'y' and returns the result.
       parameters:
         - name: x
-          type: integer
+          type: int64
           description: >
             The first integer to multiply.
         - name: y
-          type: integer
+          type: int64
           description: >
             The second integer to multiply.
           default: 1
       returns:
         - name: z
-          type: integer
+          type: int64
           description: >
             The result of (x*y).
     - name: Divide
@@ -26,17 +26,17 @@
         Divides two integers 'x' and 'y' and returns the result.
       parameters:
         - name: x
-          type: integer
+          type: int64
           description: >
             The first integer to divide.
         - name: y
-          type: integer
+          type: int64
           description: >
             The second integer to divide.
           default: 1
       returns:
         - name: z
-          type: integer
+          type: int64
           description: >
             The result of (x/y).
       errors:
@@ -46,7 +46,7 @@
         Reset the LastResult property to zero.
 properties:
     - name: LastResult
-      type: integer
+      type: int64
       default: 0
       description: >
         The result of the most recent calculation.
@@ -56,7 +56,7 @@
         Signal indicating the LastReset property has been set to zero by the
         'Clear' method.
       properties:
-        - type: integer
+        - type: int64
           description: >
             Value of LastReset prior to Clear.
 
diff --git a/tools/sdbusplus/property.py b/tools/sdbusplus/property.py
index 2c35b63..bdff93d 100644
--- a/tools/sdbusplus/property.py
+++ b/tools/sdbusplus/property.py
@@ -1,14 +1,86 @@
 from .namedelement import NamedElement
 from .renderer import Renderer
+import yaml
 
 
 class Property(NamedElement, Renderer):
     def __init__(self, **kwargs):
         self.typeName = kwargs.pop('type', None)
+        self.cppTypeName = self.parse_cpp_type(self.typeName)
         self.defaultValue = kwargs.pop('default', None)
 
         super(Property, self).__init__(**kwargs)
 
+    def parse_cpp_type(self, typeName):
+        if not typeName:
+            return None
+
+        """ typeNames are _almost_ valid YAML.  Insert a , before each [
+            and then wrap it in a [ ] and it becomes valid YAML.  (assuming
+            the user gave us a valid typename)
+        """
+        parse = yaml.safe_load("[" + ",[".join(typeName.split("[")) + "]")
+        return self.__parse_cpp_type__(parse)
+
+    """ Take a list of dbus types and perform validity checking, such as:
+            [ variant [ dict [ int32, int32 ], double ] ]
+        This function then converts the type-list into a C++ type string.
+    """
+    def __parse_cpp_type__(self, typeArray):
+        propertyMap = {
+            'byte': {'cppName': 'uint8_t', 'params': 0},
+            'boolean': {'cppName': 'bool', 'params': 0},
+            'int16': {'cppName': 'int16_t', 'params': 0},
+            'uint16': {'cppName': 'uint16_t', 'params': 0},
+            'int32': {'cppName': 'int32_t', 'params': 0},
+            'uint32': {'cppName': 'uint32_t', 'params': 0},
+            'int64': {'cppName': 'int64_t', 'params': 0},
+            'uint64': {'cppName': 'uint64_t', 'params': 0},
+            'double': {'cppName': 'double', 'params': 0},
+            'string': {'cppName': 'std::string', 'params': 0},
+            'path': {'cppName': 'std::string', 'params': 0},
+            'signature': {'cppName': 'std::string', 'params': 0},
+            'array': {'cppName': 'std::vector', 'params': 1},
+            'struct': {'cppName': 'std::tuple', 'params': -1},
+            'variant': {'cppName': 'sdbusplus::variant', 'params': -1},
+            'dict': {'cppName': 'std::map', 'params': 2},
+            'enum': {'cppName': 'enum', 'params': 1, 'noparse': True}}
+
+        first = typeArray.pop(0)
+        entry = propertyMap[first]
+
+        result = entry['cppName']
+
+        # Handle 0-entry parameter lists.
+        if (entry['params'] == 0):
+            if (len(typeArray) != 0):
+                raise RuntimeError("Invalid typeArray %s" % typeArray)
+            else:
+                return result
+
+        # Get remainder of the parameter list, which should be the last
+        # element.
+        rest = typeArray.pop(0)
+        if (len(typeArray) != 0):
+            raise RuntimeError("Invalid typeArray %s" % typeArray)
+
+        # Confirm parameter count matches.
+        if (entry['params'] != -1) and (entry['params'] != len(rest)):
+            raise RuntimeError("Invalid entry count for %s : %s" %
+                               (first, rest))
+
+        # Parse each parameter entry, if appropriate, and create C++ template
+        # syntax.
+        result += '<'
+        if entry.get('noparse'):
+            result += ", ".join(rest)
+        else:
+            result += ", ".join(map(lambda e: self.__parse_cpp_type__([e]),
+                                    rest))
+        result += '>'
+
+        return result
+
     def markdown(self, loader):
         return self.render(loader, "property.mako.md", property=self,
                            post=str.strip)
diff --git a/tools/sdbusplus/templates/interface.mako.server.cpp b/tools/sdbusplus/templates/interface.mako.server.cpp
index cc0d900..6f74ff5 100644
--- a/tools/sdbusplus/templates/interface.mako.server.cpp
+++ b/tools/sdbusplus/templates/interface.mako.server.cpp
@@ -35,7 +35,7 @@
     % endfor
 
     % for p in interface.properties:
-${p.typeName} ${classname}::${p.camelCase}() const
+${p.cppTypeName} ${classname}::${p.camelCase}() const
 {
     return _${p.camelCase};
 }
@@ -53,7 +53,7 @@
     return 0;
 }
 
-${p.typeName} ${classname}::${p.camelCase}(${p.typeName} value)
+${p.cppTypeName} ${classname}::${p.camelCase}(${p.cppTypeName} value)
 {
     if (_${p.camelCase} != value)
     {
@@ -86,7 +86,7 @@
 {
 static const auto _property_${p.name} =
     utility::tuple_to_array(message::types::type_id<
-            ${p.typeName}>());
+            ${p.cppTypeName}>());
 }
 }
     % endfor
diff --git a/tools/sdbusplus/templates/interface.mako.server.hpp b/tools/sdbusplus/templates/interface.mako.server.hpp
index 795205b..954742d 100644
--- a/tools/sdbusplus/templates/interface.mako.server.hpp
+++ b/tools/sdbusplus/templates/interface.mako.server.hpp
@@ -49,9 +49,9 @@
 
     % for p in interface.properties:
         /** Get value of ${p.name} */
-        virtual ${p.typeName} ${p.camelCase}() const;
+        virtual ${p.cppTypeName} ${p.camelCase}() const;
         /** Set value of ${p.name} */
-        virtual ${p.typeName} ${p.camelCase}(${p.typeName} value);
+        virtual ${p.cppTypeName} ${p.camelCase}(${p.cppTypeName} value);
     % endfor
 
     private:
@@ -78,9 +78,9 @@
 
     % for p in interface.properties:
         % if p.defaultValue:
-        ${p.typeName} _${p.camelCase} = ${p.defaultValue};
+        ${p.cppTypeName} _${p.camelCase} = ${p.defaultValue};
         % else:
-        ${p.typeName} _${p.camelCase}{};
+        ${p.cppTypeName} _${p.camelCase}{};
         % endif
     % endfor
 
diff --git a/tools/sdbusplus/templates/method.mako.prototype.hpp b/tools/sdbusplus/templates/method.mako.prototype.hpp
index db056ff..20a4373 100644
--- a/tools/sdbusplus/templates/method.mako.prototype.hpp
+++ b/tools/sdbusplus/templates/method.mako.prototype.hpp
@@ -3,7 +3,7 @@
         if len(method.returns) == 0:
             return "void"
         elif len(method.returns) == 1:
-            return method.returns[0].typeName
+            return method.returns[0].cppTypeName
         else:
             return "std::tuple<" + \
                    returns_as_list() + \
@@ -20,16 +20,16 @@
         return ", ".join([ p.camelCase for p in method.parameters ])
 
     def parameters_types_as_list():
-        return ", ".join([ p.typeName for p in method.parameters ])
+        return ", ".join([ p.cppTypeName for p in method.parameters ])
 
     def parameter(p, defaultValue=False):
-        r = "%s %s" % (p.typeName, p.camelCase)
+        r = "%s %s" % (p.cppTypeName, p.camelCase)
         if defaultValue:
             r += default_value(p)
         return r
 
     def returns_as_list():
-        return ", ".join([ r.typeName for r in method.returns ])
+        return ", ".join([ r.cppTypeName for r in method.returns ])
 
     def returns_as_tuple_index(tuple):
         return ", ".join([ "std::move(std::get<%d>(%s))" % (i,tuple) \
@@ -73,7 +73,7 @@
     % if len(method.returns) != 0:
          *
         % for r in method.returns:
-         *  @return ${r.camelCase}[${r.typeName}] - ${r.description.strip()}
+         *  @return ${r.camelCase}[${r.cppTypeName}] - ${r.description.strip()}
         % endfor
     % endif
          */
diff --git a/tools/sdbusplus/templates/signal.mako.prototype.hpp b/tools/sdbusplus/templates/signal.mako.prototype.hpp
index 8dfaf81..7050ec3 100644
--- a/tools/sdbusplus/templates/signal.mako.prototype.hpp
+++ b/tools/sdbusplus/templates/signal.mako.prototype.hpp
@@ -4,7 +4,7 @@
             join([ parameter(p, defaultValue) for p in signal.properties ])
 
     def parameter(p, defaultValue=False):
-        r = "%s %s" % (p.typeName, p.camelCase)
+        r = "%s %s" % (p.cppTypeName, p.camelCase)
         if defaultValue:
             r += default_value(p)
         return r
@@ -13,7 +13,7 @@
         return ", ".join([ p.camelCase for p in signal.properties ])
 
     def parameters_types_as_list():
-        return ", ".join([ p.typeName for p in signal.properties ])
+        return ", ".join([ p.cppTypeName for p in signal.properties ])
 
     def default_value(p):
         if p.defaultValue != None: