cpp_type_generator.py revision 5821806d5e7f356e8fa4b058a389a808ea183019
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
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from model import PropertyType
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import any_helper
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import cpp_util
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import operator
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import schema_util
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CppTypeGenerator(object):
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Manages the types of properties and provides utilities for getting the
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  C++ type out of a model.Property
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, root_namespace, namespace=None, cpp_namespace=None):
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Creates a cpp_type_generator. The given root_namespace should be of the
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    format extensions::api::sub. The generator will generate code suitable for
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    use in the given namespace.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._type_namespaces = {}
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._root_namespace = root_namespace.split('::')
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._cpp_namespaces = {}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if namespace and cpp_namespace:
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._namespace = namespace
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.AddNamespace(namespace, cpp_namespace)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AddNamespace(self, namespace, cpp_namespace):
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Maps a model.Namespace to its C++ namespace name. All mappings are
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    beneath the root namespace.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for type_ in namespace.types:
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if type_ in self._type_namespaces:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise ValueError('Type %s is declared in both %s and %s' %
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (type_, namespace.name, self._type_namespaces[type_].name))
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._type_namespaces[type_] = namespace
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._cpp_namespaces[namespace] = cpp_namespace
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExpandParams(self, params):
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the given parameters with PropertyType.CHOICES parameters
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    expanded so that each choice is a separate parameter.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    expanded = []
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for param in params:
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if param.type_ == PropertyType.CHOICES:
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for choice in param.choices.values():
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          expanded.append(choice)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        expanded.append(param)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return expanded
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetAllPossibleParameterLists(self, params):
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns all possible parameter lists for the given set of parameters.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Every combination of arguments passed to any of the PropertyType.CHOICES
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parameters will have a corresponding parameter list returned here.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not params:
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return [[]]
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    partial_parameter_lists = self.GetAllPossibleParameterLists(params[1:])
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return [[param] + partial_list
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            for param in self.ExpandParams(params[:1])
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            for partial_list in partial_parameter_lists]
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetCppNamespaceName(self, namespace):
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the mapped C++ namespace name for the given namespace relative to
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the root namespace.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._cpp_namespaces[namespace]
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetRootNamespaceStart(self):
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get opening root namespace declarations.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = Code()
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for namespace in self._root_namespace:
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Append('namespace %s {' % namespace)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return c
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetRootNamespaceEnd(self):
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get closing root namespace declarations.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = Code()
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for namespace in reversed(self._root_namespace):
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Append('}  // %s' % namespace)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return c
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNamespaceStart(self):
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get opening self._namespace namespace declaration.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Code().Append('namespace %s {' %
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.GetCppNamespaceName(self._namespace))
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNamespaceEnd(self):
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get closing self._namespace namespace declaration.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Code().Append('}  // %s' %
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.GetCppNamespaceName(self._namespace))
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetEnumNoneValue(self, prop):
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the enum value in the given model.Property indicating no value has
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    been set.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '%s_NONE' % self.GetReferencedProperty(prop).unix_name.upper()
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetEnumValue(self, prop, enum_value):
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the enum value of the given model.Property of the given type.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    e.g VAR_STRING
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '%s_%s' % (self.GetReferencedProperty(prop).unix_name.upper(),
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      cpp_util.Classname(enum_value.upper()))
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetChoicesEnumType(self, prop):
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the type of the enum for the given model.Property.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    e.g VarType
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return cpp_util.Classname(prop.name) + 'Type'
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetType(self, prop, pad_for_generics=False, wrap_optional=False):
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetTypeHelper(prop, pad_for_generics, wrap_optional)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetCompiledType(self, prop, pad_for_generics=False, wrap_optional=False):
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetTypeHelper(prop, pad_for_generics, wrap_optional,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               use_compiled_type=True)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetTypeHelper(self, prop, pad_for_generics=False, wrap_optional=False,
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     use_compiled_type=False):
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Translates a model.Property into its C++ type.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If REF types from different namespaces are referenced, will resolve
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    using self._type_namespaces.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Use pad_for_generics when using as a generic to avoid operator ambiguity.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Use wrap_optional to wrap the type in a scoped_ptr<T> if the Property is
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    optional.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Use use_compiled_type when converting from prop.type_ to prop.compiled_type.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cpp_type = None
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    type_ = prop.type_ if not use_compiled_type else prop.compiled_type
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if type_ == PropertyType.REF:
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dependency_namespace = self._ResolveTypeNamespace(prop.ref_type)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not dependency_namespace:
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise KeyError('Cannot find referenced type: %s' % prop.ref_type)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._namespace != dependency_namespace:
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cpp_type = '%s::%s' % (self._cpp_namespaces[dependency_namespace],
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            schema_util.StripSchemaNamespace(prop.ref_type))
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cpp_type = schema_util.StripSchemaNamespace(prop.ref_type)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.BOOLEAN:
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'bool'
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.INTEGER:
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'int'
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.INT64:
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'int64'
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.DOUBLE:
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'double'
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.STRING:
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'std::string'
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.ENUM:
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = cpp_util.Classname(prop.name)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.ADDITIONAL_PROPERTIES:
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'base::DictionaryValue'
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.ANY:
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = any_helper.ANY_CLASS
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.OBJECT:
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = cpp_util.Classname(prop.name)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.FUNCTION:
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Functions come into the json schema compiler as empty objects. We can
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # record these as empty DictionaryValue's so that we know if the function
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # was passed in or not.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'base::DictionaryValue'
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.ARRAY:
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      item_type = prop.item_type
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if item_type.type_ == PropertyType.REF:
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        item_type = self.GetReferencedProperty(item_type)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if item_type.type_ in (
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          PropertyType.REF, PropertyType.ANY, PropertyType.OBJECT):
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cpp_type = 'std::vector<linked_ptr<%s> > '
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cpp_type = 'std::vector<%s> '
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = cpp_type % self.GetType(
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          prop.item_type, pad_for_generics=True)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.BINARY:
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'std::string'
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise NotImplementedError(type_)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Enums aren't wrapped because C++ won't allow it. Optional enums have a
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # NONE value generated instead.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if wrap_optional and prop.optional and not self.IsEnumOrEnumRef(prop):
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'scoped_ptr<%s> ' % cpp_type
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if pad_for_generics:
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return cpp_type
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return cpp_type.strip()
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GenerateForwardDeclarations(self):
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the forward declarations for self._namespace.
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Use after GetRootNamespaceStart. Assumes all namespaces are relative to
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._root_namespace.
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = Code()
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    namespace_type_dependencies = self._NamespaceTypeDependencies()
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for namespace in sorted(namespace_type_dependencies.keys(),
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            key=operator.attrgetter('name')):
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Append('namespace %s {' % namespace.name)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for type_ in sorted(namespace_type_dependencies[namespace],
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          key=schema_util.StripSchemaNamespace):
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        type_name = schema_util.StripSchemaNamespace(type_)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if namespace.types[type_].type_ == PropertyType.STRING:
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          c.Append('typedef std::string %s;' % type_name)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elif namespace.types[type_].type_ == PropertyType.ARRAY:
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          c.Append('typedef std::vector<%(item_type)s> %(name)s;')
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          c.Substitute({
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'name': type_name,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'item_type': self.GetType(namespace.types[type_].item_type,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      wrap_optional=True)})
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Enums cannot be forward declared.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elif namespace.types[type_].type_ != PropertyType.ENUM:
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          c.Append('struct %s;' % type_name)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Append('}')
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c.Concat(self.GetNamespaceStart())
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (name, type_) in self._namespace.types.items():
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not type_.functions and type_.type_ == PropertyType.OBJECT:
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        c.Append('struct %s;' % schema_util.StripSchemaNamespace(name))
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c.Concat(self.GetNamespaceEnd())
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return c
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GenerateIncludes(self):
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the #include lines for self._namespace.
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = Code()
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for header in sorted(
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ['%s/%s.h' % (dependency.source_file_dir,
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      self._cpp_namespaces[dependency])
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         for dependency in self._NamespaceTypeDependencies().keys()]):
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Append('#include "%s"' % header)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c.Append('#include "base/string_number_conversions.h"')
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._namespace.events:
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Append('#include "base/json/json_writer.h"')
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return c
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _ResolveTypeNamespace(self, ref_type):
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Resolves a type, which must be explicitly qualified, to its enclosing
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    namespace.
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ref_type in self._type_namespaces:
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self._type_namespaces[ref_type]
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise KeyError('Cannot resolve type: %s. Maybe it needs a namespace prefix '
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   'if it comes from another namespace?' % ref_type)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetReferencedProperty(self, prop):
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the property a property of type REF is referring to.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If the property passed in is not of type PropertyType.REF, it will be
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    returned unchanged.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if prop.type_ != PropertyType.REF:
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return prop
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._ResolveTypeNamespace(prop.ref_type).types.get(prop.ref_type,
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        None)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsEnumOrEnumRef(self, prop):
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns true if the property is an ENUM or a reference to an ENUM.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.GetReferencedProperty(prop).type_ == PropertyType.ENUM
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsEnumRef(self, prop):
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns true if the property is a reference to an ENUM.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (prop.type_ == PropertyType.REF and
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self.GetReferencedProperty(prop).type_ == PropertyType.ENUM)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _NamespaceTypeDependencies(self):
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns a dict containing a mapping of model.Namespace to the C++ type
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    of type dependencies for self._namespace.
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dependencies = set()
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for function in self._namespace.functions.values():
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for param in function.params:
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dependencies |= self._PropertyTypeDependencies(param)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if function.callback:
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for param in function.callback.params:
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          dependencies |= self._PropertyTypeDependencies(param)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for type_ in self._namespace.types.values():
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for prop in type_.properties.values():
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dependencies |= self._PropertyTypeDependencies(prop)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for event in self._namespace.events.values():
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for param in event.params:
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dependencies |= self._PropertyTypeDependencies(param)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dependency_namespaces = dict()
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for dependency in dependencies:
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      namespace = self._ResolveTypeNamespace(dependency)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if namespace != self._namespace:
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dependency_namespaces.setdefault(namespace, [])
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dependency_namespaces[namespace].append(dependency)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return dependency_namespaces
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _PropertyTypeDependencies(self, prop):
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Recursively gets all the type dependencies of a property.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    deps = set()
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if prop:
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if prop.type_ == PropertyType.REF:
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        deps.add(prop.ref_type)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif prop.type_ == PropertyType.ARRAY:
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        deps = self._PropertyTypeDependencies(prop.item_type)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif prop.type_ == PropertyType.OBJECT:
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for p in prop.properties.values():
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          deps |= self._PropertyTypeDependencies(p)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return deps
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GeneratePropertyValues(self, property, line, nodoc=False):
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Generates the Code to display all value-containing properties.
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = Code()
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not nodoc:
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Comment(property.description)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if property.has_value:
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Append(line % {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "type": self._GetPrimitiveType(property.type_),
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "name": property.name,
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "value": property.value
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        })
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_child_code = False
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Sblock('namespace %s {' % property.name)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for child_property in property.properties.values():
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        child_code = self.GeneratePropertyValues(
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            child_property,
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            line,
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            nodoc=nodoc)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if child_code:
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          has_child_code = True
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          c.Concat(child_code)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Eblock('}  // namespace %s' % property.name)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not has_child_code:
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        c = None
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return c
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetPrimitiveType(self, type_):
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Like |GetType| but only accepts and returns C++ primitive types.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if type_ == PropertyType.BOOLEAN:
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 'bool'
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.INTEGER:
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 'int'
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.DOUBLE:
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 'double'
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type_ == PropertyType.STRING:
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 'char*'
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise Exception(type_ + ' is not primitive')
360