def Write(self): """Writes the output.""" header_file = self._out_base_filename + '.h' cc_file = self._out_base_filename + '.cc' include_file_root = self._out_root[len(self._gen_dir_relpath)+1:] header_file_path = '%s/%s' % (include_file_root, header_file) cc_file_path = '%s/%s' % (include_file_root, cc_file) substitutions = ({ 'header_file_path': header_file_path, 'header_guard': (header_file_path.replace('/', '_'). replace('.', '_').upper()), 'method_name': self._method_name, 'source_files': str([ToPosixPath(f) for f in self._source_files]), 'year': str(datetime.now().year) }) if not os.path.exists(self._out_root): os.makedirs(self._out_root) # Write the .h file. with open(os.path.join(self._out_root, header_file), 'w') as f: header_file = Code() header_file.Append(HEADER_FILE_TEMPLATE) header_file.Substitute(substitutions) f.write(header_file.Render().strip()) # Write the .cc file. with open(os.path.join(self._out_root, cc_file), 'w') as f: cc_file = Code() cc_file.Append(CC_FILE_BEGIN) cc_file.Substitute(substitutions) cc_file.Concat(self.Render()) cc_end = Code() cc_end.Append(CC_FILE_END) cc_end.Substitute(substitutions) cc_file.Concat(cc_end) f.write(cc_file.Render().strip())
def Write(self): """Writes the output.""" header_file_path = self._out_base_filename + '.h' cc_file_path = self._out_base_filename + '.cc' substitutions = ({ 'header_file_path': header_file_path, 'header_guard': (header_file_path.replace('/', '_').replace('.', '_').upper()), 'provider_class': self._provider_class, 'source_files': str(self._source_files), 'year': str(datetime.now().year) }) if not os.path.exists(self._out_root): os.makedirs(self._out_root) # Write the .h file. with open(os.path.join(self._out_root, header_file_path), 'w') as f: header_file = Code() header_file.Append(HEADER_FILE_TEMPLATE) header_file.Substitute(substitutions) f.write(header_file.Render().strip()) # Write the .cc file. with open(os.path.join(self._out_root, cc_file_path), 'w') as f: cc_file = Code() cc_file.Append(CC_FILE_BEGIN) cc_file.Substitute(substitutions) cc_file.Concat(self.Render()) cc_end = Code() cc_end.Append(CC_FILE_END) cc_end.Substitute(substitutions) cc_file.Concat(cc_end) f.write(cc_file.Render().strip())
def _GenerateType(self, type_): """Generates a struct for a type. """ classname = cpp_util.Classname(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)}) 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 _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 testSubstitute(self): c = Code() c.Append('%(var1)s %(var2)s %(var1)s') c.Substitute({'var1': 'one', 'var2': 'two'}) self.assertEquals('one two one', c.Render()) c.Append('%(var1)s %(var2)s %(var3)s') c.Append('%(var2)s %(var1)s %(var3)s') c.Substitute({'var1': 'one', 'var2': 'two', 'var3': 'three'}) self.assertEquals('one two one\n' 'one two three\n' 'two one three', c.Render())
def Write(self): """Writes the output.""" header_file = self._out_base_filename + '.h' cc_file = self._out_base_filename + '.cc' include_file_root = self._out_root GEN_DIR_PREFIX = 'gen/' if include_file_root.startswith(GEN_DIR_PREFIX) and len( include_file_root) >= len(GEN_DIR_PREFIX): include_file_root = include_file_root[len(GEN_DIR_PREFIX):] else: include_file_root = '' if include_file_root: header_file_path = '%s/%s' % (include_file_root, header_file) else: header_file_path = header_file cc_file_path = '%s/%s' % (include_file_root, cc_file) substitutions = ({ 'header_file_path': header_file_path, 'header_guard': (header_file_path.replace('/', '_').replace('.', '_').upper()), 'method_name': self._method_name, 'source_files': str(self._source_files), 'year': str(datetime.now().year) }) if not os.path.exists(self._out_root): os.makedirs(self._out_root) # Write the .h file. with open(os.path.join(self._out_root, header_file), 'w') as f: header_file = Code() header_file.Append(HEADER_FILE_TEMPLATE) header_file.Substitute(substitutions) f.write(header_file.Render().strip()) # Write the .cc file. with open(os.path.join(self._out_root, cc_file), 'w') as f: cc_file = Code() cc_file.Append(CC_FILE_BEGIN) cc_file.Substitute(substitutions) cc_file.Concat(self.Render()) cc_end = Code() cc_end.Append(CC_FILE_END) cc_end.Substitute(substitutions) cc_file.Concat(cc_end) f.write(cc_file.Render().strip())
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, types in sorted( self._NamespaceTypeDependencies().items()): c.Append('namespace %s {' % namespace.name) for type_ in types: if namespace.types[type_].type_ == PropertyType.STRING: c.Append('typedef std::string %s;' % type_) elif namespace.types[type_].type_ == PropertyType.ARRAY: c.Append('typedef std::vector<%(item_type)s> %(name)s;') c.Substitute({ 'name': type_, 'item_type': self.GetType(namespace.types[type_].item_type, wrap_optional=True) }) else: c.Append('struct %s;' % type_) 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;' % name) c.Concat(self.GetNamespaceEnd()) return c
def _GenerateTypePopulateProperty(self, prop, src, dst): """Generate the code to populate a single property in a type. src: DictionaryValue* dst: Type* """ c = Code() value_var = prop.unix_name + '_value' c.Append('Value* %(value_var)s = NULL;') if prop.optional: (c.Sblock( 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {' ) .Concat(self._GeneratePopulatePropertyFromValue( prop, value_var, dst, 'false')) .Eblock('}') ) else: (c.Append( 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))') .Append(' return false;') .Concat(self._GeneratePopulatePropertyFromValue( prop, value_var, dst, 'false')) ) c.Append() c.Substitute({'value_var': value_var, 'key': prop.name, 'src': src}) 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 _GenerateCreateCallbackArguments(self, function_scope, callback): """Generate all functions to create Value parameters for a callback. E.g for function "Bar", generate Bar::Results::Create E.g for event "Baz", generate Baz::Create function_scope: the function scope path, e.g. Foo::Bar for the function Foo::Bar::Baz(). May be None if there is no function scope. callback: the Function object we are creating callback arguments for. """ c = Code() params = callback.params c.Concat(self._GeneratePropertyFunctions(function_scope, params)) (c.Sblock('scoped_ptr<base::ListValue> %(function_scope)s' 'Create(%(declaration_list)s) {') .Append('scoped_ptr<base::ListValue> create_results(' 'new base::ListValue());') ) declaration_list = [] for param in params: declaration_list.append(cpp_util.GetParameterDeclaration( param, self._type_helper.GetCppType(param.type_))) c.Append('create_results->Append(%s);' % self._CreateValueFromType(param.type_, param.unix_name)) c.Append('return create_results.Pass();') c.Eblock('}') c.Substitute({ 'function_scope': ('%s::' % function_scope) if function_scope else '', 'declaration_list': ', '.join(declaration_list), 'param_names': ', '.join(param.unix_name for param in params) }) return c
def _GenerateTypePopulateProperty(self, prop, src, dst): """Generate the code to populate a single property in a type. src: base::DictionaryValue* dst: Type* """ c = Code() value_var = prop.unix_name + '_value' c.Append('const base::Value* %(value_var)s = NULL;') if prop.optional: (c.Sblock( 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {' ).Concat( self._GeneratePopulatePropertyFromValue( prop, value_var, dst, 'false'))) if self._cpp_type_generator.IsEnumOrEnumRef(prop): (c.Append('} else {').Append( '%%(dst)s->%%(name)s = %s;' % self._cpp_type_generator.GetEnumNoneValue(prop))) c.Eblock('}') else: (c.Append( 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))' ).Append(' return false;').Concat( self._GeneratePopulatePropertyFromValue( prop, value_var, dst, 'false'))) c.Append() c.Substitute({ 'value_var': value_var, 'key': prop.name, 'src': src, 'dst': dst, 'name': prop.unix_name }) return c
def _GenerateCreateEnumValue(self, cpp_namespace, prop): """Generates CreateEnumValue() that returns the |StringValue| representation of an enum. """ c = Code() c.Append('// static') c.Sblock( 'scoped_ptr<Value> %(cpp_namespace)s::CreateEnumValue(%(arg)s) {') c.Sblock('switch (%s) {' % prop.unix_name) if prop.optional: (c.Append('case %s: {' % self._cpp_type_generator.GetEnumNoneValue(prop)).Append( ' return scoped_ptr<Value>();').Append('}')) for enum_value in prop.enum_values: (c.Append( 'case %s: {' % self._cpp_type_generator.GetEnumValue(prop, enum_value) ).Append( ' return scoped_ptr<Value>(Value::CreateStringValue("%s"));' % enum_value).Append('}')) (c.Append('default: {').Append(' return scoped_ptr<Value>();').Append( '}')) c.Eblock('}') c.Eblock('}') c.Substitute({ 'cpp_namespace': cpp_namespace, 'arg': cpp_util.GetParameterDeclaration( prop, self._cpp_type_generator.GetType(prop)) }) 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(type_.name) c = Code() (c.Append('// static').Sblock('bool %(namespace)s::Populate' '(const Value& value, %(name)s* out) {'). Append('if (!value.IsType(Value::TYPE_DICTIONARY))').Append( ' return false;').Append( 'const DictionaryValue* dict = ' 'static_cast<const 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 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=operator.attrgetter('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) }) # Enums cannot be forward declared. elif namespace.types[type_].type_ != PropertyType.ENUM: 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 _GenerateFunctionParamsCreate(self, cpp_namespace, function): """Generate function to create an instance of Params. The generated function takes a ListValue of arguments. E.g for function "Bar", generate Bar::Params::Create() """ c = Code() (c.Append('// static') .Sblock('scoped_ptr<%(cpp_namespace)s::Params> ' '%(cpp_namespace)s::Params::Create(const ListValue& args) {') .Concat(self._GenerateParamsCheck(function, 'args')) .Append('scoped_ptr<Params> params(new Params());') ) c.Substitute({'cpp_namespace': cpp_namespace}) for param in function.params: c.Concat(self._InitializePropertyToDefault(param, 'params')) for i, param in enumerate(function.params): # Any failure will cause this function to return. If any argument is # incorrect or missing, those following it are not processed. Note that # for optional arguments, we allow missing arguments and proceed because # there may be other arguments following it. failure_value = 'scoped_ptr<Params>()' c.Append() value_var = param.unix_name + '_value' (c.Append('Value* %(value_var)s = NULL;') .Append('if (args.Get(%(i)s, &%(value_var)s) && ' '!%(value_var)s->IsType(Value::TYPE_NULL))') .Sblock('{') .Concat(self._GeneratePopulatePropertyFromValue( param, value_var, 'params', failure_value)) .Eblock('}') ) if not param.optional: (c.Sblock('else {') .Append('return %s;' % failure_value) .Eblock('}') ) c.Substitute({'value_var': value_var, 'i': i}) (c.Append() .Append('return params.Pass();') .Eblock('}') .Append() ) return c
def testCommentWithSpecialCharacters(self): c = Code() c.Comment('20% of 80%s') c.Substitute({}) self.assertEquals('// 20% of 80%s', c.Render()) d = Code() d.Append('90') d.Concat(c) self.assertEquals('90\n' '// 20% of 80%s', d.Render())
def _GeneratePopulatePropertyFromValue(self, prop, value_var, dst, failure_value, check_type=True): """Generates code to populate a model.Property given a base::Value*. The existence of data inside the base::Value* is assumed so checks for existence should be performed before the code this generates. prop: the property the code is populating. value_var: a base::Value* that should represent |prop|. dst: the object with |prop| as a member. failure_value: the value to return if |prop| cannot be extracted from |value_var| check_type: if true, will check if |value_var| is the correct base::Value::Type """ c = Code() c.Sblock('{') if self._IsFundamentalOrFundamentalRef(prop): self._GenerateFundamentalOrFundamentalRefPopulate( c, prop, value_var, dst) elif self._IsObjectOrObjectRef(prop): self._GenerateObjectOrObjectRefPopulate(c, prop) elif prop.type_ == PropertyType.FUNCTION: self._GenerateFunctionPopulate(c, prop) elif prop.type_ == PropertyType.ANY: self._GenerateAnyPopulate(c, prop, value_var, dst) elif self._IsArrayOrArrayRef(prop): self._GenerateArrayOrArrayRefPopulate(c, prop, dst) elif prop.type_ == PropertyType.CHOICES: self._GenerateChoicePopulate(c, prop, value_var, dst, failure_value) elif self._cpp_type_generator.IsEnumOrEnumRef(prop): self._GenerateEnumPopulate(c, prop, value_var) elif prop.type_ == PropertyType.BINARY: self._GenerateBinaryPopulate(c, prop) else: raise NotImplementedError(prop.type_) c.Eblock('}') sub = { 'value_var': value_var, 'name': prop.unix_name, 'dst': dst, 'failure_value': failure_value, } if prop.type_ not in (PropertyType.CHOICES, PropertyType.ANY): sub['ctype'] = self._cpp_type_generator.GetType(prop) sub['compiled_ctype'] = self._cpp_type_generator.GetCompiledType( prop) sub['value_type'] = cpp_util.GetValueType( self._cpp_type_generator.GetReferencedProperty(prop).type_) c.Substitute(sub) return c
def _GenerateFunctionParamsCreate(self, function): """Generate function to create an instance of Params. The generated function takes a base::ListValue of arguments. E.g for function "Bar", generate Bar::Params::Create() """ c = Code() (c.Append('// static') .Sblock('std::unique_ptr<Params> Params::Create(%s) {' % self._GenerateParams(['const base::ListValue& args'])) ) if self._generate_error_messages: c.Append('DCHECK(error);') (c.Concat(self._GenerateParamsCheck(function, 'args')) .Append('std::unique_ptr<Params> params(new Params());') ) for param in function.params: c.Concat(self._InitializePropertyToDefault(param, 'params')) for i, param in enumerate(function.params): # Any failure will cause this function to return. If any argument is # incorrect or missing, those following it are not processed. Note that # for optional arguments, we allow missing arguments and proceed because # there may be other arguments following it. failure_value = 'std::unique_ptr<Params>()' c.Append() value_var = param.unix_name + '_value' (c.Append('const base::Value* %(value_var)s = NULL;') .Append('if (args.Get(%(i)s, &%(value_var)s) &&') .Sblock(' !%(value_var)s->is_none()) {') .Concat(self._GeneratePopulatePropertyFromValue( param, value_var, 'params', failure_value)) .Eblock('}') ) if not param.optional: (c.Sblock('else {') .Concat(self._GenerateError('"\'%%(key)s\' is required"')) .Append('return %s;' % failure_value) .Eblock('}')) c.Substitute({'value_var': value_var, 'i': i, 'key': param.name}) (c.Append() .Append('return params;') .Eblock('}') .Append() ) return c
def _GenerateFunctionResultCreate(self, cpp_namespace, function): """Generate function to create a Result given the return value. E.g for function "Bar", generate Bar::Result::Create """ c = Code() params = function.callback.params if not params: (c.Append('Value* %s::Result::Create() {' % cpp_namespace).Append( ' return Value::CreateNullValue();').Append('}')) else: expanded_params = self._cpp_type_generator.GetExpandedChoicesInParams( params) c.Concat( self._GeneratePropertyFunctions(cpp_namespace + '::Result', expanded_params)) # If there is a single parameter, this is straightforward. However, if # the callback parameter is of 'choices', this generates a Create method # for each choice. This works because only 1 choice can be returned at a # time. for param in expanded_params: if param.type_ == PropertyType.ANY: # Generation of Value* Create(Value*) is redundant. continue # We treat this argument as 'required' to avoid wrapping it in a # scoped_ptr if it's optional. param_copy = param.Copy() param_copy.optional = False c.Sblock( 'Value* %(cpp_namespace)s::Result::Create(const %(arg)s) {' ) c.Append('return %s;' % self._CreateValueFromProperty( param_copy, param_copy.unix_name)) c.Eblock('}') c.Substitute({ 'cpp_namespace': cpp_namespace, 'arg': cpp_util.GetParameterDeclaration( param_copy, self._cpp_type_generator.GetType(param_copy)) }) return c
def _GenerateTypePopulateProperty(self, prop, src, dst): """Generate the code to populate a single property in a type. src: base::DictionaryValue* dst: Type* """ c = Code() value_var = prop.unix_name + '_value' c.Append('const base::Value* %(value_var)s = NULL;') if prop.optional: (c.Sblock( 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {') .Concat(self._GeneratePopulatePropertyFromValue( prop, value_var, dst, 'false'))) underlying_type = self._type_helper.FollowRef(prop.type_) if underlying_type.property_type == PropertyType.ENUM: namespace_prefix = ('%s::' % underlying_type.namespace.unix_name if underlying_type.namespace != self._namespace else '') (c.Append('} else {') .Append('%%(dst)s->%%(name)s = %s%s;' % (namespace_prefix, self._type_helper.GetEnumNoneValue(prop.type_)))) c.Eblock('}') else: (c.Sblock( 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {') .Concat(self._GenerateError('"\'%%(key)s\' is required"')) .Append('return false;') .Eblock('}') .Concat(self._GeneratePopulatePropertyFromValue( prop, value_var, dst, 'false')) ) c.Append() c.Substitute({ 'value_var': value_var, 'key': prop.name, 'src': src, 'dst': dst, 'name': prop.unix_name }) return c
def _GenerateCreateCallbackArguments(self, function_scope, callback): """Generate all functions to create Value parameters for a callback. E.g for function "Bar", generate Bar::Results::Create E.g for event "Baz", generate Baz::Create function_scope: the function scope path, e.g. Foo::Bar for the function Foo::Bar::Baz(). callback: the Function object we are creating callback arguments for. """ c = Code() params = callback.params expanded_params = self._cpp_type_generator.ExpandParams(params) c.Concat(self._GeneratePropertyFunctions(function_scope, expanded_params)) param_lists = self._cpp_type_generator.GetAllPossibleParameterLists(params) for param_list in param_lists: (c.Sblock('scoped_ptr<base::ListValue> %(function_scope)s::' 'Create(%(declaration_list)s) {') .Append('scoped_ptr<base::ListValue> create_results(' 'new base::ListValue());') ) declaration_list = [] for param in param_list: # We treat this argument as 'required' to avoid wrapping it in a # scoped_ptr if it's optional. param_copy = param.Copy() param_copy.optional = False c.Append('create_results->Append(%s);' % self._CreateValueFromProperty(param_copy, param_copy.unix_name)) declaration_list.append("const %s" % cpp_util.GetParameterDeclaration( param_copy, self._cpp_type_generator.GetType(param_copy))) c.Append('return create_results.Pass();') c.Eblock('}') c.Substitute({ 'function_scope': function_scope, 'declaration_list': ', '.join(declaration_list) }) return c
def _GenerateType(self, cpp_namespace, type_): """Generates the function definitions for a type. """ classname = cpp_util.Classname(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 _GenerateParamsCheck(self, function, var): """Generates a check for the correct number of arguments when creating Params. """ c = Code() num_required = 0 for param in function.params: if not param.optional: num_required += 1 if num_required == len(function.params): c.Append('if (%(var)s.GetSize() != %(total)d)') elif not num_required: c.Append('if (%(var)s.GetSize() > %(total)d)') else: c.Append('if (%(var)s.GetSize() < %(required)d' ' || %(var)s.GetSize() > %(total)d)') c.Append(' return scoped_ptr<Params>();') c.Substitute({ 'var': var, 'required': num_required, 'total': len(function.params), }) return c
def _GenerateFunction(self, cpp_namespace, function): """Generates the definitions for function structs. """ c = Code() # Params::Populate function if function.params: c.Concat( self._GeneratePropertyFunctions(cpp_namespace + '::Params', function.params)) (c.Append('%(cpp_namespace)s::Params::Params() {}').Append( '%(cpp_namespace)s::Params::~Params() {}').Append().Concat( self._GenerateFunctionParamsCreate(cpp_namespace, function)).Append()) # Result::Create function if function.callback: c.Concat( self._GenerateFunctionResultCreate(cpp_namespace, function)) c.Substitute({'cpp_namespace': cpp_namespace}) return c
def _GenerateCreateCallbackArguments(self, function_scope, callback, generate_to_json=False): """Generate all functions to create Value parameters for a callback. E.g for function "Bar", generate Bar::Results::Create E.g for event "Baz", generate Baz::Create function_scope: the function scope path, e.g. Foo::Bar for the function Foo::Bar::Baz(). callback: the Function object we are creating callback arguments for. generate_to_json: Generate a ToJson method. """ c = Code() params = callback.params expanded_params = self._cpp_type_generator.ExpandParams(params) c.Concat( self._GeneratePropertyFunctions(function_scope, expanded_params)) param_lists = self._cpp_type_generator.GetAllPossibleParameterLists( params) for param_list in param_lists: (c.Sblock('scoped_ptr<base::ListValue> %(function_scope)s::' 'Create(%(declaration_list)s) {').Append( 'scoped_ptr<base::ListValue> create_results(' 'new base::ListValue());')) declaration_list = [] for param in param_list: # We treat this argument as 'required' to avoid wrapping it in a # scoped_ptr if it's optional. param_copy = param.Copy() param_copy.optional = False declaration_list.append( "const %s" % cpp_util.GetParameterDeclaration( param_copy, self._cpp_type_generator.GetCompiledType(param_copy))) param_name = param_copy.unix_name if param_copy.type_ != param_copy.compiled_type: param_name = 'temp_' + param_name (c.Append('%s %s;' % (self._cpp_type_generator.GetType( param_copy), param_name)).Append( cpp_util.GenerateCompiledTypeToTypeConversion( param_copy, param_copy.unix_name, param_name) + ';')) c.Append('create_results->Append(%s);' % self._CreateValueFromProperty(param_copy, param_name)) c.Append('return create_results.Pass();') c.Eblock('}') if generate_to_json: c.Append() (c.Sblock('std::string %(function_scope)s::' 'ToJson(%(declaration_list)s) {').Append( 'scoped_ptr<base::ListValue> create_results = ' '%(function_scope)s::Create(%(param_list)s);'). Append('std::string json;').Append( 'base::JSONWriter::Write(create_results.get(), &json);'). Append('return json;')) c.Eblock('}') c.Substitute({ 'function_scope': function_scope, 'declaration_list': ', '.join(declaration_list), 'param_list': ', '.join(param.unix_name for param in param_list) }) return c
def _GeneratePopulateVariableFromValue(self, type_, src_var, dst_var, failure_value, is_ptr=False): """Generates code to populate a variable |dst_var| of type |type_| from a Value* at |src_var|. The Value* is assumed to be non-NULL. In the generated code, if |dst_var| fails to be populated then Populate will return |failure_value|. """ c = Code() underlying_type = self._type_helper.FollowRef(type_) if underlying_type.property_type.is_fundamental: if is_ptr: (c.Append('%(cpp_type)s temp;') .Sblock('if (!%s) {' % cpp_util.GetAsFundamentalValue( self._type_helper.FollowRef(type_), src_var, '&temp')) .Concat(self._GenerateError( '"\'%%(key)s\': expected ' + '%s, got " + %s' % ( type_.name, self._util_cc_helper.GetValueTypeString( '%%(src_var)s', True))))) c.Append('%(dst_var)s.reset();') if not self._generate_error_messages: c.Append('return %(failure_value)s;') (c.Eblock('}') .Append('else') .Append(' %(dst_var)s.reset(new %(cpp_type)s(temp));') ) else: (c.Sblock('if (!%s) {' % cpp_util.GetAsFundamentalValue( self._type_helper.FollowRef(type_), src_var, '&%s' % dst_var)) .Concat(self._GenerateError( '"\'%%(key)s\': expected ' + '%s, got " + %s' % ( type_.name, self._util_cc_helper.GetValueTypeString( '%%(src_var)s', True)))) .Append('return %(failure_value)s;') .Eblock('}') ) elif underlying_type.property_type == PropertyType.OBJECT: if is_ptr: (c.Append('const base::DictionaryValue* dictionary = NULL;') .Sblock('if (!%(src_var)s->GetAsDictionary(&dictionary)) {') .Concat(self._GenerateError( '"\'%%(key)s\': expected dictionary, got " + ' + self._util_cc_helper.GetValueTypeString('%%(src_var)s', True)))) # If an optional property fails to populate, the population can still # succeed with a warning. If no error messages are generated, this # warning is not set and we fail out instead. if not self._generate_error_messages: c.Append('return %(failure_value)s;') (c.Eblock('}') .Sblock('else {') .Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());') .Append('if (!%%(cpp_type)s::Populate(%s)) {' % self._GenerateArgs( ('*dictionary', 'temp.get()'))) .Append(' return %(failure_value)s;') ) (c.Append('}') .Append('else') .Append(' %(dst_var)s = temp.Pass();') .Eblock('}') ) else: (c.Append('const base::DictionaryValue* dictionary = NULL;') .Sblock('if (!%(src_var)s->GetAsDictionary(&dictionary)) {') .Concat(self._GenerateError( '"\'%%(key)s\': expected dictionary, got " + ' + self._util_cc_helper.GetValueTypeString('%%(src_var)s', True))) .Append('return %(failure_value)s;') .Eblock('}') .Append('if (!%%(cpp_type)s::Populate(%s)) {' % self._GenerateArgs( ('*dictionary', '&%(dst_var)s'))) .Append(' return %(failure_value)s;') .Append('}') ) elif underlying_type.property_type == PropertyType.FUNCTION: if is_ptr: c.Append('%(dst_var)s.reset(new base::DictionaryValue());') elif underlying_type.property_type == PropertyType.ANY: c.Append('%(dst_var)s.reset(%(src_var)s->DeepCopy());') elif underlying_type.property_type == PropertyType.ARRAY: # util_cc_helper deals with optional and required arrays (c.Append('const base::ListValue* list = NULL;') .Sblock('if (!%(src_var)s->GetAsList(&list)) {') .Concat(self._GenerateError( '"\'%%(key)s\': expected list, got " + ' + self._util_cc_helper.GetValueTypeString('%%(src_var)s', True))) ) if is_ptr and self._generate_error_messages: c.Append('%(dst_var)s.reset();') else: c.Append('return %(failure_value)s;') c.Eblock('}') c.Sblock('else {') item_type = self._type_helper.FollowRef(underlying_type.item_type) if item_type.property_type == PropertyType.ENUM: c.Concat(self._GenerateListValueToEnumArrayConversion( item_type, 'list', dst_var, failure_value, is_ptr=is_ptr)) else: c.Sblock('if (!%s(%s)) {' % ( self._util_cc_helper.PopulateArrayFromListFunction(is_ptr), self._GenerateArgs(('*list', '&%(dst_var)s')))) c.Concat(self._GenerateError( '"unable to populate array \'%%(parent_key)s\'"')) if is_ptr and self._generate_error_messages: c.Append('%(dst_var)s.reset();') else: c.Append('return %(failure_value)s;') c.Eblock('}') c.Eblock('}') elif underlying_type.property_type == PropertyType.CHOICES: if is_ptr: (c.Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());') .Append('if (!%%(cpp_type)s::Populate(%s))' % self._GenerateArgs( ('*%(src_var)s', 'temp.get()'))) .Append(' return %(failure_value)s;') .Append('%(dst_var)s = temp.Pass();') ) else: (c.Append('if (!%%(cpp_type)s::Populate(%s))' % self._GenerateArgs( ('*%(src_var)s', '&%(dst_var)s'))) .Append(' return %(failure_value)s;')) elif underlying_type.property_type == PropertyType.ENUM: c.Concat(self._GenerateStringToEnumConversion(underlying_type, src_var, dst_var, failure_value)) elif underlying_type.property_type == PropertyType.BINARY: (c.Append('const base::BinaryValue* binary_value = NULL;') .Sblock('if (!%(src_var)s->IsType(base::Value::TYPE_BINARY)) {') .Concat(self._GenerateError( '"\'%%(key)s\': expected binary, got " + ' + self._util_cc_helper.GetValueTypeString('%%(src_var)s', True))) ) if not self._generate_error_messages: c.Append('return %(failure_value)s;') (c.Eblock('}') .Sblock('else {') .Append(' binary_value =') .Append(' static_cast<const base::BinaryValue*>(%(src_var)s);') ) if is_ptr: (c.Append('%(dst_var)s.reset(new std::vector<char>(') .Append(' binary_value->GetBuffer(),') .Append(' binary_value->GetBuffer() + binary_value->GetSize()));') ) else: (c.Append('%(dst_var)s.assign(') .Append(' binary_value->GetBuffer(),') .Append(' binary_value->GetBuffer() + binary_value->GetSize());') ) c.Eblock('}') else: raise NotImplementedError(type_) if c.IsEmpty(): return c return Code().Sblock('{').Concat(c.Substitute({ 'cpp_type': self._type_helper.GetCppType(type_), 'src_var': src_var, 'dst_var': dst_var, 'failure_value': failure_value, 'key': type_.name, 'parent_key': type_.parent.name, })).Eblock('}')
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_, 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 _GeneratePopulatePropertyFromValue(self, prop, value_var, dst, failure_value, check_type=True): """Generates code to populate a model.Property given a Value*. The existence of data inside the Value* is assumed so checks for existence should be performed before the code this generates. prop: the property the code is populating. value_var: a Value* that should represent |prop|. dst: the object with |prop| as a member. failure_value: the value to return if |prop| cannot be extracted from |value_var| check_type: if true, will check if |value_var| is the correct Value::Type """ c = Code() c.Sblock('{') if self._IsFundamentalOrFundamentalRef(prop): if prop.optional: (c.Append('%(ctype)s temp;').Append( 'if (!%s)' % cpp_util.GetAsFundamentalValue( self._cpp_type_generator.GetReferencedProperty(prop), value_var, '&temp')).Append(' return %(failure_value)s;').Append( '%(dst)s->%(name)s.reset(new %(ctype)s(temp));')) else: (c.Append('if (!%s)' % cpp_util.GetAsFundamentalValue( self._cpp_type_generator.GetReferencedProperty(prop), value_var, '&%s->%s' % (dst, prop.unix_name))).Append( ' return %(failure_value)s;')) elif self._IsObjectOrObjectRef(prop): if prop.optional: (c.Append('DictionaryValue* dictionary = NULL;').Append( 'if (!%(value_var)s->GetAsDictionary(&dictionary))'). Append(' return %(failure_value)s;').Append( 'scoped_ptr<%(ctype)s> temp(new %(ctype)s());').Append( 'if (!%(ctype)s::Populate(*dictionary, temp.get()))'). Append(' return %(failure_value)s;').Append( '%(dst)s->%(name)s = temp.Pass();')) else: (c.Append('DictionaryValue* dictionary = NULL;').Append( 'if (!%(value_var)s->GetAsDictionary(&dictionary))' ).Append(' return %(failure_value)s;').Append( 'if (!%(ctype)s::Populate(*dictionary, &%(dst)s->%(name)s))' ).Append(' return %(failure_value)s;')) elif prop.type_ == PropertyType.ANY: if prop.optional: c.Append('%(dst)s->%(name)s.reset(new Any());') c.Append(self._any_helper.Init(prop, value_var, dst) + ';') elif self._IsArrayOrArrayRef(prop): # util_cc_helper deals with optional and required arrays (c.Append('ListValue* list = NULL;'). Append('if (!%(value_var)s->GetAsList(&list))').Append( ' return %(failure_value)s;').Append( 'if (!%s)' % self._util_cc_helper.PopulateArrayFromList( self._cpp_type_generator.GetReferencedProperty(prop), 'list', dst + '->' + prop.unix_name, prop.optional)).Append(' return %(failure_value)s;')) elif prop.type_ == PropertyType.CHOICES: type_var = '%(dst)s->%(name)s_type' c.Sblock('switch (%(value_var)s->GetType()) {') for choice in self._cpp_type_generator.GetExpandedChoicesInParams( [prop]): (c.Sblock('case %s: {' % cpp_util.GetValueType( self._cpp_type_generator.GetReferencedProperty( choice).type_)).Concat( self._GeneratePopulatePropertyFromValue( choice, value_var, dst, failure_value, check_type=False)).Append( '%s = %s;' % (type_var, self._cpp_type_generator.GetEnumValue( prop, choice.type_.name))).Append( 'break;').Eblock('}')) (c.Append('default:').Append(' return %(failure_value)s;')) c.Eblock('}') elif prop.type_ == PropertyType.ENUM: (c.Append('std::string enum_temp;').Append( 'if (!%(value_var)s->GetAsString(&enum_temp))').Append( ' return %(failure_value)s;')) for i, enum_value in enumerate(prop.enum_values): (c.Append(('if' if i == 0 else 'else if') + '(enum_temp == "%s")' % enum_value).Append( ' %s->%s = %s;' % (dst, prop.unix_name, self._cpp_type_generator.GetEnumValue( prop, enum_value)))) (c.Append('else').Append(' return %(failure_value)s;')) elif prop.type_ == PropertyType.BINARY: # This is the same if the property is optional or not. We need a pointer # to the BinaryValue to be able to populate it, so a scoped_ptr is used # whether it is optional or required. (c.Append('if (!%(value_var)s->IsType(%(value_type)s))').Append( ' return %(failure_value)s;'). Append('%(dst)s->%(name)s.reset(').Append( ' static_cast<BinaryValue*>(%(value_var)s)->DeepCopy());')) else: raise NotImplementedError(prop.type_) c.Eblock('}') sub = { 'value_var': value_var, 'name': prop.unix_name, 'dst': dst, 'failure_value': failure_value, } if prop.type_ not in (PropertyType.CHOICES, PropertyType.ANY): sub['ctype'] = self._cpp_type_generator.GetType(prop) sub['value_type'] = cpp_util.GetValueType( self._cpp_type_generator.GetReferencedProperty(prop).type_) c.Substitute(sub) return c