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 ToPpapiType(self, type_, array=False, optional=False): """Returns a string containing the name of the Pepper C type for |type_|. If array is True, returns the name of an array of |type_|. If optional is True, returns the name of an optional |type_|. If both array and optional are True, returns the name of an optional array of |type_|. """ if isinstance(type_, model.Function) or type_.property_type in ( model.PropertyType.OBJECT, model.PropertyType.ENUM): return self._FormatPpapiTypeName( array, optional, '_'.join( cpp_util.Classname(s) for s in self._NameComponents(type_)), namespace=cpp_util.Classname(self._namespace.name)) elif type_.property_type == model.PropertyType.REF: return self.ToPpapiType(self._namespace.types[type_.ref_type], optional=optional, array=array) elif type_.property_type == model.PropertyType.ARRAY: return self.ToPpapiType(type_.item_type, array=True, optional=optional) elif type_.property_type == model.PropertyType.STRING and not array: return 'PP_Var' elif array or optional: if type_.property_type in self._PPAPI_COMPOUND_PRIMITIVE_TYPE_MAP: return self._FormatPpapiTypeName( array, optional, self._PPAPI_COMPOUND_PRIMITIVE_TYPE_MAP[ type_.property_type], '') return self._PPAPI_PRIMITIVE_TYPE_MAP.get(type_.property_type, 'PP_Var')
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 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], prop.ref_type) else: cpp_type = 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: if prop.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: 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 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 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 _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 _GenerateFunction(self, function): """Generates the definitions for function structs. """ c = Code() # TODO(kalman): use function.unix_name not Classname. function_namespace = cpp_util.Classname(function.name) (c.Append('namespace %s {' % function_namespace).Append()) # Params::Populate function if function.params: c.Concat(self._GeneratePropertyFunctions('Params', function.params)) (c.Append('Params::Params() {}').Append( 'Params::~Params() {}').Append().Cblock( self._GenerateFunctionParamsCreate(function))) # Results::Create function if function.callback: c.Concat( self._GenerateCreateCallbackArguments('Results', function.callback)) c.Append('} // namespace %s' % function_namespace) 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 _ShowCompiledFile(self, parsed_url, head, body): """Show the compiled version of a json file given the path to the compiled file. """ api_model = model.Model() request_path = self._GetRequestPath(parsed_url) (file_root, file_ext) = os.path.splitext(request_path) (filedir, filename) = os.path.split(file_root) json_file_path = os.path.normpath(file_root + '.json') try: # Get main json file api_defs = json_schema.Load(json_file_path) namespace = api_model.AddNamespace(api_defs[0], json_file_path) type_generator = cpp_type_generator.CppTypeGenerator( 'previewserver::api', namespace, namespace.unix_name) # Get json file depedencies for dependency in api_defs[0].get('dependencies', []): json_file_path = os.path.join(filedir, dependency + '.json') api_defs = json_schema.Load(json_file_path) referenced_namespace = api_model.AddNamespace( api_defs[0], json_file_path) if referenced_namespace: type_generator.AddNamespace( referenced_namespace, cpp_util.Classname(referenced_namespace.name).lower()) # Generate code if file_ext == '.h': cpp_code = (h_generator.HGenerator( namespace, type_generator).Generate().Render()) elif file_ext == '.cc': cpp_code = (cc_generator.CCGenerator( namespace, type_generator).Generate().Render()) else: self.send_error(404, "File not found: %s" % request_path) return # Do highlighting on the generated code (highlighter_param, style_param) = self._GetHighlighterParams(parsed_url) head.Append('<style>' + self.server.highlighters[highlighter_param].GetCSS( style_param) + '</style>') body.Append( self.server.highlighters[highlighter_param].GetCodeElement( cpp_code, style_param)) except IOError: self.send_error(404, "File not found: %s" % request_path) return except (TypeError, KeyError, AttributeError, AssertionError, NotImplementedError) as error: body.Append('<pre>') body.Append('compiler error: ' + str(error)) body.Append('Check server log for more details') body.Append('</pre>') raise
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 _GeneratePropertyFunctions(self, param_namespace, params): """Generate the functions for structures generated by a property such as CreateEnumValue for ENUMs and Populate/ToValue for Params/Results objects. """ c = Code() for param in params: if param.type_ == PropertyType.OBJECT: c.Concat( self._GenerateType( param_namespace + '::' + cpp_util.Classname(param.name), param)) c.Append() elif param.type_ == PropertyType.ARRAY: c.Concat( self._GeneratePropertyFunctions(param_namespace, [param.item_type])) elif param.type_ == PropertyType.CHOICES: c.Concat( self._GeneratePropertyFunctions(param_namespace, param.choices.values())) if param.from_client: c.Concat( self._GenerateGetChoiceValue(param_namespace, param)) elif param.type_ == PropertyType.ENUM: (c.Concat(self._GenerateCreateEnumValue( param_namespace, param)).Append().Concat( self._GenerateEnumFromString( param_namespace, param, use_namespace=True)).Append().Concat( self._GenerateEnumToString( param_namespace, param, use_namespace=True)).Append()) return c
def GetEnumValue(self, prop, enum_value): """Gets the enum value of the given model.Property of the given type. e.g VAR_STRING """ return '%s_%s' % (prop.unix_name.upper(), cpp_util.Classname(enum_value.upper()))
def _GenerateEnumToString(self, cpp_namespace, type_): """Generates ToString() which gets the string representation of an enum. """ c = Code() classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) if cpp_namespace is not None: c.Append('// static') maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace c.Sblock('std::string %sToString(%s enum_param) {' % (maybe_namespace, classname)) c.Sblock('switch (enum_param) {') for enum_value in self._type_helper.FollowRef(type_).enum_values: name = enum_value.name if 'camel_case_enum_to_string' in self._namespace.compiler_options: name = enum_value.CamelName() (c.Append('case %s: ' % self._type_helper.GetEnumValue(type_, enum_value)) .Append(' return "%s";' % name)) (c.Append('case %s:' % self._type_helper.GetEnumNoneValue(type_)) .Append(' return "";') .Eblock('}') .Append('NOTREACHED();') .Append('return "";') .Eblock('}') ) return c
def Generate(self): """Generates a code.Code object with the .cc for a single namespace. """ c = code.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.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 %s;' % any_helper.ANY_CLASS).Append().Concat( self._cpp_type_generator.GetRootNamespaceStart()).Concat( self._cpp_type_generator.GetNamespaceStart()).Append()) if self._namespace.types: (c.Append('//').Append('// Types').Append('//').Append()) for type_ in self._namespace.types.values(): (c.Concat(self._GenerateType(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 _ShowCompiledFile(self, parsed_url, head, body): """Show the compiled version of a json or idl file given the path to the compiled file. """ api_model = model.Model() request_path = self._GetRequestPath(parsed_url) (file_root, file_ext) = os.path.splitext(request_path) (filedir, filename) = os.path.split(file_root) try: # Get main file. (api_def, file_path) = self._LoadModel(filedir, filename) namespace = api_model.AddNamespace(api_def, file_path) type_generator = cpp_type_generator.CppTypeGenerator( api_model, schema_loader.SchemaLoader(filedir), namespace) # Get the model's dependencies. for dependency in api_def.get('dependencies', []): # Dependencies can contain : in which case they don't refer to APIs, # rather, permissions or manifest keys. if ':' in dependency: continue (api_def, file_path) = self._LoadModel(filedir, dependency) referenced_namespace = api_model.AddNamespace(api_def, file_path) if referenced_namespace: type_generator.AddNamespace(referenced_namespace, cpp_util.Classname(referenced_namespace.name).lower()) # Generate code cpp_namespace = 'generated_api_schemas' if file_ext == '.h': cpp_code = (h_generator.HGenerator(type_generator, cpp_namespace) .Generate(namespace).Render()) elif file_ext == '.cc': cpp_code = (cc_generator.CCGenerator(type_generator, cpp_namespace) .Generate(namespace).Render()) else: self.send_error(404, "File not found: %s" % request_path) return # Do highlighting on the generated code (highlighter_param, style_param) = self._GetHighlighterParams(parsed_url) head.Append('<style>' + self.server.highlighters[highlighter_param].GetCSS(style_param) + '</style>') body.Append(self.server.highlighters[highlighter_param] .GetCodeElement(cpp_code, style_param)) except IOError: self.send_error(404, "File not found: %s" % request_path) return except (TypeError, KeyError, AttributeError, AssertionError, NotImplementedError) as error: body.Append('<pre>') body.Append('compiler error: %s' % error) body.Append('Check server log for more details') body.Append('</pre>') raise
def _GenerateEvent(self, event): """Generates the namespaces for an event. """ c = Code() (c.Sblock('namespace %s {' % cpp_util.Classname(event.name)).Concat( self._GenerateCreateCallbackArguments(event)).Eblock('};')) return c
def _GenerateFunction(self, function): """Generates the definitions for function structs. """ c = Code() # TODO(kalman): use function.unix_name not Classname. function_namespace = cpp_util.Classname(function.name) # Windows has a #define for SendMessage, so to avoid any issues, we need # to not use the name. if function_namespace == 'SendMessage': function_namespace = 'PassMessage' (c.Append('namespace %s {' % function_namespace) .Append() ) # Params::Populate function if function.params: c.Concat(self._GeneratePropertyFunctions('Params', function.params)) (c.Append('Params::Params() {}') .Append('Params::~Params() {}') .Append() .Cblock(self._GenerateFunctionParamsCreate(function)) ) # Results::Create function if function.callback: c.Concat(self._GenerateCreateCallbackArguments('Results', function.callback)) c.Append('} // namespace %s' % function_namespace) return c
def _GenerateGetChoiceValue(self, cpp_namespace, prop): """Generates Get<Type>ChoiceValue() that returns a scoped_ptr<base::Value> representing the choice value. """ c = Code() (c.Sblock( 'scoped_ptr<base::Value> ' '%(cpp_namespace)s::Get%(choice)sChoiceValue() const {').Sblock( 'switch (%s_type) {' % prop.unix_name).Concat( self._GenerateReturnCase( self._cpp_type_generator.GetEnumNoneValue(prop), 'scoped_ptr<base::Value>()'))) for choice in self._cpp_type_generator.ExpandParams([prop]): c.Concat( self._GenerateReturnCase( self._cpp_type_generator.GetEnumValue( prop, choice.type_.name), 'make_scoped_ptr<base::Value>(%s)' % self._CreateValueFromProperty(choice, choice.unix_name))) (c.Eblock('}').Append('return scoped_ptr<base::Value>();').Eblock( '}').Append().Substitute({ 'cpp_namespace': cpp_namespace, 'choice': cpp_util.Classname(prop.name) })) return c
def _GenerateEnumFromString(self, cpp_namespace, type_): """Generates FromClassNameString() which gets an enum from its string representation. """ c = Code() classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) if cpp_namespace is not None: c.Append('// static') maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace c.Sblock('%s%s %sParse%s(const std::string& enum_string) {' % (maybe_namespace, classname, maybe_namespace, classname)) for _, enum_value in enumerate( self._type_helper.FollowRef(type_).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.name) .Append(' return %s;' % self._type_helper.GetEnumValue(type_, enum_value))) (c.Append('return %s;' % self._type_helper.GetEnumNoneValue(type_)) .Eblock('}') ) return c
def _GenerateEvent(self, event): # TODO(kalman): use event.unix_name not Classname. c = Code() event_namespace = cpp_util.Classname(event.name) (c.Append('namespace %s {' % event_namespace).Append().Cblock( self._GenerateCreateCallbackArguments(None, event)).Append( '} // namespace %s' % event_namespace)) return c
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 _CreateValueFromProperty(self, prop, var): """Creates a base::Value given a property. Generated code passes ownership to caller. var: variable or variable* E.g for std::string, generate base::Value::CreateStringValue(var) """ if prop.type_ == PropertyType.CHOICES: return 'Get%sChoiceValue().release()' % cpp_util.Classname( prop.name) elif self._IsObjectOrObjectRef(prop): if prop.optional: return '%s->ToValue().release()' % var else: return '%s.ToValue().release()' % var elif prop.type_ == PropertyType.ANY: return '%s.DeepCopy()' % self._any_helper.GetValue(prop, var) elif prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: return '%s.DeepCopy()' % var elif prop.type_ == PropertyType.FUNCTION: if prop.optional: vardot = var + '->' else: vardot = var + '.' return '%sDeepCopy()' % vardot elif self._cpp_type_generator.IsEnumOrEnumRef(prop): return 'base::Value::CreateStringValue(ToString(%s))' % var elif prop.type_ == PropertyType.BINARY: if prop.optional: vardot = var + '->' else: vardot = var + '.' return ( 'base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())' % (vardot, vardot)) elif self._IsArrayOrArrayRef(prop): return '%s.release()' % self._util_cc_helper.CreateValueFromArray( self._cpp_type_generator.GetReferencedProperty(prop), var, prop.optional) elif self._IsFundamentalOrFundamentalRef(prop): # If prop.type != prop.compiled_type, then no asterisk is necessary # because the target is a local variable and not a dereferenced scoped # pointer. The asterisk is instead prepended to conversion_src around line # 273. if prop.optional and prop.type_ == prop.compiled_type: var = '*' + var prop = self._cpp_type_generator.GetReferencedProperty(prop) return { PropertyType.STRING: 'base::Value::CreateStringValue(%s)', PropertyType.BOOLEAN: 'base::Value::CreateBooleanValue(%s)', PropertyType.INTEGER: 'base::Value::CreateIntegerValue(%s)', PropertyType.DOUBLE: 'base::Value::CreateDoubleValue(%s)', }[prop.type_] % var else: raise NotImplementedError('Conversion of %s to base::Value not ' 'implemented' % repr(prop.type_))
def _GenerateEvent(self, event): """Generates the namespaces for an event. """ c = Code() # TODO(kalman): use event.unix_name not Classname. event_namespace = cpp_util.Classname(event.name) (c.Append('namespace %s {' % event_namespace).Append().Concat( self._GenerateCreateCallbackArguments(event)).Eblock( '} // namespace %s' % event_namespace)) return c
def _GenerateType(self, cpp_namespace, type_): """Generates the function definitions for a type. """ 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: c.Cblock(self._GenerateType(cpp_namespace, type_.item_type)) elif type_.property_type in (PropertyType.CHOICES, PropertyType.OBJECT): if cpp_namespace is None: classname_in_namespace = classname else: classname_in_namespace = '%s::%s' % (cpp_namespace, classname) if type_.property_type == PropertyType.OBJECT: c.Cblock( self._GeneratePropertyFunctions(classname_in_namespace, type_.properties.values())) else: c.Cblock( self._GenerateTypes(classname_in_namespace, type_.choices)) (c.Append('%s::%s()' % (classname_in_namespace, classname)).Cblock( self._GenerateInitializersAndBody(type_)).Append( '%s::~%s() {}' % (classname_in_namespace, classname))) # Note: we use 'rhs' because some API objects have a member 'other'. (c.Append('%s::%s(%s&& rhs)' % (classname_in_namespace, classname, classname)).Cblock( self._GenerateMoveCtor(type_)).Append( '%s& %s::operator=(%s&& rhs)' % (classname_in_namespace, classname_in_namespace, classname)).Cblock( self._GenerateMoveAssignOperator(type_))) if type_.origin.from_json: c.Cblock( self._GenerateTypePopulate(classname_in_namespace, type_)) if cpp_namespace is None: # only generate for top-level types c.Cblock( self._GenerateTypeFromValue(classname_in_namespace, type_)) if type_.origin.from_client: c.Cblock( self._GenerateTypeToValue(classname_in_namespace, type_)) elif type_.property_type == PropertyType.ENUM: (c.Cblock(self._GenerateEnumToString(cpp_namespace, type_)).Cblock( self._GenerateEnumFromString(cpp_namespace, type_))) return c
def _GenerateFunction(self, function): """Generates the structs for a function. """ c = code.Code() (c.Sblock('namespace %s {' % cpp_util.Classname(function.name)).Concat( self._GenerateFunctionParams(function)).Append()) if function.callback: (c.Concat(self._GenerateFunctionResult(function)).Append()) c.Eblock('};') return c
def _GenerateEvent(self, event): """Generates the namespaces for an event. """ c = Code() # TODO(kalman): use event.unix_name not Classname. event_namespace = cpp_util.Classname(event.name) (c.Append('namespace %s {' % event_namespace).Append().Concat( self._GenerateEventNameConstant(event)).Concat( self._GenerateAsyncResponseArguments(event.params)).Append( '} // namespace %s' % event_namespace)) return c
def GetEnumValue(self, type_, enum_value): """Gets the enum value of the given model.Property of the given type. e.g VAR_STRING """ value = '%s_%s' % (self.FollowRef(type_).unix_name.upper(), cpp_util.Classname(enum_value.upper())) # To avoid collisions with built-in OS_* preprocessor definitions, we add a # trailing slash to enum names that start with OS_. if value.startswith("OS_"): value += "_" return value
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.StripNamespace(type_.name)) c = Code() (c.Append('// static').Append('bool %(namespace)s::Populate(').Sblock( ' const base::Value& value, %(name)s* out) {')) if type_.property_type == PropertyType.CHOICES: for choice in type_.choices: value_type = cpp_util.GetValueType( self._type_helper.FollowRef(choice)) (c.Sblock('if (value.IsType(%s)) {' % value_type).Concat( self._GeneratePopulateVariableFromValue( choice, '(&value)', 'out->as_%s' % choice.unix_name, 'false', is_ptr=True)).Append('return true;').Eblock('}')) c.Append('return false;') elif type_.property_type == PropertyType.OBJECT: (c.Append('if (!value.IsType(base::Value::TYPE_DICTIONARY))'). Append(' return false;')) if type_.properties or type_.additional_properties is not None: c.Append('const base::DictionaryValue* dict = ' 'static_cast<const base::DictionaryValue*>(&value);') for prop in type_.properties.values(): c.Concat(self._InitializePropertyToDefault(prop, 'out')) for prop in type_.properties.values(): c.Concat( self._GenerateTypePopulateProperty(prop, 'dict', 'out')) if type_.additional_properties is not None: if type_.additional_properties.property_type == PropertyType.ANY: c.Append( 'out->additional_properties.MergeDictionary(dict);') else: cpp_type = self._type_helper.GetCppType( type_.additional_properties, is_in_container=True) (c.Append('for (base::DictionaryValue::Iterator it(*dict);' ).Sblock(' !it.IsAtEnd(); it.Advance()) {'). Append('%s tmp;' % cpp_type).Concat( self._GeneratePopulateVariableFromValue( type_.additional_properties, '(&it.value())', 'tmp', 'false')).Append( 'out->additional_properties[it.key()] = tmp;' ).Eblock('}')) c.Append('return true;') (c.Eblock('}').Substitute({ 'namespace': cpp_namespace, 'name': classname })) return c
def _GenerateTypeFromValue(self, cpp_namespace, type_): classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) c = Code() (c.Append('// static').Append( 'scoped_ptr<%s> %s::FromValue(const base::Value& value) {' % (classname, cpp_namespace)).Append( ' scoped_ptr<%s> out(new %s());' % (classname, classname)).Append( ' if (!Populate(value, out.get()))').Append( ' return scoped_ptr<%s>();' % classname).Append(' return out.Pass();').Append('}')) return c
def _GenerateFunction(self, function): """Generates the namespaces and structs for a function. """ c = Code() # TODO(kalman): Use function.unix_name not Classname here. function_namespace = cpp_util.Classname(function.name) (c.Append('namespace %s {' % function_namespace).Append().Cblock( self._GenerateFunctionParams(function))) if function.callback: c.Cblock(self._GenerateFunctionResults(function.callback)) c.Append('} // namespace %s' % function_namespace) return c