cc_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 any_helper 8import cpp_util 9import model 10import schema_util 11import sys 12import util_cc_helper 13 14class CCGenerator(object): 15 """A .cc generator for a namespace. 16 """ 17 def __init__(self, namespace, cpp_type_generator): 18 self._cpp_type_generator = cpp_type_generator 19 self._namespace = namespace 20 self._target_namespace = ( 21 self._cpp_type_generator.GetCppNamespaceName(self._namespace)) 22 self._util_cc_helper = ( 23 util_cc_helper.UtilCCHelper(self._cpp_type_generator)) 24 self._any_helper = any_helper.AnyHelper() 25 26 def Generate(self): 27 """Generates a Code object with the .cc for a single namespace. 28 """ 29 c = Code() 30 (c.Append(cpp_util.CHROMIUM_LICENSE) 31 .Append() 32 .Append(cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file) 33 .Append() 34 .Append(self._util_cc_helper.GetIncludePath()) 35 .Append('#include "%s/%s.h"' % 36 (self._namespace.source_file_dir, self._namespace.unix_name)) 37 ) 38 includes = self._cpp_type_generator.GenerateIncludes() 39 if not includes.IsEmpty(): 40 (c.Concat(includes) 41 .Append() 42 ) 43 44 (c.Append() 45 .Concat(self._cpp_type_generator.GetRootNamespaceStart()) 46 .Concat(self._cpp_type_generator.GetNamespaceStart()) 47 .Append() 48 ) 49 if self._namespace.properties: 50 (c.Append('//') 51 .Append('// Properties') 52 .Append('//') 53 .Append() 54 ) 55 for property in self._namespace.properties.values(): 56 property_code = self._cpp_type_generator.GeneratePropertyValues( 57 property, 58 'const %(type)s %(name)s = %(value)s;', 59 nodoc=True) 60 if property_code: 61 c.Concat(property_code).Append() 62 if self._namespace.types: 63 (c.Append('//') 64 .Append('// Types') 65 .Append('//') 66 .Append() 67 ) 68 for type_ in self._namespace.types.values(): 69 (c.Concat(self._GenerateType( 70 schema_util.StripSchemaNamespace(type_.name), type_)).Append() 71 ) 72 if self._namespace.functions: 73 (c.Append('//') 74 .Append('// Functions') 75 .Append('//') 76 .Append() 77 ) 78 for function in self._namespace.functions.values(): 79 (c.Concat(self._GenerateFunction( 80 cpp_util.Classname(function.name), function)) 81 .Append() 82 ) 83 if self._namespace.events: 84 (c.Append('//') 85 .Append('// Events') 86 .Append('//') 87 .Append() 88 ) 89 for event in self._namespace.events.values(): 90 (c.Concat(self._GenerateCreateCallbackArguments( 91 cpp_util.Classname(event.name), event, generate_to_json=True)) 92 .Append() 93 ) 94 (c.Concat(self._cpp_type_generator.GetNamespaceEnd()) 95 .Concat(self._cpp_type_generator.GetRootNamespaceEnd()) 96 .Append() 97 ) 98 return c 99 100 def _GenerateType(self, cpp_namespace, type_): 101 """Generates the function definitions for a type. 102 """ 103 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name)) 104 c = Code() 105 106 if type_.functions: 107 for function in type_.functions.values(): 108 (c.Concat( 109 self._GenerateFunction( 110 cpp_namespace + '::' + cpp_util.Classname(function.name), 111 function)) 112 .Append()) 113 elif type_.type_ == PropertyType.OBJECT: 114 (c.Concat(self._GeneratePropertyFunctions( 115 cpp_namespace, type_.properties.values())) 116 .Sblock('%(namespace)s::%(classname)s()') 117 .Concat(self._GenerateInitializersAndBody(type_)) 118 .Eblock('%(namespace)s::~%(classname)s() {}') 119 .Append()) 120 if type_.from_json: 121 (c.Concat(self._GenerateTypePopulate(cpp_namespace, type_)) 122 .Append()) 123 if type_.from_client: 124 (c.Concat(self._GenerateTypeToValue(cpp_namespace, type_)) 125 .Append()) 126 elif self._cpp_type_generator.IsEnumOrEnumRef(type_): 127 (c.Concat(self._GenerateCreateEnumTypeValue(cpp_namespace, type_)) 128 .Append() 129 .Concat(self._GenerateEnumFromString(cpp_namespace, type_)) 130 .Append() 131 .Concat(self._GenerateEnumToString(cpp_namespace, type_)) 132 .Append()) 133 c.Substitute({'classname': classname, 'namespace': cpp_namespace}) 134 135 return c 136 137 def _GenerateInitializersAndBody(self, type_): 138 items = [] 139 for prop in type_.properties.values(): 140 if prop.optional: 141 continue 142 143 t = prop.type_ 144 if t == PropertyType.INTEGER: 145 items.append('%s(0)' % prop.unix_name) 146 elif t == PropertyType.DOUBLE: 147 items.append('%s(0.0)' % prop.unix_name) 148 elif t == PropertyType.BOOLEAN: 149 items.append('%s(false)' % prop.unix_name) 150 elif t == PropertyType.BINARY: 151 items.append('%s(NULL)' % prop.unix_name) 152 elif (t == PropertyType.ADDITIONAL_PROPERTIES or 153 t == PropertyType.ANY or 154 t == PropertyType.ARRAY or 155 t == PropertyType.CHOICES or 156 t == PropertyType.ENUM or 157 t == PropertyType.OBJECT or 158 t == PropertyType.FUNCTION or 159 t == PropertyType.REF or 160 t == PropertyType.STRING): 161 # TODO(miket): It would be nice to initialize CHOICES and ENUM, but we 162 # don't presently have the semantics to indicate which one of a set 163 # should be the default. 164 continue 165 else: 166 sys.exit("Unhandled PropertyType: %s" % t) 167 168 if items: 169 s = ': %s' % (', '.join(items)) 170 else: 171 s = '' 172 s = s + ' {}' 173 return Code().Append(s) 174 175 def _GenerateTypePopulate(self, cpp_namespace, type_): 176 """Generates the function for populating a type given a pointer to it. 177 178 E.g for type "Foo", generates Foo::Populate() 179 """ 180 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name)) 181 c = Code() 182 (c.Append('// static') 183 .Sblock('bool %(namespace)s::Populate' 184 '(const base::Value& value, %(name)s* out) {') 185 .Append('if (!value.IsType(base::Value::TYPE_DICTIONARY))') 186 .Append(' return false;') 187 ) 188 if type_.properties: 189 (c.Append('const base::DictionaryValue* dict = ' 190 'static_cast<const base::DictionaryValue*>(&value);') 191 .Append() 192 ) 193 for prop in type_.properties.values(): 194 c.Concat(self._InitializePropertyToDefault(prop, 'out')) 195 for prop in type_.properties.values(): 196 if prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: 197 c.Append('out->additional_properties.MergeDictionary(dict);') 198 # remove all keys that are actual properties 199 for cur_prop in type_.properties.values(): 200 if prop != cur_prop: 201 c.Append('out->additional_properties' 202 '.RemoveWithoutPathExpansion("%s", NULL);' % cur_prop.name) 203 c.Append() 204 else: 205 c.Concat(self._GenerateTypePopulateProperty(prop, 'dict', 'out')) 206 (c.Append('return true;') 207 .Eblock('}') 208 ) 209 c.Substitute({'namespace': cpp_namespace, 'name': classname}) 210 return c 211 212 def _GenerateTypePopulateProperty(self, prop, src, dst): 213 """Generate the code to populate a single property in a type. 214 215 src: base::DictionaryValue* 216 dst: Type* 217 """ 218 c = Code() 219 value_var = prop.unix_name + '_value' 220 c.Append('const base::Value* %(value_var)s = NULL;') 221 if prop.optional: 222 (c.Sblock( 223 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {') 224 .Concat(self._GeneratePopulatePropertyFromValue( 225 prop, value_var, dst, 'false'))) 226 if self._cpp_type_generator.IsEnumOrEnumRef(prop): 227 (c.Append('} else {') 228 .Append('%%(dst)s->%%(name)s = %s;' % 229 self._cpp_type_generator.GetEnumNoneValue(prop))) 230 c.Eblock('}') 231 else: 232 (c.Append( 233 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))') 234 .Append(' return false;') 235 .Concat(self._GeneratePopulatePropertyFromValue( 236 prop, value_var, dst, 'false')) 237 ) 238 c.Append() 239 c.Substitute({ 240 'value_var': value_var, 241 'key': prop.name, 242 'src': src, 243 'dst': dst, 244 'name': prop.unix_name 245 }) 246 return c 247 248 def _GenerateTypeToValue(self, cpp_namespace, type_): 249 """Generates a function that serializes the type into a 250 |base::DictionaryValue|. 251 252 E.g. for type "Foo" generates Foo::ToValue() 253 """ 254 c = Code() 255 (c.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' % 256 cpp_namespace) 257 .Append('scoped_ptr<base::DictionaryValue> value(' 258 'new base::DictionaryValue());') 259 .Append() 260 ) 261 for prop in type_.properties.values(): 262 if prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: 263 c.Append('value->MergeDictionary(&%s);' % prop.unix_name) 264 else: 265 if prop.optional: 266 if self._cpp_type_generator.IsEnumOrEnumRef(prop): 267 c.Sblock('if (%s != %s) {' % 268 (prop.unix_name, 269 self._cpp_type_generator.GetEnumNoneValue(prop))) 270 elif prop.type_ == PropertyType.CHOICES: 271 c.Sblock('if (%s_type != %s) {' % 272 (prop.unix_name, 273 self._cpp_type_generator.GetEnumNoneValue(prop))) 274 else: 275 c.Sblock('if (%s.get()) {' % prop.unix_name) 276 277 if prop.type_ == prop.compiled_type: 278 c.Append('value->SetWithoutPathExpansion("%s", %s);' % ( 279 prop.name, 280 self._CreateValueFromProperty(prop, 'this->' + prop.unix_name))) 281 else: 282 conversion_src = 'this->' + prop.unix_name 283 if prop.optional: 284 conversion_src = '*' + conversion_src 285 (c.Append('%s %s;' % (self._cpp_type_generator.GetType(prop), 286 prop.unix_name)) 287 .Append(cpp_util.GenerateCompiledTypeToTypeConversion( 288 self._cpp_type_generator.GetReferencedProperty(prop), 289 conversion_src, 290 prop.unix_name) + ';') 291 .Append('value->SetWithoutPathExpansion("%s", %s);' % ( 292 prop.unix_name, 293 self._CreateValueFromProperty(prop, prop.unix_name))) 294 ) 295 if prop.optional: 296 c.Eblock('}'); 297 (c.Append() 298 .Append('return value.Pass();') 299 .Eblock('}') 300 ) 301 return c 302 303 def _GenerateFunction(self, cpp_namespace, function): 304 """Generates the definitions for function structs. 305 """ 306 c = Code() 307 308 # Params::Populate function 309 if function.params: 310 c.Concat(self._GeneratePropertyFunctions(cpp_namespace + '::Params', 311 function.params)) 312 (c.Append('%(cpp_namespace)s::Params::Params() {}') 313 .Append('%(cpp_namespace)s::Params::~Params() {}') 314 .Append() 315 .Concat(self._GenerateFunctionParamsCreate(cpp_namespace, function)) 316 .Append() 317 ) 318 319 # Results::Create function 320 if function.callback: 321 c.Concat(self._GenerateCreateCallbackArguments( 322 "%s::Results" % cpp_namespace, function.callback)) 323 324 c.Substitute({'cpp_namespace': cpp_namespace}) 325 326 return c 327 328 def _CreateValueFromProperty(self, prop, var): 329 """Creates a base::Value given a property. Generated code passes ownership 330 to caller. 331 332 var: variable or variable* 333 334 E.g for std::string, generate base::Value::CreateStringValue(var) 335 """ 336 if prop.type_ == PropertyType.CHOICES: 337 return 'Get%sChoiceValue().release()' % cpp_util.Classname(prop.name) 338 elif self._IsObjectOrObjectRef(prop): 339 if prop.optional: 340 return '%s->ToValue().release()' % var 341 else: 342 return '%s.ToValue().release()' % var 343 elif prop.type_ == PropertyType.ANY: 344 return '%s.DeepCopy()' % self._any_helper.GetValue(prop, var) 345 elif prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: 346 return '%s.DeepCopy()' % var 347 elif prop.type_ == PropertyType.FUNCTION: 348 if prop.optional: 349 vardot = var + '->' 350 else: 351 vardot = var + '.' 352 return '%sDeepCopy()' % vardot 353 elif self._cpp_type_generator.IsEnumOrEnumRef(prop): 354 return 'base::Value::CreateStringValue(ToString(%s))' % var 355 elif prop.type_ == PropertyType.BINARY: 356 if prop.optional: 357 vardot = var + '->' 358 else: 359 vardot = var + '.' 360 return ('base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())' % 361 (vardot, vardot)) 362 elif self._IsArrayOrArrayRef(prop): 363 return '%s.release()' % self._util_cc_helper.CreateValueFromArray( 364 self._cpp_type_generator.GetReferencedProperty(prop), var, 365 prop.optional) 366 elif self._IsFundamentalOrFundamentalRef(prop): 367 # If prop.type != prop.compiled_type, then no asterisk is necessary 368 # because the target is a local variable and not a dereferenced scoped 369 # pointer. The asterisk is instead prepended to conversion_src around line 370 # 273. 371 if prop.optional and prop.type_ == prop.compiled_type: 372 var = '*' + var 373 prop = self._cpp_type_generator.GetReferencedProperty(prop); 374 return { 375 PropertyType.STRING: 'base::Value::CreateStringValue(%s)', 376 PropertyType.BOOLEAN: 'base::Value::CreateBooleanValue(%s)', 377 PropertyType.INTEGER: 'base::Value::CreateIntegerValue(%s)', 378 PropertyType.DOUBLE: 'base::Value::CreateDoubleValue(%s)', 379 }[prop.type_] % var 380 else: 381 raise NotImplementedError('Conversion of %s to base::Value not ' 382 'implemented' % repr(prop.type_)) 383 384 def _GenerateParamsCheck(self, function, var): 385 """Generates a check for the correct number of arguments when creating 386 Params. 387 """ 388 c = Code() 389 num_required = 0 390 for param in function.params: 391 if not param.optional: 392 num_required += 1 393 if num_required == len(function.params): 394 c.Append('if (%(var)s.GetSize() != %(total)d)') 395 elif not num_required: 396 c.Append('if (%(var)s.GetSize() > %(total)d)') 397 else: 398 c.Append('if (%(var)s.GetSize() < %(required)d' 399 ' || %(var)s.GetSize() > %(total)d)') 400 c.Append(' return scoped_ptr<Params>();') 401 c.Substitute({ 402 'var': var, 403 'required': num_required, 404 'total': len(function.params), 405 }) 406 return c 407 408 def _GenerateFunctionParamsCreate(self, cpp_namespace, function): 409 """Generate function to create an instance of Params. The generated 410 function takes a base::ListValue of arguments. 411 412 E.g for function "Bar", generate Bar::Params::Create() 413 """ 414 c = Code() 415 (c.Append('// static') 416 .Sblock('scoped_ptr<%(cpp_namespace)s::Params> ' 417 '%(cpp_namespace)s::Params::Create(const base::ListValue& args) {') 418 .Concat(self._GenerateParamsCheck(function, 'args')) 419 .Append('scoped_ptr<Params> params(new Params());') 420 ) 421 c.Substitute({'cpp_namespace': cpp_namespace}) 422 423 for param in function.params: 424 c.Concat(self._InitializePropertyToDefault(param, 'params')) 425 426 for i, param in enumerate(function.params): 427 # Any failure will cause this function to return. If any argument is 428 # incorrect or missing, those following it are not processed. Note that 429 # for optional arguments, we allow missing arguments and proceed because 430 # there may be other arguments following it. 431 failure_value = 'scoped_ptr<Params>()' 432 c.Append() 433 value_var = param.unix_name + '_value' 434 (c.Append('const base::Value* %(value_var)s = NULL;') 435 .Append('if (args.Get(%(i)s, &%(value_var)s) &&\n' 436 ' !%(value_var)s->IsType(base::Value::TYPE_NULL))') 437 .Sblock('{') 438 .Concat(self._GeneratePopulatePropertyFromValue( 439 param, value_var, 'params', failure_value)) 440 .Eblock('}') 441 ) 442 if not param.optional: 443 (c.Sblock('else {') 444 .Append('return %s;' % failure_value) 445 .Eblock('}') 446 ) 447 c.Substitute({'value_var': value_var, 'i': i}) 448 (c.Append() 449 .Append('return params.Pass();') 450 .Eblock('}') 451 .Append() 452 ) 453 454 return c 455 456 def _GeneratePopulatePropertyFromValue( 457 self, prop, value_var, dst, failure_value, check_type=True): 458 """Generates code to populate a model.Property given a base::Value*. The 459 existence of data inside the base::Value* is assumed so checks for existence 460 should be performed before the code this generates. 461 462 prop: the property the code is populating. 463 value_var: a base::Value* that should represent |prop|. 464 dst: the object with |prop| as a member. 465 failure_value: the value to return if |prop| cannot be extracted from 466 |value_var| 467 check_type: if true, will check if |value_var| is the correct 468 base::Value::Type 469 """ 470 c = Code() 471 c.Sblock('{') 472 473 if self._IsFundamentalOrFundamentalRef(prop): 474 self._GenerateFundamentalOrFundamentalRefPopulate(c, prop, value_var, dst) 475 elif self._IsObjectOrObjectRef(prop): 476 self._GenerateObjectOrObjectRefPopulate(c, prop) 477 elif prop.type_ == PropertyType.FUNCTION: 478 self._GenerateFunctionPopulate(c, prop) 479 elif prop.type_ == PropertyType.ANY: 480 self._GenerateAnyPopulate(c, prop, value_var, dst) 481 elif self._IsArrayOrArrayRef(prop): 482 self._GenerateArrayOrArrayRefPopulate(c, prop, dst) 483 elif prop.type_ == PropertyType.CHOICES: 484 self._GenerateChoicePopulate(c, prop, value_var, dst, failure_value) 485 elif self._cpp_type_generator.IsEnumOrEnumRef(prop): 486 self._GenerateEnumPopulate(c, prop, value_var) 487 elif prop.type_ == PropertyType.BINARY: 488 self._GenerateBinaryPopulate(c, prop) 489 else: 490 raise NotImplementedError(prop.type_) 491 c.Eblock('}') 492 sub = { 493 'value_var': value_var, 494 'name': prop.unix_name, 495 'dst': dst, 496 'failure_value': failure_value, 497 } 498 if prop.type_ not in (PropertyType.CHOICES, PropertyType.ANY): 499 sub['ctype'] = self._cpp_type_generator.GetType(prop) 500 sub['compiled_ctype'] = self._cpp_type_generator.GetCompiledType(prop) 501 sub['value_type'] = cpp_util.GetValueType(self._cpp_type_generator 502 .GetReferencedProperty(prop).type_) 503 c.Substitute(sub) 504 return c 505 506 def _GenerateFundamentalOrFundamentalRefPopulate(self, 507 c, 508 prop, 509 value_var, 510 dst): 511 if prop.optional: 512 (c.Append('%(ctype)s temp;') 513 .Append('if (!%s)' % 514 cpp_util.GetAsFundamentalValue( 515 self._cpp_type_generator.GetReferencedProperty(prop), 516 value_var, 517 '&temp')) 518 .Append(' return %(failure_value)s;') 519 ) 520 if prop.type_ != prop.compiled_type: 521 (c.Append('%(compiled_ctype)s temp2;') 522 .Append('if (!%s)' % 523 cpp_util.GenerateTypeToCompiledTypeConversion( 524 self._cpp_type_generator.GetReferencedProperty(prop), 525 'temp', 526 'temp2')) 527 .Append(' return %(failure_value)s;') 528 .Append('%(dst)s->%(name)s.reset(new %(compiled_ctype)s(temp2));') 529 ) 530 else: 531 c.Append('%(dst)s->%(name)s.reset(new %(ctype)s(temp));') 532 533 else: 534 if prop.type_ == prop.compiled_type: 535 assignment_target = '&%s->%s' % (dst, prop.unix_name) 536 else: 537 c.Append('%(ctype)s temp;') 538 assignment_target = '&temp' 539 (c.Append('if (!%s)' % 540 cpp_util.GetAsFundamentalValue( 541 self._cpp_type_generator.GetReferencedProperty(prop), 542 value_var, 543 assignment_target)) 544 .Append(' return %(failure_value)s;') 545 ) 546 if prop.type_ != prop.compiled_type: 547 (c.Append('if (!%s)' % 548 cpp_util.GenerateTypeToCompiledTypeConversion( 549 self._cpp_type_generator.GetReferencedProperty(prop), 550 'temp', 551 '%s->%s' % (dst, prop.unix_name))) 552 .Append(' return %(failure_value)s;') 553 ) 554 555 def _GenerateObjectOrObjectRefPopulate(self, c, prop): 556 if prop.optional: 557 (c.Append('const base::DictionaryValue* dictionary = NULL;') 558 .Append('if (!%(value_var)s->GetAsDictionary(&dictionary))') 559 .Append(' return %(failure_value)s;') 560 .Append('scoped_ptr<%(ctype)s> temp(new %(ctype)s());') 561 .Append('if (!%(ctype)s::Populate(*dictionary, temp.get()))') 562 .Append(' return %(failure_value)s;') 563 .Append('%(dst)s->%(name)s = temp.Pass();') 564 ) 565 else: 566 (c.Append('const base::DictionaryValue* dictionary = NULL;') 567 .Append('if (!%(value_var)s->GetAsDictionary(&dictionary))') 568 .Append(' return %(failure_value)s;') 569 .Append( 570 'if (!%(ctype)s::Populate(*dictionary, &%(dst)s->%(name)s))') 571 .Append(' return %(failure_value)s;') 572 ) 573 574 def _GenerateFunctionPopulate(self, c, prop): 575 if prop.optional: 576 c.Append('%(dst)s->%(name)s.reset(new base::DictionaryValue());') 577 578 def _GenerateAnyPopulate(self, c, prop, value_var, dst): 579 if prop.optional: 580 c.Append('%(dst)s->%(name)s.reset(new ' + any_helper.ANY_CLASS + '());') 581 c.Append(self._any_helper.Init(prop, value_var, dst) + ';') 582 583 def _GenerateArrayOrArrayRefPopulate(self, c, prop, dst): 584 # util_cc_helper deals with optional and required arrays 585 (c.Append('const base::ListValue* list = NULL;') 586 .Append('if (!%(value_var)s->GetAsList(&list))') 587 .Append(' return %(failure_value)s;')) 588 if prop.item_type.type_ == PropertyType.ENUM: 589 self._GenerateListValueToEnumArrayConversion(c, prop) 590 else: 591 (c.Append('if (!%s)' % self._util_cc_helper.PopulateArrayFromList( 592 self._cpp_type_generator.GetReferencedProperty(prop), 'list', 593 dst + '->' + prop.unix_name, prop.optional)) 594 .Append(' return %(failure_value)s;') 595 ) 596 597 def _GenerateChoicePopulate(self, c, prop, value_var, dst, failure_value): 598 type_var = '%(dst)s->%(name)s_type' 599 c.Sblock('switch (%(value_var)s->GetType()) {') 600 for choice in self._cpp_type_generator.ExpandParams([prop]): 601 (c.Sblock('case %s: {' % cpp_util.GetValueType( 602 self._cpp_type_generator.GetReferencedProperty(choice).type_)) 603 .Concat(self._GeneratePopulatePropertyFromValue( 604 choice, value_var, dst, failure_value, check_type=False)) 605 .Append('%s = %s;' % 606 (type_var, 607 self._cpp_type_generator.GetEnumValue( 608 prop, choice.type_.name))) 609 .Append('break;') 610 .Eblock('}') 611 ) 612 (c.Append('default:') 613 .Append(' return %(failure_value)s;') 614 ) 615 c.Eblock('}') 616 617 def _GenerateEnumPopulate(self, c, prop, value_var): 618 c.Sblock('{') 619 self._GenerateStringToEnumConversion(c, prop, value_var, 'enum_temp') 620 c.Append('%(dst)s->%(name)s = enum_temp;') 621 c.Eblock('}') 622 623 def _GenerateBinaryPopulate(self, c, prop): 624 (c.Append('if (!%(value_var)s->IsType(%(value_type)s))') 625 .Append(' return %(failure_value)s;') 626 .Append('const base::BinaryValue* binary_value =') 627 .Append(' static_cast<const base::BinaryValue*>(%(value_var)s);') 628 ) 629 if prop.optional: 630 (c.Append('%(dst)s->%(name)s.reset(') 631 .Append(' new std::string(binary_value->GetBuffer(),') 632 .Append(' binary_value->GetSize()));') 633 ) 634 else: 635 (c.Append('%(dst)s->%(name)s.assign(binary_value->GetBuffer(),') 636 .Append(' binary_value->GetSize());') 637 ) 638 639 def _GenerateListValueToEnumArrayConversion(self, c, prop): 640 """Appends code that converts a ListValue of string contstants to 641 an array of enums in dst. 642 Leaves dst, name, and failure_value unsubstituted. 643 644 c: the Code object that is being appended to. 645 prop: the property that the code is populating. 646 """ 647 accessor = '.' 648 if prop.optional: 649 c.Append('%(dst)s->%(name)s.reset(new std::vector<' + ( 650 self._cpp_type_generator.GetType(prop.item_type) + '>);')) 651 accessor = '->' 652 c.Sblock('for (ListValue::const_iterator it = list->begin(); ' 653 'it != list->end(); ++it) {') 654 self._GenerateStringToEnumConversion( 655 c, prop.item_type, '(*it)', 'enum_temp') 656 c.Append('%(dst)s->%(name)s' + accessor + 'push_back(enum_temp);') 657 c.Eblock('}') 658 659 def _GenerateStringToEnumConversion(self, c, prop, value_var, enum_temp): 660 """Appends code that converts a string to an enum. 661 Leaves failure_value unsubstituted. 662 663 c: the code that is appended to. 664 prop: the property that the code is populating. 665 value_var: the string value that is being converted. 666 enum_temp: the name used to store the temporary enum value. 667 """ 668 (c.Append('std::string enum_as_string;') 669 .Append('if (!%s->GetAsString(&enum_as_string))' % value_var) 670 .Append(' return %(failure_value)s;') 671 .Append('%(type)s %(enum)s = From%(type)sString(enum_as_string);' % { 672 'type': self._cpp_type_generator.GetCompiledType(prop), 673 'enum': enum_temp 674 }) 675 .Append('if (%s == %s)' % 676 (enum_temp, self._cpp_type_generator.GetEnumNoneValue(prop))) 677 .Append(' return %(failure_value)s;')) 678 679 def _GeneratePropertyFunctions(self, param_namespace, params): 680 """Generate the functions for structures generated by a property such as 681 CreateEnumValue for ENUMs and Populate/ToValue for Params/Results objects. 682 """ 683 c = Code() 684 for param in params: 685 if param.type_ == PropertyType.OBJECT: 686 c.Concat(self._GenerateType( 687 param_namespace + '::' + cpp_util.Classname(param.name), 688 param)) 689 c.Append() 690 elif param.type_ == PropertyType.ARRAY: 691 c.Concat(self._GeneratePropertyFunctions( 692 param_namespace, [param.item_type])) 693 elif param.type_ == PropertyType.CHOICES: 694 c.Concat(self._GeneratePropertyFunctions( 695 param_namespace, param.choices.values())) 696 if param.from_client: 697 c.Concat(self._GenerateGetChoiceValue(param_namespace, param)) 698 elif param.type_ == PropertyType.ENUM: 699 (c.Concat(self._GenerateCreateEnumValue(param_namespace, param)) 700 .Append() 701 .Concat(self._GenerateEnumFromString(param_namespace, 702 param, 703 use_namespace=True)) 704 .Append() 705 .Concat(self._GenerateEnumToString(param_namespace, 706 param, 707 use_namespace=True)) 708 .Append()) 709 return c 710 711 def _GenerateGetChoiceValue(self, cpp_namespace, prop): 712 """Generates Get<Type>ChoiceValue() that returns a scoped_ptr<base::Value> 713 representing the choice value. 714 """ 715 c = Code() 716 (c.Sblock('scoped_ptr<base::Value> ' 717 '%(cpp_namespace)s::Get%(choice)sChoiceValue() const {') 718 .Sblock('switch (%s_type) {' % prop.unix_name) 719 .Concat(self._GenerateReturnCase( 720 self._cpp_type_generator.GetEnumNoneValue(prop), 721 'scoped_ptr<base::Value>()'))) 722 for choice in self._cpp_type_generator.ExpandParams([prop]): 723 c.Concat(self._GenerateReturnCase( 724 self._cpp_type_generator.GetEnumValue(prop, choice.type_.name), 725 'make_scoped_ptr<base::Value>(%s)' % 726 self._CreateValueFromProperty(choice, choice.unix_name))) 727 (c.Eblock('}') 728 .Append('return scoped_ptr<base::Value>();') 729 .Eblock('}') 730 .Append() 731 .Substitute({ 732 'cpp_namespace': cpp_namespace, 733 'choice': cpp_util.Classname(prop.name) 734 }) 735 ) 736 return c 737 738 def _GenerateCreateEnumTypeValue(self, cpp_namespace, prop): 739 """Generates CreateEnumValue() that returns the base::StringValue 740 representation of an enum type. 741 """ 742 c = Code() 743 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(prop.name)) 744 (c.Sblock('scoped_ptr<base::Value> CreateEnumValue(%s %s) {' % 745 (classname, classname.lower())) 746 .Append('std::string enum_temp = ToString(%s);' % classname.lower()) 747 .Append('if (enum_temp.empty())') 748 .Append(' return scoped_ptr<base::Value>();') 749 .Append('return scoped_ptr<base::Value>(' 750 'base::Value::CreateStringValue(enum_temp));') 751 .Eblock('}')) 752 return c 753 754 def _GenerateEnumToString(self, cpp_namespace, prop, use_namespace=False): 755 """Generates ToString() which gets the string representation of an enum. 756 """ 757 c = Code() 758 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(prop.name)) 759 if use_namespace: 760 namespace = '%s::' % cpp_namespace 761 else: 762 namespace = '' 763 764 (c.Append('// static') 765 .Sblock('std::string %(namespace)sToString(%(class)s enum_param) {')) 766 enum_prop = self._cpp_type_generator.GetReferencedProperty(prop) 767 c.Sblock('switch (enum_param) {') 768 for enum_value in enum_prop.enum_values: 769 c.Concat(self._GenerateReturnCase( 770 self._cpp_type_generator.GetEnumValue(prop, enum_value), 771 '"%s"' % enum_value)) 772 (c.Append('case %s:' % self._cpp_type_generator.GetEnumNoneValue(prop)) 773 .Append(' return "";') 774 .Eblock('}') 775 .Append('return "";') 776 .Eblock('}') 777 .Substitute({ 778 'namespace': namespace, 779 'class': classname 780 })) 781 return c 782 783 def _GenerateEnumFromString(self, cpp_namespace, prop, use_namespace=False): 784 """Generates FromClassNameString() which gets an enum from its string 785 representation. 786 """ 787 c = Code() 788 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(prop.name)) 789 if use_namespace: 790 namespace = '%s::' % cpp_namespace 791 else: 792 namespace = '' 793 794 (c.Append('// static') 795 .Sblock('%(namespace)s%(class)s' 796 ' %(namespace)sFrom%(class)sString(' 797 'const std::string& enum_string) {')) 798 enum_prop = self._cpp_type_generator.GetReferencedProperty(prop) 799 for i, enum_value in enumerate( 800 self._cpp_type_generator.GetReferencedProperty(prop).enum_values): 801 # This is broken up into all ifs with no else ifs because we get 802 # "fatal error C1061: compiler limit : blocks nested too deeply" 803 # on Windows. 804 (c.Append('if (enum_string == "%s")' % enum_value) 805 .Append(' return %s;' % 806 self._cpp_type_generator.GetEnumValue(prop, enum_value))) 807 (c.Append('return %s;' % 808 self._cpp_type_generator.GetEnumNoneValue(prop)) 809 .Eblock('}') 810 .Substitute({ 811 'namespace': namespace, 812 'class': classname 813 })) 814 return c 815 816 # TODO(chebert): This is basically the same as GenerateCreateEnumTypeValue(). 817 # The plan is to phase out the old-style enums, and make all enums into REF 818 # types. 819 def _GenerateCreateEnumValue(self, cpp_namespace, prop): 820 """Generates CreateEnumValue() that returns the base::StringValue 821 representation of an enum. 822 """ 823 c = Code() 824 (c.Append('// static') 825 .Sblock('scoped_ptr<base::Value> %(cpp_namespace)s::CreateEnumValue(' 826 '%(arg)s) {') 827 .Append('std::string enum_temp = ToString(%s);' % prop.unix_name) 828 .Append('if (enum_temp.empty())') 829 .Append(' return scoped_ptr<base::Value>();') 830 .Append('return scoped_ptr<base::Value>(' 831 'base::Value::CreateStringValue(enum_temp));') 832 .Eblock('}') 833 .Substitute({ 834 'cpp_namespace': cpp_namespace, 835 'arg': cpp_util.GetParameterDeclaration( 836 prop, self._cpp_type_generator.GetType(prop)) 837 })) 838 return c 839 840 def _GenerateReturnCase(self, case_value, return_value): 841 """Generates a single return case for a switch block. 842 """ 843 c = Code() 844 (c.Append('case %s:' % case_value) 845 .Append(' return %s;' % return_value) 846 ) 847 return c 848 849 def _GenerateCreateCallbackArguments(self, 850 function_scope, 851 callback, 852 generate_to_json=False): 853 """Generate all functions to create Value parameters for a callback. 854 855 E.g for function "Bar", generate Bar::Results::Create 856 E.g for event "Baz", generate Baz::Create 857 858 function_scope: the function scope path, e.g. Foo::Bar for the function 859 Foo::Bar::Baz(). 860 callback: the Function object we are creating callback arguments for. 861 generate_to_json: Generate a ToJson method. 862 """ 863 c = Code() 864 params = callback.params 865 expanded_params = self._cpp_type_generator.ExpandParams(params) 866 c.Concat(self._GeneratePropertyFunctions(function_scope, expanded_params)) 867 868 param_lists = self._cpp_type_generator.GetAllPossibleParameterLists(params) 869 for param_list in param_lists: 870 (c.Sblock('scoped_ptr<base::ListValue> %(function_scope)s::' 871 'Create(%(declaration_list)s) {') 872 .Append('scoped_ptr<base::ListValue> create_results(' 873 'new base::ListValue());') 874 ) 875 declaration_list = [] 876 for param in param_list: 877 # We treat this argument as 'required' to avoid wrapping it in a 878 # scoped_ptr if it's optional. 879 param_copy = param.Copy() 880 param_copy.optional = False 881 declaration_list.append("const %s" % cpp_util.GetParameterDeclaration( 882 param_copy, self._cpp_type_generator.GetCompiledType(param_copy))) 883 param_name = param_copy.unix_name 884 if param_copy.type_ != param_copy.compiled_type: 885 param_name = 'temp_' + param_name 886 (c.Append('%s %s;' % (self._cpp_type_generator.GetType(param_copy), 887 param_name)) 888 .Append(cpp_util.GenerateCompiledTypeToTypeConversion( 889 param_copy, 890 param_copy.unix_name, 891 param_name) + ';') 892 ) 893 c.Append('create_results->Append(%s);' % 894 self._CreateValueFromProperty(param_copy, param_name)) 895 896 c.Append('return create_results.Pass();') 897 c.Eblock('}') 898 if generate_to_json: 899 c.Append() 900 (c.Sblock('std::string %(function_scope)s::' 901 'ToJson(%(declaration_list)s) {') 902 .Append('scoped_ptr<base::ListValue> create_results = ' 903 '%(function_scope)s::Create(%(param_list)s);') 904 .Append('std::string json;') 905 .Append('base::JSONWriter::Write(create_results.get(), &json);') 906 .Append('return json;') 907 ) 908 c.Eblock('}') 909 910 c.Substitute({ 911 'function_scope': function_scope, 912 'declaration_list': ', '.join(declaration_list), 913 'param_list': ', '.join(param.unix_name for param in param_list) 914 }) 915 916 return c 917 918 def _InitializePropertyToDefault(self, prop, dst): 919 """Initialize a model.Property to its default value inside an object. 920 921 E.g for optional enum "state", generate dst->state = STATE_NONE; 922 923 dst: Type* 924 """ 925 c = Code() 926 if (self._cpp_type_generator.IsEnumOrEnumRef(prop) or 927 prop.type_ == PropertyType.CHOICES): 928 if prop.optional: 929 prop_name = prop.unix_name 930 if prop.type_ == PropertyType.CHOICES: 931 prop_name = prop.unix_name + '_type' 932 c.Append('%s->%s = %s;' % ( 933 dst, 934 prop_name, 935 self._cpp_type_generator.GetEnumNoneValue(prop))) 936 return c 937 938 def _IsObjectOrObjectRef(self, prop): 939 """Determines if this property is an Object or is a ref to an Object. 940 """ 941 return (self._cpp_type_generator.GetReferencedProperty(prop).type_ == 942 PropertyType.OBJECT) 943 944 def _IsArrayOrArrayRef(self, prop): 945 """Determines if this property is an Array or is a ref to an Array. 946 """ 947 return (self._cpp_type_generator.GetReferencedProperty(prop).type_ == 948 PropertyType.ARRAY) 949 950 def _IsFundamentalOrFundamentalRef(self, prop): 951 """Determines if this property is a Fundamental type or is a ref to a 952 Fundamental type. 953 """ 954 return (self._cpp_type_generator.GetReferencedProperty(prop).type_. 955 is_fundamental) 956