h_generator.py revision 5821806d5e7f356e8fa4b058a389a808ea183019
1# Copyright (c) 2012 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5from code import Code 6from model import PropertyType 7import cpp_util 8import schema_util 9 10class HGenerator(object): 11 """A .h generator for a namespace. 12 """ 13 def __init__(self, namespace, cpp_type_generator): 14 self._cpp_type_generator = cpp_type_generator 15 self._namespace = namespace 16 self._target_namespace = ( 17 self._cpp_type_generator.GetCppNamespaceName(self._namespace)) 18 19 def Generate(self): 20 """Generates a Code object with the .h for a single namespace. 21 """ 22 c = Code() 23 (c.Append(cpp_util.CHROMIUM_LICENSE) 24 .Append() 25 .Append(cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file) 26 .Append() 27 ) 28 29 ifndef_name = cpp_util.GenerateIfndefName(self._namespace.source_file_dir, 30 self._target_namespace) 31 (c.Append('#ifndef %s' % ifndef_name) 32 .Append('#define %s' % ifndef_name) 33 .Append() 34 .Append('#include <string>') 35 .Append('#include <vector>') 36 .Append() 37 .Append('#include "base/basictypes.h"') 38 .Append('#include "base/logging.h"') 39 .Append('#include "base/memory/linked_ptr.h"') 40 .Append('#include "base/memory/scoped_ptr.h"') 41 .Append('#include "base/values.h"') 42 .Append('#include "tools/json_schema_compiler/any.h"') 43 .Append() 44 ) 45 46 c.Concat(self._cpp_type_generator.GetRootNamespaceStart()) 47 # TODO(calamity): These forward declarations should be #includes to allow 48 # $ref types from other files to be used as required params. This requires 49 # some detangling of windows and tabs which will currently lead to circular 50 # #includes. 51 forward_declarations = ( 52 self._cpp_type_generator.GenerateForwardDeclarations()) 53 if not forward_declarations.IsEmpty(): 54 (c.Append() 55 .Concat(forward_declarations) 56 .Append() 57 ) 58 59 c.Concat(self._cpp_type_generator.GetNamespaceStart()) 60 c.Append() 61 if self._namespace.properties: 62 (c.Append('//') 63 .Append('// Properties') 64 .Append('//') 65 .Append() 66 ) 67 for property in self._namespace.properties.values(): 68 property_code = self._cpp_type_generator.GeneratePropertyValues( 69 property, 70 'extern const %(type)s %(name)s;') 71 if property_code: 72 c.Concat(property_code).Append() 73 if self._namespace.types: 74 (c.Append('//') 75 .Append('// Types') 76 .Append('//') 77 .Append() 78 ) 79 for type_ in self._FieldDependencyOrder(): 80 (c.Concat(self._GenerateType(type_)) 81 .Append() 82 ) 83 if self._namespace.functions: 84 (c.Append('//') 85 .Append('// Functions') 86 .Append('//') 87 .Append() 88 ) 89 for function in self._namespace.functions.values(): 90 (c.Concat(self._GenerateFunction(function)) 91 .Append() 92 ) 93 if self._namespace.events: 94 (c.Append('//') 95 .Append('// Events') 96 .Append('//') 97 .Append() 98 ) 99 for event in self._namespace.events.values(): 100 (c.Concat(self._GenerateEvent(event)) 101 .Append() 102 ) 103 (c.Concat(self._cpp_type_generator.GetNamespaceEnd()) 104 .Concat(self._cpp_type_generator.GetRootNamespaceEnd()) 105 .Append() 106 .Append('#endif // %s' % ifndef_name) 107 .Append() 108 ) 109 return c 110 111 def _FieldDependencyOrder(self): 112 """Generates the list of types in the current namespace in an order in which 113 depended-upon types appear before types which depend on them. 114 """ 115 dependency_order = [] 116 117 def ExpandType(path, type_): 118 if type_ in path: 119 raise ValueError("Illegal circular dependency via cycle " + 120 ", ".join(map(lambda x: x.name, path + [type_]))) 121 for prop in type_.properties.values(): 122 if (prop.type_ == PropertyType.REF and 123 schema_util.GetNamespace(prop.ref_type) == self._namespace.name): 124 ExpandType(path + [type_], self._namespace.types[prop.ref_type]) 125 if not type_ in dependency_order: 126 dependency_order.append(type_) 127 128 for type_ in self._namespace.types.values(): 129 ExpandType([], type_) 130 return dependency_order 131 132 def _GenerateEnumDeclaration(self, enum_name, prop, values): 133 """Generate the declaration of a C++ enum for the given property and 134 values. 135 """ 136 c = Code() 137 c.Sblock('enum %s {' % enum_name) 138 c.Append(self._cpp_type_generator.GetEnumNoneValue(prop) + ',') 139 for value in values: 140 c.Append(self._cpp_type_generator.GetEnumValue(prop, value) + ',') 141 (c.Eblock('};') 142 .Append() 143 ) 144 return c 145 146 def _GenerateFields(self, props): 147 """Generates the field declarations when declaring a type. 148 """ 149 c = Code() 150 # Generate the enums needed for any fields with "choices" 151 for prop in props: 152 if prop.type_ == PropertyType.CHOICES: 153 enum_name = self._cpp_type_generator.GetChoicesEnumType(prop) 154 c.Append('%s %s_type;' % (enum_name, prop.unix_name)) 155 c.Append() 156 157 for prop in self._cpp_type_generator.ExpandParams(props): 158 if prop.description: 159 c.Comment(prop.description) 160 (c.Append('%s %s;' % ( 161 self._cpp_type_generator.GetCompiledType(prop, wrap_optional=True), 162 prop.unix_name)) 163 .Append() 164 ) 165 return c 166 167 def _GenerateType(self, type_): 168 """Generates a struct for a type. 169 """ 170 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name)) 171 c = Code() 172 173 if type_.functions: 174 c.Sblock('namespace %(classname)s {') 175 for function in type_.functions.values(): 176 (c.Concat(self._GenerateFunction(function)) 177 .Append() 178 ) 179 c.Eblock('}') 180 elif type_.type_ == PropertyType.ARRAY: 181 if type_.description: 182 c.Comment(type_.description) 183 c.Append('typedef std::vector<%(item_type)s> %(classname)s;') 184 c.Substitute({'classname': classname, 'item_type': 185 self._cpp_type_generator.GetCompiledType(type_.item_type, 186 wrap_optional=True)}) 187 elif type_.type_ == PropertyType.STRING: 188 if type_.description: 189 c.Comment(type_.description) 190 c.Append('typedef std::string %(classname)s;') 191 elif type_.type_ == PropertyType.ENUM: 192 if type_.description: 193 c.Comment(type_.description) 194 c.Sblock('enum %(classname)s {') 195 c.Append('%s,' % self._cpp_type_generator.GetEnumNoneValue(type_)) 196 for value in type_.enum_values: 197 c.Append('%s,' % self._cpp_type_generator.GetEnumValue(type_, value)) 198 (c.Eblock('};') 199 .Append() 200 .Append('scoped_ptr<base::Value> CreateEnumValue(%s %s);' % 201 (classname, classname.lower())) 202 .Append('std::string ToString(%s enum_param);' % classname) 203 .Append('%s From%sString(const std::string& enum_string);' % 204 (classname, classname)) 205 ) 206 else: 207 if type_.description: 208 c.Comment(type_.description) 209 (c.Sblock('struct %(classname)s {') 210 .Append('~%(classname)s();') 211 .Append('%(classname)s();') 212 .Append() 213 .Concat(self._GeneratePropertyStructures(type_.properties.values())) 214 .Concat(self._GenerateFields(type_.properties.values())) 215 ) 216 if type_.from_json: 217 (c.Comment('Populates a %s object from a base::Value. Returns' 218 ' whether |out| was successfully populated.' % classname) 219 .Append('static bool Populate(const base::Value& value, ' 220 '%(classname)s* out);') 221 .Append() 222 ) 223 224 if type_.from_client: 225 (c.Comment('Returns a new base::DictionaryValue representing the' 226 ' serialized form of this %s object. Passes ' 227 'ownership to caller.' % classname) 228 .Append('scoped_ptr<base::DictionaryValue> ToValue() const;') 229 ) 230 231 (c.Eblock() 232 .Sblock(' private:') 233 .Concat(self._GeneratePrivatePropertyStructures( 234 type_.properties.values())) 235 .Append() 236 .Append('DISALLOW_COPY_AND_ASSIGN(%(classname)s);') 237 .Eblock('};') 238 ) 239 c.Substitute({'classname': classname}) 240 return c 241 242 def _GenerateEvent(self, event): 243 """Generates the namespaces for an event. 244 """ 245 c = Code() 246 (c.Sblock('namespace %s {' % cpp_util.Classname(event.name)) 247 .Concat(self._GenerateCreateCallbackArguments(event, 248 generate_to_json=True)) 249 .Eblock('};') 250 ) 251 return c 252 253 def _GenerateFunction(self, function): 254 """Generates the namespaces and structs for a function. 255 """ 256 c = Code() 257 (c.Sblock('namespace %s {' % cpp_util.Classname(function.name)) 258 .Concat(self._GenerateFunctionParams(function)) 259 .Append() 260 ) 261 if function.callback: 262 (c.Concat(self._GenerateFunctionResults(function.callback)) 263 .Append() 264 ) 265 c.Eblock('};') 266 267 return c 268 269 def _GenerateFunctionParams(self, function): 270 """Generates the struct for passing parameters from JSON to a function. 271 """ 272 c = Code() 273 274 if function.params: 275 (c.Sblock('struct Params {') 276 .Concat(self._GeneratePropertyStructures(function.params)) 277 .Concat(self._GenerateFields(function.params)) 278 .Append('~Params();') 279 .Append() 280 .Append('static scoped_ptr<Params> Create(' 281 'const base::ListValue& args);') 282 .Eblock() 283 .Sblock(' private:') 284 .Append('Params();') 285 .Append() 286 .Append('DISALLOW_COPY_AND_ASSIGN(Params);') 287 .Eblock('};') 288 ) 289 290 return c 291 292 def _GeneratePropertyStructures(self, props): 293 """Generate the structures required by a property such as OBJECT classes 294 and enums. 295 """ 296 c = Code() 297 for prop in props: 298 if prop.type_ == PropertyType.OBJECT: 299 c.Concat(self._GenerateType(prop)) 300 c.Append() 301 elif prop.type_ == PropertyType.ARRAY: 302 c.Concat(self._GeneratePropertyStructures([prop.item_type])) 303 c.Append() 304 elif prop.type_ == PropertyType.CHOICES: 305 c.Concat(self._GenerateEnumDeclaration( 306 self._cpp_type_generator.GetChoicesEnumType(prop), 307 prop, 308 [choice.type_.name for choice in prop.choices.values()])) 309 c.Concat(self._GeneratePropertyStructures(prop.choices.values())) 310 elif prop.type_ == PropertyType.ENUM: 311 enum_name = self._cpp_type_generator.GetCompiledType(prop) 312 c.Concat(self._GenerateEnumDeclaration( 313 enum_name, 314 prop, 315 prop.enum_values)) 316 create_enum_value = ('scoped_ptr<base::Value> CreateEnumValue(%s %s);' % 317 (enum_name, prop.unix_name)) 318 enum_to_string = 'std::string ToString(%s enum_param);' % enum_name 319 enum_from_string = ('%s From%sString(const std::string& enum_string);' % 320 (enum_name, enum_name)) 321 # If the property is from the UI then we're in a struct so this function 322 # should be static. If it's from the client, then we're just in a 323 # namespace so we can't have the static keyword. 324 if prop.from_json: 325 create_enum_value = 'static %s' % create_enum_value 326 enum_to_string = 'static %s' % enum_to_string 327 enum_from_string = 'static %s' % enum_from_string 328 (c.Append(create_enum_value) 329 .Append(enum_to_string) 330 .Append(enum_from_string)) 331 return c 332 333 def _GeneratePrivatePropertyStructures(self, props): 334 """Generate the private structures required by a property such as OBJECT 335 classes and enums. 336 """ 337 c = Code() 338 for prop in props: 339 if prop.type_ == PropertyType.ARRAY: 340 c.Concat(self._GeneratePrivatePropertyStructures([prop.item_type])) 341 c.Append() 342 elif prop.type_ == PropertyType.CHOICES: 343 # We only need GetChoiceValue() if there is a ToValue() method. 344 if prop.from_client: 345 c.Append('scoped_ptr<base::Value> Get%sChoiceValue() const;' % ( 346 cpp_util.Classname(prop.name))) 347 return c 348 349 def _GenerateCreateCallbackArguments(self, function, generate_to_json=False): 350 """Generates functions for passing paramaters to a callback. 351 """ 352 c = Code() 353 params = function.params 354 c.Concat(self._GeneratePropertyStructures(params)) 355 356 param_lists = self._cpp_type_generator.GetAllPossibleParameterLists(params) 357 for param_list in param_lists: 358 declaration_list = [] 359 for param in param_list: 360 if param.description: 361 c.Comment(param.description) 362 declaration_list.append('const %s' % cpp_util.GetParameterDeclaration( 363 param, self._cpp_type_generator.GetCompiledType(param))) 364 c.Append('scoped_ptr<base::ListValue> Create(%s);' % 365 ', '.join(declaration_list)) 366 if generate_to_json: 367 c.Append('std::string ToJson(%s);' % ', '.join(declaration_list)) 368 return c 369 370 def _GenerateFunctionResults(self, callback): 371 """Generates namespace for passing a function's result back. 372 """ 373 c = Code() 374 (c.Sblock('namespace Results {') 375 .Concat(self._GenerateCreateCallbackArguments(callback)) 376 .Eblock('};') 377 ) 378 return c 379