Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(590)

Unified Diff: third_party/chrome/tools/cpp_type_generator.py

Issue 12261015: Import chrome idl into third_party (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/chrome/tools/compiler.py ('k') | third_party/chrome/tools/cpp_type_generator_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/chrome/tools/cpp_type_generator.py
diff --git a/third_party/chrome/tools/cpp_type_generator.py b/third_party/chrome/tools/cpp_type_generator.py
new file mode 100644
index 0000000000000000000000000000000000000000..f15bae86e468a4444367f18ee18b9ed26cde7643
--- /dev/null
+++ b/third_party/chrome/tools/cpp_type_generator.py
@@ -0,0 +1,306 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from code import Code
+from model import Namespace, PropertyType, Type
+import cpp_util
+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
+ """
+ def __init__(self, root_namespace, namespace=None, cpp_namespace=None):
+ """Creates a cpp_type_generator. The given root_namespace should be of the
+ format extensions::api::sub. The generator will generate code suitable for
+ use in the given namespace.
+ """
+ self._type_namespaces = {}
+ self._root_namespace = root_namespace.split('::')
+ self._cpp_namespaces = {}
+ if namespace and cpp_namespace:
+ self._namespace = namespace
+ self.AddNamespace(namespace, cpp_namespace)
+ else:
+ self._namespace = None
+
+ def AddNamespace(self, namespace, cpp_namespace):
+ """Maps a model.Namespace to its C++ namespace name. All mappings are
+ beneath the root namespace.
+ """
+ self._cpp_namespaces[namespace] = cpp_namespace
+ for type_name in namespace.types:
+ # Allow $refs to refer to just 'Type' within namespaces. Otherwise they
+ # must be qualified with 'namespace.Type'.
+ type_aliases = ['%s.%s' % (namespace.name, type_name)]
+ if namespace is self._namespace:
+ type_aliases.append(type_name)
+ for alias in type_aliases:
+ self._type_namespaces[alias] = namespace
+
+ def GetCppNamespaceName(self, namespace):
+ """Gets the mapped C++ namespace name for the given namespace relative to
+ the root namespace.
+ """
+ return self._cpp_namespaces[namespace]
+
+ def GetRootNamespaceStart(self):
+ """Get opening root namespace declarations.
+ """
+ c = Code()
+ for namespace in self._root_namespace:
+ c.Append('namespace %s {' % namespace)
+ return c
+
+ def GetRootNamespaceEnd(self):
+ """Get closing root namespace declarations.
+ """
+ c = Code()
+ for namespace in reversed(self._root_namespace):
+ c.Append('} // %s' % namespace)
+ return c
+
+ def GetNamespaceStart(self):
+ """Get opening self._namespace namespace declaration.
+ """
+ return Code().Append('namespace %s {' %
+ self.GetCppNamespaceName(self._namespace))
+
+ def GetNamespaceEnd(self):
+ """Get closing self._namespace namespace declaration.
+ """
+ return Code().Append('} // %s' %
+ self.GetCppNamespaceName(self._namespace))
+
+ def GetEnumNoneValue(self, type_):
+ """Gets the enum value in the given model.Property indicating no value has
+ been set.
+ """
+ return '%s_NONE' % self.FollowRef(type_).unix_name.upper()
+
+ def GetEnumValue(self, type_, enum_value):
+ """Gets the enum value of the given model.Property of the given type.
+
+ e.g VAR_STRING
+ """
+ return '%s_%s' % (self.FollowRef(type_).unix_name.upper(),
+ cpp_util.Classname(enum_value.upper()))
+
+ def GetCppType(self, type_, is_ptr=False, is_in_container=False):
+ """Translates a model.Property or model.Type into its C++ type.
+
+ If REF types from different namespaces are referenced, will resolve
+ using self._type_namespaces.
+
+ Use |is_ptr| if the type is optional. This will wrap the type in a
+ scoped_ptr if possible (it is not possible to wrap an enum).
+
+ Use |is_in_container| if the type is appearing in a collection, e.g. a
+ std::vector or std::map. This will wrap it in the correct type with spacing.
+ """
+ cpp_type = None
+ if type_.property_type == PropertyType.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 = '%s::%s' % (ref_type.namespace.name, ref_type.name)
+ elif type_.property_type == PropertyType.BOOLEAN:
+ cpp_type = 'bool'
+ elif type_.property_type == PropertyType.INTEGER:
+ cpp_type = 'int'
+ elif type_.property_type == PropertyType.INT64:
+ cpp_type = 'int64'
+ elif type_.property_type == PropertyType.DOUBLE:
+ cpp_type = 'double'
+ elif type_.property_type == PropertyType.STRING:
+ cpp_type = 'std::string'
+ elif type_.property_type == PropertyType.ENUM:
+ cpp_type = cpp_util.Classname(type_.name)
+ elif type_.property_type == PropertyType.ANY:
+ cpp_type = 'base::Value'
+ elif (type_.property_type == PropertyType.OBJECT or
+ type_.property_type == PropertyType.CHOICES):
+ cpp_type = cpp_util.Classname(type_.name)
+ elif type_.property_type == PropertyType.FUNCTION:
+ # Functions come into the json schema compiler as empty objects. We can
+ # record these as empty DictionaryValues so that we know if the function
+ # was passed in or not.
+ cpp_type = 'base::DictionaryValue'
+ elif type_.property_type == PropertyType.ARRAY:
+ item_cpp_type = self.GetCppType(type_.item_type, is_in_container=True)
+ cpp_type = 'std::vector<%s>' % cpp_util.PadForGenerics(item_cpp_type)
+ elif type_.property_type == PropertyType.BINARY:
+ cpp_type = 'std::string'
+ else:
+ raise NotImplementedError('Cannot get type of %s' % type_.property_type)
+
+ # HACK: optional ENUM is represented elsewhere with a _NONE value, so it
+ # never needs to be wrapped in pointer shenanigans.
+ # TODO(kalman): change this - but it's an exceedingly far-reaching change.
+ if not self.FollowRef(type_).property_type == PropertyType.ENUM:
+ if is_in_container and (is_ptr or not self.IsCopyable(type_)):
+ cpp_type = 'linked_ptr<%s>' % cpp_util.PadForGenerics(cpp_type)
+ elif is_ptr:
+ cpp_type = 'scoped_ptr<%s>' % cpp_util.PadForGenerics(cpp_type)
+
+ return cpp_type
+
+ def IsCopyable(self, type_):
+ return not (self.FollowRef(type_).property_type in (PropertyType.ANY,
+ PropertyType.ARRAY,
+ PropertyType.OBJECT,
+ PropertyType.CHOICES))
+
+ def GenerateForwardDeclarations(self):
+ """Returns the forward declarations for self._namespace.
+
+ Use after GetRootNamespaceStart. Assumes all namespaces are relative to
+ self._root_namespace.
+ """
+ c = Code()
+
+ for namespace, dependencies in self._NamespaceTypeDependencies().items():
+ c.Append('namespace %s {' % namespace.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 dependency.type_.property_type == PropertyType.OBJECT:
+ c.Append('struct %s;' % dependency.type_.name)
+ c.Append('}')
+
+ return c
+
+ def GenerateIncludes(self, include_soft=False):
+ """Returns the #include lines for self._namespace.
+ """
+ c = Code()
+ 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 _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(full_name, None)
+ if namespace is None:
+ raise KeyError('Cannot resolve type %s. Maybe it needs a prefix '
+ '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.
+
+ If the property passed in is not of type PropertyType.REF, it will be
+ returned unchanged.
+ """
+ if type_.property_type != PropertyType.REF:
+ return type_
+ return self.FollowRef(self._FindType(type_.ref_type))
+
+ def _NamespaceTypeDependencies(self):
+ """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_,
+ hard=not param.optional)
+ if function.callback:
+ for param in function.callback.params:
+ 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_,
+ hard=not prop.optional)
+ for event in self._namespace.events.values():
+ for param in event.params:
+ 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_, hard=False):
+ """Gets all the type dependencies of a property.
+ """
+ deps = set()
+ if type_.property_type == PropertyType.REF:
+ deps.add(_TypeDependency(self._FindType(type_.ref_type), hard=hard))
+ elif type_.property_type == PropertyType.ARRAY:
+ # 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_, hard=not p.optional)
+ return deps
+
+ def GeneratePropertyValues(self, property, line, nodoc=False):
+ """Generates the Code to display all value-containing properties.
+ """
+ c = Code()
+ if not nodoc:
+ c.Comment(property.description)
+
+ if property.value is not None:
+ c.Append(line % {
+ "type": self.GetCppType(property.type_),
+ "name": property.name,
+ "value": property.value
+ })
+ else:
+ has_child_code = False
+ c.Sblock('namespace %s {' % property.name)
+ for child_property in property.type_.properties.values():
+ child_code = self.GeneratePropertyValues(child_property,
+ line,
+ nodoc=nodoc)
+ if child_code:
+ has_child_code = True
+ c.Concat(child_code)
+ c.Eblock('} // namespace %s' % property.name)
+ if not has_child_code:
+ c = None
+ return c
« no previous file with comments | « third_party/chrome/tools/compiler.py ('k') | third_party/chrome/tools/cpp_type_generator_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698