| Index: tools/json_schema_compiler/cpp_type_generator.py
|
| diff --git a/tools/json_schema_compiler/cpp_type_generator.py b/tools/json_schema_compiler/cpp_type_generator.py
|
| index 296eb41440bbab0799a11a91d96a647337f915b9..f15bae86e468a4444367f18ee18b9ed26cde7643 100644
|
| --- a/tools/json_schema_compiler/cpp_type_generator.py
|
| +++ b/tools/json_schema_compiler/cpp_type_generator.py
|
| @@ -5,9 +5,22 @@
|
| from code import Code
|
| from model import Namespace, PropertyType, Type
|
| import cpp_util
|
| -import operator
|
| +from json_parse import OrderedDict
|
| +from operator import attrgetter
|
| import schema_util
|
|
|
| +class _TypeDependency(object):
|
| + """Contains information about a dependency a namespace has on a type: the
|
| + type's model, and whether that dependency is "hard" meaning that it cannot be
|
| + forward declared.
|
| + """
|
| + def __init__(self, type_, hard=False):
|
| + self.type_ = type_
|
| + self.hard = hard
|
| +
|
| + def GetSortKey(self):
|
| + return '%s.%s' % (self.type_.namespace.name, self.type_.name)
|
| +
|
| class CppTypeGenerator(object):
|
| """Manages the types of properties and provides utilities for getting the
|
| C++ type out of a model.Property
|
| @@ -102,15 +115,13 @@ class CppTypeGenerator(object):
|
| """
|
| cpp_type = None
|
| if type_.property_type == PropertyType.REF:
|
| - ref = type_.ref_type
|
| - dependency_namespace = self._ResolveTypeNamespace(ref)
|
| - if not dependency_namespace:
|
| - raise KeyError('Cannot find referenced type: %s' % ref)
|
| - if self._namespace != dependency_namespace:
|
| - cpp_type = '%s::%s' % (self._cpp_namespaces[dependency_namespace],
|
| - schema_util.StripSchemaNamespace(ref))
|
| + ref_type = self._FindType(type_.ref_type)
|
| + if ref_type is None:
|
| + raise KeyError('Cannot find referenced type: %s' % type_.ref_type)
|
| + if self._namespace is ref_type.namespace:
|
| + cpp_type = ref_type.name
|
| else:
|
| - cpp_type = schema_util.StripSchemaNamespace(ref)
|
| + cpp_type = '%s::%s' % (ref_type.namespace.name, ref_type.name)
|
| elif type_.property_type == PropertyType.BOOLEAN:
|
| cpp_type = 'bool'
|
| elif type_.property_type == PropertyType.INTEGER:
|
| @@ -165,49 +176,40 @@ class CppTypeGenerator(object):
|
| self._root_namespace.
|
| """
|
| c = Code()
|
| - namespace_type_dependencies = self._NamespaceTypeDependencies()
|
| - for namespace in sorted(namespace_type_dependencies.keys(),
|
| - key=operator.attrgetter('name')):
|
| +
|
| + for namespace, dependencies in self._NamespaceTypeDependencies().items():
|
| c.Append('namespace %s {' % namespace.name)
|
| - for type_name in sorted(namespace_type_dependencies[namespace],
|
| - key=schema_util.StripSchemaNamespace):
|
| - simple_type_name = schema_util.StripSchemaNamespace(type_name)
|
| - type_ = namespace.types[simple_type_name]
|
| + for dependency in dependencies:
|
| + # No point forward-declaring hard dependencies.
|
| + if dependency.hard:
|
| + continue
|
| # Add more ways to forward declare things as necessary.
|
| - if type_.property_type == PropertyType.OBJECT:
|
| - c.Append('struct %s;' % simple_type_name)
|
| + if dependency.type_.property_type == PropertyType.OBJECT:
|
| + c.Append('struct %s;' % dependency.type_.name)
|
| c.Append('}')
|
| - c.Concat(self.GetNamespaceStart())
|
| - for (name, type_) in self._namespace.types.items():
|
| - if not type_.functions and type_.property_type == PropertyType.OBJECT:
|
| - c.Append('struct %s;' % schema_util.StripSchemaNamespace(name))
|
| - c.Concat(self.GetNamespaceEnd())
|
| +
|
| return c
|
|
|
| - def GenerateIncludes(self):
|
| + def GenerateIncludes(self, include_soft=False):
|
| """Returns the #include lines for self._namespace.
|
| """
|
| c = Code()
|
| - for header in sorted(
|
| - ['%s/%s.h' % (dependency.source_file_dir,
|
| - self._cpp_namespaces[dependency])
|
| - for dependency in self._NamespaceTypeDependencies().keys()]):
|
| - c.Append('#include "%s"' % header)
|
| - c.Append('#include "base/string_number_conversions.h"')
|
| -
|
| - if self._namespace.events:
|
| - c.Append('#include "base/json/json_writer.h"')
|
| + for namespace, dependencies in self._NamespaceTypeDependencies().items():
|
| + for dependency in dependencies:
|
| + if dependency.hard or include_soft:
|
| + c.Append('#include "%s/%s.h"' % (namespace.source_file_dir,
|
| + namespace.unix_name))
|
| return c
|
|
|
| - def _ResolveTypeNamespace(self, qualified_name):
|
| - """Resolves a type, which must be explicitly qualified, to its enclosing
|
| - namespace.
|
| + def _FindType(self, full_name):
|
| + """Finds the model.Type with name |qualified_name|. If it's not from
|
| + |self._namespace| then it needs to be qualified.
|
| """
|
| - namespace = self._type_namespaces.get(qualified_name, None)
|
| + namespace = self._type_namespaces.get(full_name, None)
|
| if namespace is None:
|
| raise KeyError('Cannot resolve type %s. Maybe it needs a prefix '
|
| - 'if it comes from another namespace?' % qualified_type)
|
| - return namespace
|
| + 'if it comes from another namespace?' % full_name)
|
| + return namespace.types[schema_util.StripNamespace(full_name)]
|
|
|
| def FollowRef(self, type_):
|
| """Follows $ref link of types to resolve the concrete type a ref refers to.
|
| @@ -215,54 +217,64 @@ class CppTypeGenerator(object):
|
| If the property passed in is not of type PropertyType.REF, it will be
|
| returned unchanged.
|
| """
|
| - if not type_.property_type == PropertyType.REF:
|
| + if type_.property_type != PropertyType.REF:
|
| return type_
|
| - ref = type_.ref_type
|
| -
|
| - without_namespace = ref
|
| - if '.' in ref:
|
| - without_namespace = ref.split('.', 1)[1]
|
| -
|
| - # TODO(kalman): Do we need to keep on resolving?
|
| - return self._ResolveTypeNamespace(ref).types[without_namespace]
|
| + return self.FollowRef(self._FindType(type_.ref_type))
|
|
|
| def _NamespaceTypeDependencies(self):
|
| - """Returns a dict containing a mapping of model.Namespace to the C++ type
|
| - of type dependencies for self._namespace.
|
| + """Returns a dict ordered by namespace name containing a mapping of
|
| + model.Namespace to every _TypeDependency for |self._namespace|, sorted
|
| + by the type's name.
|
| """
|
| dependencies = set()
|
| for function in self._namespace.functions.values():
|
| for param in function.params:
|
| - dependencies |= self._TypeDependencies(param.type_)
|
| + dependencies |= self._TypeDependencies(param.type_,
|
| + hard=not param.optional)
|
| if function.callback:
|
| for param in function.callback.params:
|
| - dependencies |= self._TypeDependencies(param.type_)
|
| + dependencies |= self._TypeDependencies(param.type_,
|
| + hard=not param.optional)
|
| for type_ in self._namespace.types.values():
|
| for prop in type_.properties.values():
|
| - dependencies |= self._TypeDependencies(prop.type_)
|
| + dependencies |= self._TypeDependencies(prop.type_,
|
| + hard=not prop.optional)
|
| for event in self._namespace.events.values():
|
| for param in event.params:
|
| - dependencies |= self._TypeDependencies(param.type_)
|
| -
|
| - dependency_namespaces = dict()
|
| - for dependency in dependencies:
|
| - namespace = self._ResolveTypeNamespace(dependency)
|
| - if namespace != self._namespace:
|
| - dependency_namespaces.setdefault(namespace, [])
|
| - dependency_namespaces[namespace].append(dependency)
|
| + dependencies |= self._TypeDependencies(param.type_,
|
| + hard=not param.optional)
|
| +
|
| + # Make sure that the dependencies are returned in alphabetical order.
|
| + dependency_namespaces = OrderedDict()
|
| + for dependency in sorted(dependencies, key=_TypeDependency.GetSortKey):
|
| + namespace = dependency.type_.namespace
|
| + if namespace is self._namespace:
|
| + continue
|
| + if namespace not in dependency_namespaces:
|
| + dependency_namespaces[namespace] = []
|
| + dependency_namespaces[namespace].append(dependency)
|
| +
|
| return dependency_namespaces
|
|
|
| - def _TypeDependencies(self, type_):
|
| - """Recursively gets all the type dependencies of a property.
|
| + def _TypeDependencies(self, type_, hard=False):
|
| + """Gets all the type dependencies of a property.
|
| """
|
| deps = set()
|
| if type_.property_type == PropertyType.REF:
|
| - deps.add(type_.ref_type)
|
| + deps.add(_TypeDependency(self._FindType(type_.ref_type), hard=hard))
|
| elif type_.property_type == PropertyType.ARRAY:
|
| - deps = self._TypeDependencies(type_.item_type)
|
| + # Non-copyable types are not hard because they are wrapped in linked_ptrs
|
| + # when generated. Otherwise they're typedefs, so they're hard (though we
|
| + # could generate those typedefs in every dependent namespace, but that
|
| + # seems weird).
|
| + deps = self._TypeDependencies(type_.item_type,
|
| + hard=self.IsCopyable(type_.item_type))
|
| + elif type_.property_type == PropertyType.CHOICES:
|
| + for type_ in type_.choices:
|
| + deps |= self._TypeDependencies(type_, hard=self.IsCopyable(type_))
|
| elif type_.property_type == PropertyType.OBJECT:
|
| for p in type_.properties.values():
|
| - deps |= self._TypeDependencies(p.type_)
|
| + deps |= self._TypeDependencies(p.type_, hard=not p.optional)
|
| return deps
|
|
|
| def GeneratePropertyValues(self, property, line, nodoc=False):
|
|
|