def GenerateForwardDeclarations(self): """Returns the forward declarations for self._namespace. Use after GetRootNamespaceStart. Assumes all namespaces are relative to self._root_namespace. """ c = Code() namespace_type_dependencies = self._NamespaceTypeDependencies() for namespace in sorted(namespace_type_dependencies.keys(), key=lambda ns: ns.name): c.Append('namespace %s {' % namespace.name) for type_ in sorted(namespace_type_dependencies[namespace], key=schema_util.StripSchemaNamespace): type_name = schema_util.StripSchemaNamespace(type_) if namespace.types[type_].type_ == PropertyType.STRING: c.Append('typedef std::string %s;' % type_name) elif namespace.types[type_].type_ == PropertyType.ARRAY: c.Append('typedef std::vector<%(item_type)s> %(name)s;') c.Substitute({ 'name': type_name, 'item_type': self.GetType(namespace.types[type_].item_type, wrap_optional=True)}) else: c.Append('struct %s;' % type_name) c.Append('}') c.Concat(self.GetNamespaceStart()) for (name, type_) in self._namespace.types.items(): if not type_.functions and type_.type_ == PropertyType.OBJECT: c.Append('struct %s;' % schema_util.StripSchemaNamespace(name)) c.Concat(self.GetNamespaceEnd()) return c
def _GenerateEnumFromString(self, cpp_namespace, prop, use_namespace=False): """Generates FromClassNameString() which gets an enum from its string representation. """ c = Code() classname = cpp_util.Classname( schema_util.StripSchemaNamespace(prop.name)) if use_namespace: namespace = '%s::' % cpp_namespace else: namespace = '' (c.Append('// static').Sblock('%(namespace)s%(class)s' ' %(namespace)sFrom%(class)sString(' 'const std::string& enum_string) {')) enum_prop = self._cpp_type_generator.GetReferencedProperty(prop) for i, enum_value in enumerate( self._cpp_type_generator.GetReferencedProperty( prop).enum_values): # This is broken up into all ifs with no else ifs because we get # "fatal error C1061: compiler limit : blocks nested too deeply" # on Windows. (c.Append('if (enum_string == "%s")' % enum_value).Append( ' return %s;' % self._cpp_type_generator.GetEnumValue(prop, enum_value))) (c.Append('return %s;' % self._cpp_type_generator.GetEnumNoneValue(prop)).Eblock( '}').Substitute({ 'namespace': namespace, 'class': classname })) return c
def _GenerateEnumToString(self, cpp_namespace, prop, use_namespace=False): """Generates ToString() which gets the string representation of an enum. """ c = Code() classname = cpp_util.Classname( schema_util.StripSchemaNamespace(prop.name)) if use_namespace: namespace = '%s::' % cpp_namespace else: namespace = '' (c.Append('// static').Sblock( 'std::string %(namespace)sToString(%(class)s enum_param) {')) enum_prop = self._cpp_type_generator.GetReferencedProperty(prop) c.Sblock('switch (enum_param) {') for enum_value in enum_prop.enum_values: c.Concat( self._GenerateReturnCase( self._cpp_type_generator.GetEnumValue(prop, enum_value), '"%s"' % enum_value)) (c.Append('case %s:' % self._cpp_type_generator.GetEnumNoneValue(prop)).Append( ' return "";').Eblock('}').Append('return "";').Eblock( '}').Substitute({ 'namespace': namespace, 'class': classname })) return c
def _GenerateType(self, cpp_namespace, type_): """Generates the function definitions for a type. """ classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name)) c = Code() if type_.functions: for function in type_.functions.values(): (c.Concat( self._GenerateFunction( cpp_namespace + '::' + cpp_util.Classname(function.name), function)) .Append() ) elif type_.type_ == PropertyType.OBJECT: (c.Concat(self._GeneratePropertyFunctions( cpp_namespace, type_.properties.values())) .Sblock('%(namespace)s::%(classname)s()') .Concat(self._GenerateInitializersAndBody(type_)) .Eblock('%(namespace)s::~%(classname)s() {}') .Append() ) if type_.from_json: (c.Concat(self._GenerateTypePopulate(cpp_namespace, type_)) .Append() ) if type_.from_client: (c.Concat(self._GenerateTypeToValue(cpp_namespace, type_)) .Append() ) c.Substitute({'classname': classname, 'namespace': cpp_namespace}) return c
def _GenerateType(self, type_): """Generates a struct for a type. """ classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name)) c = Code() if type_.functions: c.Sblock('namespace %(classname)s {') for function in type_.functions.values(): (c.Concat(self._GenerateFunction(function)) .Append() ) c.Eblock('}') elif type_.type_ == PropertyType.ARRAY: if type_.description: c.Comment(type_.description) c.Append('typedef std::vector<%(item_type)s> %(classname)s;') c.Substitute({'classname': classname, 'item_type': self._cpp_type_generator.GetType(type_.item_type, wrap_optional=True)}) elif type_.type_ == PropertyType.STRING: if type_.description: c.Comment(type_.description) c.Append('typedef std::string %(classname)s;') c.Substitute({'classname': classname}) else: if type_.description: c.Comment(type_.description) (c.Sblock('struct %(classname)s {') .Append('~%(classname)s();') .Append('%(classname)s();') .Append() .Concat(self._GeneratePropertyStructures(type_.properties.values())) .Concat(self._GenerateFields(type_.properties.values())) ) if type_.from_json: (c.Comment('Populates a %s object from a Value. Returns' ' whether |out| was successfully populated.' % classname) .Append( 'static bool Populate(const Value& value, %(classname)s* out);') .Append() ) if type_.from_client: (c.Comment('Returns a new DictionaryValue representing the' ' serialized form of this %s object. Passes ' 'ownership to caller.' % classname) .Append('scoped_ptr<DictionaryValue> ToValue() const;') ) (c.Eblock() .Sblock(' private:') .Append('DISALLOW_COPY_AND_ASSIGN(%(classname)s);') .Eblock('};') ) c.Substitute({'classname': classname}) return c
def Generate(self): """Generates a Code object with the .cc for a single namespace. """ c = Code() (c.Append(cpp_util.CHROMIUM_LICENSE).Append().Append( cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file).Append().Append( self._util_cc_helper.GetIncludePath()).Append( '#include "%s/%s.h"' % (self._namespace.source_file_dir, self._namespace.unix_name))) includes = self._cpp_type_generator.GenerateIncludes() if not includes.IsEmpty(): (c.Concat(includes).Append()) (c.Append().Concat( self._cpp_type_generator.GetRootNamespaceStart()).Concat( self._cpp_type_generator.GetNamespaceStart()).Append()) if self._namespace.properties: (c.Append('//').Append('// Properties').Append('//').Append()) for property in self._namespace.properties.values(): property_code = self._cpp_type_generator.GeneratePropertyValues( property, 'const %(type)s %(name)s = %(value)s;', nodoc=True) if property_code: c.Concat(property_code).Append() if self._namespace.types: (c.Append('//').Append('// Types').Append('//').Append()) for type_ in self._namespace.types.values(): (c.Concat( self._GenerateType( schema_util.StripSchemaNamespace(type_.name), type_)).Append()) if self._namespace.functions: (c.Append('//').Append('// Functions').Append('//').Append()) for function in self._namespace.functions.values(): (c.Concat( self._GenerateFunction(cpp_util.Classname(function.name), function)).Append()) if self._namespace.events: (c.Append('//').Append('// Events').Append('//').Append()) for event in self._namespace.events.values(): (c.Concat( self._GenerateCreateCallbackArguments( cpp_util.Classname(event.name), event, generate_to_json=True)).Append()) (c.Concat(self._cpp_type_generator.GetNamespaceEnd()).Concat( self._cpp_type_generator.GetRootNamespaceEnd()).Append()) return c
def _GenerateCreateEnumTypeValue(self, cpp_namespace, prop): """Generates CreateEnumValue() that returns the base::StringValue representation of an enum type. """ c = Code() classname = cpp_util.Classname( schema_util.StripSchemaNamespace(prop.name)) (c.Sblock('scoped_ptr<base::Value> CreateEnumValue(%s %s) {' % (classname, classname.lower())).Append( 'std::string enum_temp = ToString(%s);' % classname.lower()).Append('if (enum_temp.empty())'). Append(' return scoped_ptr<base::Value>();').Append( 'return scoped_ptr<base::Value>(' 'base::Value::CreateStringValue(enum_temp));').Eblock('}')) return c
def Generate(self): """Generates a Code object with the .cc for a single namespace. """ c = Code() (c.Append(cpp_util.CHROMIUM_LICENSE).Append().Append( cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file).Append().Append( self._util_cc_helper.GetIncludePath()).Append( '#include "%s/%s.h"' % (self._namespace.source_file_dir, self._namespace.unix_name))) includes = self._cpp_type_generator.GenerateIncludes() if not includes.IsEmpty(): (c.Concat(includes).Append()) (c.Append().Append('using base::Value;').Append( 'using base::DictionaryValue;').Append('using base::ListValue;'). Append('using base::BinaryValue;').Append( 'using %s;' % any_helper.ANY_CLASS).Append().Concat( self._cpp_type_generator.GetRootNamespaceStart()).Concat( self._cpp_type_generator.GetNamespaceStart()).Append()) if self._namespace.properties: (c.Append('//').Append('// Properties').Append('//').Append()) for property in self._namespace.properties.values(): property_code = self._cpp_type_generator.GeneratePropertyValues( property, 'const %(type)s %(name)s = %(value)s;', nodoc=True) if property_code: c.Concat(property_code).Append() if self._namespace.types: (c.Append('//').Append('// Types').Append('//').Append()) for type_ in self._namespace.types.values(): (c.Concat( self._GenerateType( schema_util.StripSchemaNamespace(type_.name), type_)).Append()) if self._namespace.functions: (c.Append('//').Append('// Functions').Append('//').Append()) for function in self._namespace.functions.values(): (c.Concat( self._GenerateFunction(cpp_util.Classname(function.name), function)).Append()) (c.Concat(self._cpp_type_generator.GetNamespaceEnd()).Concat( self._cpp_type_generator.GetRootNamespaceEnd()).Append()) # TODO(calamity): Events return c
def _GenerateTypePopulate(self, cpp_namespace, type_): """Generates the function for populating a type given a pointer to it. E.g for type "Foo", generates Foo::Populate() """ classname = cpp_util.Classname( schema_util.StripSchemaNamespace(type_.name)) c = Code() (c.Append('// static').Sblock( 'bool %(namespace)s::Populate' '(const base::Value& value, %(name)s* out) {').Append( 'if (!value.IsType(base::Value::TYPE_DICTIONARY))').Append( ' return false;')) if type_.properties: (c.Append( 'const base::DictionaryValue* dict = ' 'static_cast<const base::DictionaryValue*>(&value);').Append()) for prop in type_.properties.values(): c.Concat(self._InitializePropertyToDefault(prop, 'out')) for prop in type_.properties.values(): if prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: c.Append( 'out->additional_properties.MergeDictionary(dict);') # remove all keys that are actual properties for cur_prop in type_.properties.values(): if prop != cur_prop: c.Append( 'out->additional_properties' '.RemoveWithoutPathExpansion("%s", NULL);' % cur_prop.name) c.Append() else: c.Concat( self._GenerateTypePopulateProperty( prop, 'dict', 'out')) (c.Append('return true;').Eblock('}')) c.Substitute({'namespace': cpp_namespace, 'name': classname}) return c
def _GenerateType(self, cpp_namespace, type_): """Generates the function definitions for a type. """ classname = cpp_util.Classname( schema_util.StripSchemaNamespace(type_.name)) c = Code() if type_.functions: # Types with functions are not instantiable in C++ because they are # handled in pure Javascript and hence have no properties or # additionalProperties. if type_.properties: raise NotImplementedError( '\n'.join(model.GetModelHierarchy(type_)) + '\nCannot generate both functions and properties on a type' ) for function in type_.functions.values(): (c.Concat( self._GenerateFunction( cpp_namespace + '::' + cpp_util.Classname(function.name), function)).Append()) elif type_.type_ == PropertyType.OBJECT: (c.Concat( self._GeneratePropertyFunctions( cpp_namespace, type_.properties.values())).Sblock( '%(namespace)s::%(classname)s()').Concat( self._GenerateInitializersAndBody(type_)).Eblock( '%(namespace)s::~%(classname)s() {}').Append()) if type_.from_json: (c.Concat(self._GenerateTypePopulate(cpp_namespace, type_)).Append()) if type_.from_client: (c.Concat(self._GenerateTypeToValue(cpp_namespace, type_)).Append()) c.Substitute({'classname': classname, 'namespace': cpp_namespace}) return c
def GetType(self, prop, pad_for_generics=False, wrap_optional=False): """Translates a model.Property into its C++ type. If REF types from different namespaces are referenced, will resolve using self._type_namespaces. Use pad_for_generics when using as a generic to avoid operator ambiguity. Use wrap_optional to wrap the type in a scoped_ptr<T> if the Property is optional. """ cpp_type = None force_wrapping = False if prop.type_ == PropertyType.REF: dependency_namespace = self._ResolveTypeNamespace(prop.ref_type) if not dependency_namespace: raise KeyError('Cannot find referenced type: %s' % prop.ref_type) if self._namespace != dependency_namespace: cpp_type = '%s::%s' % (self._cpp_namespaces[dependency_namespace], schema_util.StripSchemaNamespace(prop.ref_type)) else: cpp_type = schema_util.StripSchemaNamespace(prop.ref_type) elif prop.type_ == PropertyType.BOOLEAN: cpp_type = 'bool' elif prop.type_ == PropertyType.INTEGER: cpp_type = 'int' elif prop.type_ == PropertyType.DOUBLE: cpp_type = 'double' elif prop.type_ == PropertyType.STRING: cpp_type = 'std::string' elif prop.type_ == PropertyType.ENUM: cpp_type = cpp_util.Classname(prop.name) elif prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: cpp_type = 'base::DictionaryValue' elif prop.type_ == PropertyType.ANY: cpp_type = any_helper.ANY_CLASS elif prop.type_ == PropertyType.OBJECT: cpp_type = cpp_util.Classname(prop.name) elif prop.type_ == PropertyType.ARRAY: item_type = prop.item_type if item_type.type_ == PropertyType.REF: item_type = self.GetReferencedProperty(item_type) if item_type.type_ in ( PropertyType.REF, PropertyType.ANY, PropertyType.OBJECT): cpp_type = 'std::vector<linked_ptr<%s> > ' else: cpp_type = 'std::vector<%s> ' cpp_type = cpp_type % self.GetType( prop.item_type, pad_for_generics=True) elif prop.type_ == PropertyType.BINARY: # Since base::BinaryValue's are immutable, we wrap them in a scoped_ptr to # allow them to be modified after the fact. force_wrapping = True cpp_type = 'base::BinaryValue' else: raise NotImplementedError(prop.type_) # Enums aren't wrapped because C++ won't allow it. Optional enums have a # NONE value generated instead. if force_wrapping or (wrap_optional and prop.optional and prop.type_ != PropertyType.ENUM): cpp_type = 'scoped_ptr<%s> ' % cpp_type if pad_for_generics: return cpp_type return cpp_type.strip()
def testStripSchemaNamespace(self): self.assertEquals('Bar', schema_util.StripSchemaNamespace('foo.Bar')) self.assertEquals('Baz', schema_util.StripSchemaNamespace('Baz'))
def _GetTypeHelper(self, prop, pad_for_generics=False, wrap_optional=False, use_compiled_type=False): """Translates a model.Property into its C++ type. If REF types from different namespaces are referenced, will resolve using self._type_namespaces. Use pad_for_generics when using as a generic to avoid operator ambiguity. Use wrap_optional to wrap the type in a scoped_ptr<T> if the Property is optional. Use use_compiled_type when converting from prop.type_ to prop.compiled_type. """ cpp_type = None type_ = prop.type_ if not use_compiled_type else prop.compiled_type if type_ == PropertyType.REF: dependency_namespace = self._ResolveTypeNamespace(prop.ref_type) if not dependency_namespace: raise KeyError('Cannot find referenced type: %s' % prop.ref_type) if self._namespace != dependency_namespace: cpp_type = '%s::%s' % ( self._cpp_namespaces[dependency_namespace], schema_util.StripSchemaNamespace(prop.ref_type)) else: cpp_type = schema_util.StripSchemaNamespace(prop.ref_type) elif type_ == PropertyType.BOOLEAN: cpp_type = 'bool' elif type_ == PropertyType.INTEGER: cpp_type = 'int' elif type_ == PropertyType.INT64: cpp_type = 'int64' elif type_ == PropertyType.DOUBLE: cpp_type = 'double' elif type_ == PropertyType.STRING: cpp_type = 'std::string' elif type_ == PropertyType.ENUM: cpp_type = cpp_util.Classname(prop.name) elif type_ == PropertyType.ADDITIONAL_PROPERTIES: cpp_type = 'base::DictionaryValue' elif type_ == PropertyType.ANY: cpp_type = any_helper.ANY_CLASS elif type_ == PropertyType.OBJECT: cpp_type = cpp_util.Classname(prop.name) elif type_ == PropertyType.FUNCTION: # Functions come into the json schema compiler as empty objects. We can # record these as empty DictionaryValue's so that we know if the function # was passed in or not. cpp_type = 'base::DictionaryValue' elif type_ == PropertyType.ARRAY: item_type = prop.item_type if item_type.type_ == PropertyType.REF: item_type = self.GetReferencedProperty(item_type) if item_type.type_ in (PropertyType.REF, PropertyType.ANY, PropertyType.OBJECT): cpp_type = 'std::vector<linked_ptr<%s> > ' else: cpp_type = 'std::vector<%s> ' cpp_type = cpp_type % self.GetType(prop.item_type, pad_for_generics=True) elif type_ == PropertyType.BINARY: cpp_type = 'std::string' else: raise NotImplementedError(type_) # Enums aren't wrapped because C++ won't allow it. Optional enums have a # NONE value generated instead. if wrap_optional and prop.optional and not self.IsEnumOrEnumRef(prop): cpp_type = 'scoped_ptr<%s> ' % cpp_type if pad_for_generics: return cpp_type return cpp_type.strip()