cpp_type_generator.py revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from code import Code
658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)from model import PropertyType
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import cpp_util
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from json_parse import OrderedDict
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import schema_util
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class _TypeDependency(object):
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """Contains information about a dependency a namespace has on a type: the
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  type's model, and whether that dependency is "hard" meaning that it cannot be
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  forward declared.
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __init__(self, type_, hard=False):
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.type_ = type_
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.hard = hard
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetSortKey(self):
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return '%s.%s' % (self.type_.namespace.name, self.type_.name)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CppTypeGenerator(object):
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Manages the types of properties and provides utilities for getting the
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  C++ type out of a model.Property
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __init__(self, model, schema_loader, default_namespace=None):
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Creates a cpp_type_generator. The given root_namespace should be of the
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    format extensions::api::sub. The generator will generate code suitable for
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    use in the given model's namespace.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._default_namespace = default_namespace
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._default_namespace is None:
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._default_namespace = model.namespaces.values()[0]
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._schema_loader = schema_loader
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetCppNamespaceName(self, namespace):
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the mapped C++ namespace name for the given namespace relative to
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the root namespace.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return namespace.unix_name
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNamespaceStart(self):
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Get opening self._default_namespace namespace declaration.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Code().Append('namespace %s {' %
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.GetCppNamespaceName(self._default_namespace))
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNamespaceEnd(self):
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Get closing self._default_namespace namespace declaration.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Code().Append('}  // %s' %
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.GetCppNamespaceName(self._default_namespace))
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetEnumNoneValue(self, type_):
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the enum value in the given model.Property indicating no value has
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    been set.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return '%s_NONE' % self.FollowRef(type_).unix_name.upper()
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def GetEnumLastValue(self, type_):
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """Gets the enum value in the given model.Property indicating the last value
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for the type.
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return '%s_LAST' % self.FollowRef(type_).unix_name.upper()
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetEnumValue(self, type_, enum_value):
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the enum value of the given model.Property of the given type.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    e.g VAR_STRING
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    value = cpp_util.Classname(enum_value.name.upper())
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not type_.cpp_omit_enum_type:
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      value = '%s_%s' % (self.FollowRef(type_).unix_name.upper(), value)
76b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    # To avoid collisions with built-in OS_* preprocessor definitions, we add a
77b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    # trailing slash to enum names that start with OS_.
78b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if value.startswith("OS_"):
79b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      value += "_"
80b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return value
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetCppType(self, type_, is_ptr=False, is_in_container=False):
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Translates a model.Property or model.Type into its C++ type.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If REF types from different namespaces are referenced, will resolve
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    using self._schema_loader.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Use |is_ptr| if the type is optional. This will wrap the type in a
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr if possible (it is not possible to wrap an enum).
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Use |is_in_container| if the type is appearing in a collection, e.g. a
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector or std::map. This will wrap it in the correct type with spacing.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cpp_type = None
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type == PropertyType.REF:
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ref_type = self._FindType(type_.ref_type)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if ref_type is None:
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        raise KeyError('Cannot find referenced type: %s' % type_.ref_type)
99c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      cpp_type = self.GetCppType(ref_type)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.BOOLEAN:
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'bool'
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.INTEGER:
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'int'
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.INT64:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'int64'
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.DOUBLE:
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'double'
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.STRING:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'std::string'
110c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    elif type_.property_type in (PropertyType.ENUM,
111c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                 PropertyType.OBJECT,
112c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                 PropertyType.CHOICES):
113c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if self._default_namespace is type_.namespace:
114c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        cpp_type = cpp_util.Classname(type_.name)
115c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      else:
116c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        cpp_type = '%s::%s' % (type_.namespace.unix_name,
117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                               cpp_util.Classname(type_.name))
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.ANY:
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cpp_type = 'base::Value'
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.FUNCTION:
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Functions come into the json schema compiler as empty objects. We can
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # record these as empty DictionaryValues so that we know if the function
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # was passed in or not.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'base::DictionaryValue'
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.ARRAY:
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item_cpp_type = self.GetCppType(type_.item_type, is_in_container=True)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cpp_type = 'std::vector<%s>' % cpp_util.PadForGenerics(item_cpp_type)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.BINARY:
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'std::string'
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise NotImplementedError('Cannot get type of %s' % type_.property_type)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # HACK: optional ENUM is represented elsewhere with a _NONE value, so it
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # never needs to be wrapped in pointer shenanigans.
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # TODO(kalman): change this - but it's an exceedingly far-reaching change.
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not self.FollowRef(type_).property_type == PropertyType.ENUM:
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if is_in_container and (is_ptr or not self.IsCopyable(type_)):
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        cpp_type = 'linked_ptr<%s>' % cpp_util.PadForGenerics(cpp_type)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      elif is_ptr:
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        cpp_type = 'scoped_ptr<%s>' % cpp_util.PadForGenerics(cpp_type)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return cpp_type
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def IsCopyable(self, type_):
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return not (self.FollowRef(type_).property_type in (PropertyType.ANY,
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                        PropertyType.ARRAY,
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                        PropertyType.OBJECT,
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                        PropertyType.CHOICES))
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GenerateForwardDeclarations(self):
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Returns the forward declarations for self._default_namespace.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = Code()
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for namespace, dependencies in self._NamespaceTypeDependencies().items():
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Append('namespace %s {' % namespace.unix_name)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for dependency in dependencies:
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # No point forward-declaring hard dependencies.
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if dependency.hard:
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          continue
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # Add more ways to forward declare things as necessary.
1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if dependency.type_.property_type in (PropertyType.CHOICES,
1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                              PropertyType.OBJECT):
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          c.Append('struct %s;' % dependency.type_.name)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Append('}')
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return c
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GenerateIncludes(self, include_soft=False):
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Returns the #include lines for self._default_namespace.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = Code()
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for namespace, dependencies in self._NamespaceTypeDependencies().items():
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for dependency in dependencies:
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if dependency.hard or include_soft:
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          c.Append('#include "%s/%s.h"' % (namespace.source_file_dir,
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           namespace.unix_name))
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return c
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _FindType(self, full_name):
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Finds the model.Type with name |qualified_name|. If it's not from
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    |self._default_namespace| then it needs to be qualified.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    namespace = self._schema_loader.ResolveType(full_name,
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                self._default_namespace)
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if namespace is None:
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise KeyError('Cannot resolve type %s. Maybe it needs a prefix '
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     'if it comes from another namespace?' % full_name)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return namespace.types[schema_util.StripNamespace(full_name)]
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def FollowRef(self, type_):
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Follows $ref link of types to resolve the concrete type a ref refers to.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If the property passed in is not of type PropertyType.REF, it will be
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    returned unchanged.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type != PropertyType.REF:
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return type_
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self.FollowRef(self._FindType(type_.ref_type))
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _NamespaceTypeDependencies(self):
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Returns a dict ordered by namespace name containing a mapping of
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    model.Namespace to every _TypeDependency for |self._default_namespace|,
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sorted by the type's name.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dependencies = set()
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for function in self._default_namespace.functions.values():
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for param in function.params:
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        dependencies |= self._TypeDependencies(param.type_,
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               hard=not param.optional)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if function.callback:
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for param in function.callback.params:
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          dependencies |= self._TypeDependencies(param.type_,
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 hard=not param.optional)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for type_ in self._default_namespace.types.values():
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for prop in type_.properties.values():
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        dependencies |= self._TypeDependencies(prop.type_,
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               hard=not prop.optional)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for event in self._default_namespace.events.values():
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for param in event.params:
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        dependencies |= self._TypeDependencies(param.type_,
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               hard=not param.optional)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Make sure that the dependencies are returned in alphabetical order.
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dependency_namespaces = OrderedDict()
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for dependency in sorted(dependencies, key=_TypeDependency.GetSortKey):
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      namespace = dependency.type_.namespace
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if namespace is self._default_namespace:
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if namespace not in dependency_namespaces:
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        dependency_namespaces[namespace] = []
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dependency_namespaces[namespace].append(dependency)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return dependency_namespaces
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _TypeDependencies(self, type_, hard=False):
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Gets all the type dependencies of a property.
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    deps = set()
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type == PropertyType.REF:
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      deps.add(_TypeDependency(self._FindType(type_.ref_type), hard=hard))
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.ARRAY:
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # Non-copyable types are not hard because they are wrapped in linked_ptrs
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # when generated. Otherwise they're typedefs, so they're hard (though we
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # could generate those typedefs in every dependent namespace, but that
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # seems weird).
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      deps = self._TypeDependencies(type_.item_type,
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    hard=self.IsCopyable(type_.item_type))
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.CHOICES:
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for type_ in type_.choices:
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        deps |= self._TypeDependencies(type_, hard=self.IsCopyable(type_))
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.OBJECT:
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for p in type_.properties.values():
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        deps |= self._TypeDependencies(p.type_, hard=not p.optional)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return deps
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GeneratePropertyValues(self, property, line, nodoc=False):
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Generates the Code to display all value-containing properties.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = Code()
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not nodoc:
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Comment(property.description)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if property.value is not None:
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Append(line % {
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "type": self.GetCppType(property.type_),
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "name": property.name,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "value": property.value
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        })
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_child_code = False
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Sblock('namespace %s {' % property.name)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for child_property in property.type_.properties.values():
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        child_code = self.GeneratePropertyValues(child_property,
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 line,
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 nodoc=nodoc)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if child_code:
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          has_child_code = True
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          c.Concat(child_code)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Eblock('}  // namespace %s' % property.name)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not has_child_code:
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        c = None
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return c
284