def _GenerateFields(self, props): """Generates the field declarations when declaring a type. """ c = Code() # Generate the enums needed for any fields with "choices" for prop in props: if prop.type_ == PropertyType.CHOICES: enum_name = self._cpp_type_generator.GetChoicesEnumType(prop) c.Append('%s %s_type;' % (enum_name, prop.unix_name)) c.Append() for prop in self._cpp_type_generator.GetExpandedChoicesInParams(props): if prop.description: c.Comment(prop.description) c.Append('%s %s;' % ( self._cpp_type_generator.GetType(prop, wrap_optional=True), prop.unix_name)) c.Append() return c
def _GenerateCreateCallbackArguments(self, function): """Generates functions for passing parameters to a callback. """ c = Code() params = function.params c.Cblock( self._GenerateTypes((p.type_ for p in params), is_toplevel=True)) declaration_list = [] for param in params: if param.description: c.Comment(param.description) declaration_list.append( cpp_util.GetParameterDeclaration( param, self._type_helper.GetCppType(param.type_))) c.Append('std::unique_ptr<base::ListValue> Create(%s);' % ', '.join(declaration_list)) return c
def _GenerateFunctionJsDoc(self, function): """Generates the documentation for a function as a Code. Returns an empty code object if the object has no documentation. """ c = Code() c.Sblock(line='/**', line_prefix=' * ') if function.description: c.Comment(function.description, comment_prefix='') def append_field(c, tag, js_type, name, optional, description): c.Append('@%s {' % tag) c.Concat(js_type, new_line=False) if optional: c.Append('=', new_line=False) c.Append('} %s' % name, new_line=False) if description: c.Comment(' %s' % description, comment_prefix='', wrap_indent=4, new_line=False) for param in function.params: append_field(c, 'param', self._TypeToJsType(param.type_), param.name, param.optional, param.description) if function.callback: append_field(c, 'param', self._FunctionToJsFunction(function.callback), function.callback.name, function.callback.optional, function.callback.description) if function.returns: append_field(c, 'return', self._TypeToJsType(function.returns), '', False, function.returns.description) if function.deprecated: c.Append('@deprecated %s' % function.deprecated) c.Append(self._GenerateSeeLink('method', function.name)) c.Eblock(' */') return c
def _GenerateFields(self, props): """Generates the field declarations when declaring a type. """ c = Code() needs_blank_line = False for prop in props: if needs_blank_line: c.Append() needs_blank_line = True if prop.description: c.Comment(prop.description) # ANY is a base::Value which is abstract and cannot be a direct member, so # we always need to wrap it in a scoped_ptr. is_ptr = prop.optional or prop.type_.property_type == PropertyType.ANY (c.Append('%s %s;' % ( self._type_helper.GetCppType(prop.type_, is_ptr=is_ptr), prop.unix_name)) ) return c
def _GenerateCreateCallbackArguments(self, function, generate_to_json=False): """Generates functions for passing paramaters to a callback. """ c = Code() params = function.params c.Concat(self._GeneratePropertyStructures(params)) param_lists = self._cpp_type_generator.GetAllPossibleParameterLists(params) for param_list in param_lists: declaration_list = [] for param in param_list: if param.description: c.Comment(param.description) declaration_list.append('const %s' % cpp_util.GetParameterDeclaration( param, self._cpp_type_generator.GetCompiledType(param))) c.Append('scoped_ptr<base::ListValue> Create(%s);' % ', '.join(declaration_list)) if generate_to_json: c.Append('std::string ToJson(%s);' % ', '.join(declaration_list)) return c
def testComment(self): long_comment = ('This comment is ninety one characters in longness, ' 'that is, using a different word, length.') c = Code() c.Comment(long_comment) self.assertEqual( '// This comment is ninety one characters ' 'in longness, that is, using a different\n' '// word, length.', c.Render()) c = Code() c.Sblock('sblock') c.Comment(long_comment) c.Eblock('eblock') c.Comment(long_comment) self.assertEqual( 'sblock\n' ' // This comment is ninety one characters ' 'in longness, that is, using a\n' ' // different word, length.\n' 'eblock\n' '// This comment is ninety one characters in ' 'longness, that is, using a different\n' '// word, length.', c.Render()) # Words that cannot be broken up are left as too long. long_word = 'x' * 100 c = Code() c.Comment('xxx') c.Comment(long_word) c.Comment('xxx') self.assertEqual('// xxx\n' '// ' + 'x' * 100 + '\n' '// xxx', c.Render()) c = Code(indent_size=2, comment_length=40) c.Comment( 'Pretend this is a Closure Compiler style comment, which should ' 'both wrap and indent', comment_prefix=' * ', wrap_indent=4) self.assertEqual( ' * Pretend this is a Closure Compiler\n' ' * style comment, which should both\n' ' * wrap and indent', c.Render())
def _GenerateType(self, type_, is_toplevel=False, generate_typedefs=False): """Generates a struct for |type_|. |is_toplevel| implies that the type was declared in the "types" field of an API schema. This determines the correct function modifier(s). |generate_typedefs| controls whether primitive types should be generated as a typedef. This may not always be desired. If false, primitive types are ignored. """ classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) c = Code() if type_.functions: # Wrap functions within types in the type's namespace. (c.Append('namespace %s {' % classname).Append()) for function in type_.functions.values(): c.Cblock(self._GenerateFunction(function)) c.Append('} // namespace %s' % classname) elif type_.property_type == PropertyType.ARRAY: if generate_typedefs and type_.description: c.Comment(type_.description) c.Cblock( self._GenerateType(type_.item_type, is_toplevel=is_toplevel)) if generate_typedefs: (c.Append('typedef std::vector<%s > %s;' % (self._type_helper.GetCppType( type_.item_type), classname))) elif type_.property_type == PropertyType.STRING: if generate_typedefs: if type_.description: c.Comment(type_.description) c.Append('typedef std::string %(classname)s;') elif type_.property_type == PropertyType.ENUM: if type_.description: c.Comment(type_.description) c.Cblock(self._GenerateEnumDeclaration(classname, type_)) # Top level enums are in a namespace scope so the methods shouldn't be # static. On the other hand, those declared inline (e.g. in an object) do. maybe_static = '' if is_toplevel else 'static ' (c.Append().Append( '%sconst char* ToString(%s as_enum);' % (maybe_static, classname)).Append( '%s%s Parse%s(const std::string& as_string);' % (maybe_static, classname, classname))) elif type_.property_type in (PropertyType.CHOICES, PropertyType.OBJECT): if type_.description: c.Comment(type_.description) (c.Sblock('struct %(classname)s {').Append( '%(classname)s();').Append('~%(classname)s();').Append( '%(classname)s(const %(classname)s&) = delete;'). Append('%(classname)s& operator=(const %(classname)s&) = delete;' ).Append('%(classname)s(%(classname)s&& rhs);').Append( '%(classname)s& operator=(%(classname)s&& rhs);')) if type_.origin.from_manifest_keys: c.Append() c.Comment('Manifest key constants.') c.Concat( self._GenerateManifestKeyConstants( type_.properties.values())) if type_.origin.from_json: (c.Append().Comment( 'Populates a %s object from a base::Value. Returns' ' whether |out| was successfully populated.' % classname).Append('static bool Populate(%s);' % self._GenerateParams( ('const base::Value& value', '%s* out' % classname)))) if is_toplevel: (c.Append().Comment( 'Creates a %s object from a base::Value, or NULL on ' 'failure.' % classname).Append( 'static std::unique_ptr<%s> FromValue(%s);' % (classname, self._GenerateParams( ('const base::Value& value', ))))) if type_.origin.from_client: value_type = ('base::Value' if type_.property_type is PropertyType.CHOICES else 'base::DictionaryValue') (c.Append().Comment( 'Returns a new %s representing the serialized form of this ' '%s object.' % (value_type, classname)).Append( 'std::unique_ptr<%s> ToValue() const;' % value_type)) if type_.origin.from_manifest_keys: c.Cblock(self._GenerateParseFromDictionary(type_, classname)) if type_.property_type == PropertyType.CHOICES: # Choices are modelled with optional fields for each choice. Exactly one # field of the choice is guaranteed to be set by the compiler. c.Cblock(self._GenerateTypes(type_.choices)) c.Append('// Choices:') for choice_type in type_.choices: c.Append('%s as_%s;' % (self._type_helper.GetCppType( choice_type, is_ptr=True), choice_type.unix_name)) else: properties = type_.properties.values() (c.Append().Cblock( self._GenerateTypes(p.type_ for p in properties)).Cblock( self._GenerateFields(properties))) if type_.additional_properties is not None: # Most additionalProperties actually have type "any", which is better # modelled as a DictionaryValue rather than a map of string -> Value. if type_.additional_properties.property_type == PropertyType.ANY: c.Append( 'base::DictionaryValue additional_properties;') else: (c.Cblock( self._GenerateType(type_.additional_properties)). Append( 'std::map<std::string, %s> additional_properties;' % self._type_helper.GetCppType( type_.additional_properties, is_in_container=True))) (c.Eblock('};')) return c.Substitute({'classname': classname})
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.GetCompiledType(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;') elif type_.type_ == PropertyType.ENUM: if type_.description: c.Comment(type_.description) c.Sblock('enum %(classname)s {') c.Append('%s,' % self._cpp_type_generator.GetEnumNoneValue(type_)) for value in type_.enum_values: c.Append('%s,' % self._cpp_type_generator.GetEnumValue(type_, value)) (c.Eblock('};') .Append() .Append('scoped_ptr<base::Value> CreateEnumValue(%s %s);' % (classname, classname.lower())) .Append('std::string ToString(%s enum_param);' % classname) .Append('%s From%sString(const std::string& enum_string);' % (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 base::Value. Returns' ' whether |out| was successfully populated.' % classname) .Append('static bool Populate(const base::Value& value, ' '%(classname)s* out);') .Append() ) if type_.from_client: (c.Comment('Returns a new base::DictionaryValue representing the' ' serialized form of this %s object. Passes ' 'ownership to caller.' % classname) .Append('scoped_ptr<base::DictionaryValue> ToValue() const;') ) (c.Eblock() .Sblock(' private:') .Concat(self._GeneratePrivatePropertyStructures( type_.properties.values())) .Append() .Append('DISALLOW_COPY_AND_ASSIGN(%(classname)s);') .Eblock('};') ) c.Substitute({'classname': classname}) return c
def _GenerateType(self, type_, is_toplevel=False, generate_typedefs=False): """Generates a struct for |type_|. |is_toplevel| implies that the type was declared in the "types" field of an API schema. This determines the correct function modifier(s). |generate_typedefs| controls whether primitive types should be generated as a typedef. This may not always be desired. If false, primitive types are ignored. """ classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) c = Code() if type_.functions: # Wrap functions within types in the type's namespace. (c.Append('namespace %s {' % classname) .Append() ) for function in type_.functions.values(): c.Cblock(self._GenerateFunction(function)) c.Append('} // namespace %s' % classname) elif type_.property_type == PropertyType.ARRAY: if generate_typedefs and type_.description: c.Comment(type_.description) c.Cblock(self._GenerateType(type_.item_type)) if generate_typedefs: (c.Append('typedef std::vector<%s > %s;' % ( self._type_helper.GetCppType(type_.item_type), classname)) ) elif type_.property_type == PropertyType.STRING: if generate_typedefs: if type_.description: c.Comment(type_.description) c.Append('typedef std::string %(classname)s;') elif type_.property_type == PropertyType.ENUM: if type_.description: c.Comment(type_.description) c.Sblock('enum %(classname)s {') c.Append('%s,' % self._type_helper.GetEnumNoneValue(type_)) for value in type_.enum_values: c.Append('%s,' % self._type_helper.GetEnumValue(type_, value)) # Top level enums are in a namespace scope so the methods shouldn't be # static. On the other hand, those declared inline (e.g. in an object) do. maybe_static = '' if is_toplevel else 'static ' (c.Eblock('};') .Append() .Append('%sstd::string ToString(%s as_enum);' % (maybe_static, classname)) .Append('%s%s Parse%s(const std::string& as_string);' % (maybe_static, classname, classname)) ) elif type_.property_type == PropertyType.OBJECT: if type_.description: c.Comment(type_.description) (c.Sblock('struct %(classname)s {') .Append('%(classname)s();') .Append('~%(classname)s();') ) if type_.origin.from_json: (c.Append() .Comment('Populates a %s object from a base::Value. Returns' ' whether |out| was successfully populated.' % classname) .Append('static bool Populate(const base::Value& value, ' '%(classname)s* out);') ) if type_.origin.from_client: (c.Append() .Comment('Returns a new base::DictionaryValue representing the' ' serialized form of this %s object.' % classname) .Append('scoped_ptr<base::DictionaryValue> ToValue() const;') ) properties = type_.properties.values() (c.Append() .Cblock(self._GenerateTypes(p.type_ for p in properties)) .Cblock(self._GenerateFields(properties))) if type_.additional_properties is not None: # Most additionalProperties actually have type "any", which is better # modelled as a DictionaryValue rather than a map of string -> Value. if type_.additional_properties.property_type == PropertyType.ANY: c.Append('base::DictionaryValue additional_properties;') else: (c.Cblock(self._GenerateType(type_.additional_properties)) .Append('std::map<std::string, %s> additional_properties;' % cpp_util.PadForGenerics( self._type_helper.GetCppType(type_.additional_properties, is_in_container=True))) ) (c.Eblock() .Append() .Sblock(' private:') .Append('DISALLOW_COPY_AND_ASSIGN(%(classname)s);') .Eblock('};') ) elif type_.property_type == PropertyType.CHOICES: if type_.description: c.Comment(type_.description) # Choices are modelled with optional fields for each choice. Exactly one # field of the choice is guaranteed to be set by the compiler. (c.Sblock('struct %(classname)s {') .Append('%(classname)s();') .Append('~%(classname)s();') .Append()) c.Cblock(self._GenerateTypes(type_.choices)) if type_.origin.from_json: (c.Comment('Populates a %s object from a base::Value. Returns' ' whether |out| was successfully populated.' % classname) .Append('static bool Populate(const base::Value& value, ' '%(classname)s* out);') .Append() ) if type_.origin.from_client: (c.Comment('Returns a new base::Value representing the' ' serialized form of this %s object.' % classname) .Append('scoped_ptr<base::Value> ToValue() const;') .Append() ) c.Append('// Choices:') for choice_type in type_.choices: c.Append('%s as_%s;' % ( self._type_helper.GetCppType(choice_type, is_ptr=True), choice_type.unix_name)) c.Eblock('};') c.Substitute({'classname': classname}) 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: # 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') 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