cc_generator.py revision 5e3f23d412006dc4db4e659864679f29341e113f
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, Type 7import cpp_util 8import model 9import schema_util 10import sys 11import util_cc_helper 12 13class CCGenerator(object): 14 def __init__(self, type_generator, cpp_namespace): 15 self._type_generator = type_generator 16 self._cpp_namespace = cpp_namespace 17 18 def Generate(self, namespace): 19 return _Generator(namespace, 20 self._type_generator, 21 self._cpp_namespace).Generate() 22 23class _Generator(object): 24 """A .cc generator for a namespace. 25 """ 26 def __init__(self, namespace, cpp_type_generator, cpp_namespace): 27 self._namespace = namespace 28 self._type_helper = cpp_type_generator 29 self._cpp_namespace = cpp_namespace 30 self._target_namespace = ( 31 self._type_helper.GetCppNamespaceName(self._namespace)) 32 self._util_cc_helper = ( 33 util_cc_helper.UtilCCHelper(self._type_helper)) 34 35 def Generate(self): 36 """Generates a Code object with the .cc for a single namespace. 37 """ 38 c = Code() 39 (c.Append(cpp_util.CHROMIUM_LICENSE) 40 .Append() 41 .Append(cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file) 42 .Append() 43 .Append(self._util_cc_helper.GetIncludePath()) 44 .Append('#include "base/logging.h"') 45 .Append('#include "base/strings/string_number_conversions.h"') 46 .Append('#include "%s/%s.h"' % 47 (self._namespace.source_file_dir, self._namespace.unix_name)) 48 .Cblock(self._type_helper.GenerateIncludes(include_soft=True)) 49 .Append() 50 .Concat(cpp_util.OpenNamespace(self._cpp_namespace)) 51 .Cblock(self._type_helper.GetNamespaceStart()) 52 ) 53 if self._namespace.properties: 54 (c.Append('//') 55 .Append('// Properties') 56 .Append('//') 57 .Append() 58 ) 59 for property in self._namespace.properties.values(): 60 property_code = self._type_helper.GeneratePropertyValues( 61 property, 62 'const %(type)s %(name)s = %(value)s;', 63 nodoc=True) 64 if property_code: 65 c.Cblock(property_code) 66 if self._namespace.types: 67 (c.Append('//') 68 .Append('// Types') 69 .Append('//') 70 .Append() 71 .Cblock(self._GenerateTypes(None, self._namespace.types.values())) 72 ) 73 if self._namespace.functions: 74 (c.Append('//') 75 .Append('// Functions') 76 .Append('//') 77 .Append() 78 ) 79 for function in self._namespace.functions.values(): 80 c.Cblock(self._GenerateFunction(function)) 81 if self._namespace.events: 82 (c.Append('//') 83 .Append('// Events') 84 .Append('//') 85 .Append() 86 ) 87 for event in self._namespace.events.values(): 88 c.Cblock(self._GenerateEvent(event)) 89 (c.Concat(self._type_helper.GetNamespaceEnd()) 90 .Cblock(cpp_util.CloseNamespace(self._cpp_namespace)) 91 ) 92 return c 93 94 def _GenerateType(self, cpp_namespace, type_): 95 """Generates the function definitions for a type. 96 """ 97 classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) 98 c = Code() 99 100 if type_.functions: 101 # Wrap functions within types in the type's namespace. 102 (c.Append('namespace %s {' % classname) 103 .Append()) 104 for function in type_.functions.values(): 105 c.Cblock(self._GenerateFunction(function)) 106 c.Append('} // namespace %s' % classname) 107 elif type_.property_type == PropertyType.ARRAY: 108 c.Cblock(self._GenerateType(cpp_namespace, type_.item_type)) 109 elif (type_.property_type == PropertyType.OBJECT or 110 type_.property_type == PropertyType.CHOICES): 111 if cpp_namespace is None: 112 classname_in_namespace = classname 113 else: 114 classname_in_namespace = '%s::%s' % (cpp_namespace, classname) 115 116 if type_.property_type == PropertyType.OBJECT: 117 c.Cblock(self._GeneratePropertyFunctions(classname_in_namespace, 118 type_.properties.values())) 119 else: 120 c.Cblock(self._GenerateTypes(classname_in_namespace, type_.choices)) 121 122 (c.Append('%s::%s()' % (classname_in_namespace, classname)) 123 .Cblock(self._GenerateInitializersAndBody(type_)) 124 .Append('%s::~%s() {}' % (classname_in_namespace, classname)) 125 .Append() 126 ) 127 if type_.origin.from_json: 128 c.Cblock(self._GenerateTypePopulate(classname_in_namespace, type_)) 129 if cpp_namespace is None: # only generate for top-level types 130 c.Cblock(self._GenerateTypeFromValue(classname_in_namespace, type_)) 131 if type_.origin.from_client: 132 c.Cblock(self._GenerateTypeToValue(classname_in_namespace, type_)) 133 elif type_.property_type == PropertyType.ENUM: 134 (c.Cblock(self._GenerateEnumToString(cpp_namespace, type_)) 135 .Cblock(self._GenerateEnumFromString(cpp_namespace, type_)) 136 ) 137 138 return c 139 140 def _GenerateInitializersAndBody(self, type_): 141 items = [] 142 for prop in type_.properties.values(): 143 if prop.optional: 144 continue 145 146 t = prop.type_ 147 if t.property_type == PropertyType.INTEGER: 148 items.append('%s(0)' % prop.unix_name) 149 elif t.property_type == PropertyType.DOUBLE: 150 items.append('%s(0.0)' % prop.unix_name) 151 elif t.property_type == PropertyType.BOOLEAN: 152 items.append('%s(false)' % prop.unix_name) 153 elif t.property_type == PropertyType.BINARY: 154 items.append('%s(NULL)' % prop.unix_name) 155 elif (t.property_type == PropertyType.ANY or 156 t.property_type == PropertyType.ARRAY or 157 t.property_type == PropertyType.CHOICES or 158 t.property_type == PropertyType.ENUM or 159 t.property_type == PropertyType.OBJECT or 160 t.property_type == PropertyType.FUNCTION or 161 t.property_type == PropertyType.REF or 162 t.property_type == PropertyType.STRING): 163 # TODO(miket): It would be nice to initialize CHOICES and ENUM, but we 164 # don't presently have the semantics to indicate which one of a set 165 # should be the default. 166 continue 167 else: 168 raise TypeError(t) 169 170 if items: 171 s = ': %s' % (', '.join(items)) 172 else: 173 s = '' 174 s = s + ' {}' 175 return Code().Append(s) 176 177 def _GenerateTypePopulate(self, cpp_namespace, type_): 178 """Generates the function for populating a type given a pointer to it. 179 180 E.g for type "Foo", generates Foo::Populate() 181 """ 182 classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) 183 c = Code() 184 (c.Append('// static') 185 .Append('bool %(namespace)s::Populate(') 186 .Sblock(' const base::Value& value, %(name)s* out) {') 187 ) 188 if type_.property_type == PropertyType.CHOICES: 189 for choice in type_.choices: 190 value_type = cpp_util.GetValueType(self._type_helper.FollowRef(choice)) 191 (c.Sblock('if (value.IsType(%s)) {' % value_type) 192 .Concat(self._GeneratePopulateVariableFromValue( 193 choice, 194 '(&value)', 195 'out->as_%s' % choice.unix_name, 196 'false', 197 is_ptr=True)) 198 .Append('return true;') 199 .Eblock('}') 200 ) 201 c.Append('return false;') 202 elif type_.property_type == PropertyType.OBJECT: 203 (c.Append('if (!value.IsType(base::Value::TYPE_DICTIONARY))') 204 .Append(' return false;') 205 ) 206 if type_.properties or type_.additional_properties is not None: 207 c.Append('const base::DictionaryValue* dict = ' 208 'static_cast<const base::DictionaryValue*>(&value);') 209 for prop in type_.properties.values(): 210 c.Concat(self._InitializePropertyToDefault(prop, 'out')) 211 for prop in type_.properties.values(): 212 c.Concat(self._GenerateTypePopulateProperty(prop, 'dict', 'out')) 213 if type_.additional_properties is not None: 214 if type_.additional_properties.property_type == PropertyType.ANY: 215 c.Append('out->additional_properties.MergeDictionary(dict);') 216 else: 217 cpp_type = self._type_helper.GetCppType(type_.additional_properties, 218 is_in_container=True) 219 (c.Append('for (base::DictionaryValue::Iterator it(*dict);') 220 .Sblock(' !it.IsAtEnd(); it.Advance()) {') 221 .Append('%s tmp;' % cpp_type) 222 .Concat(self._GeneratePopulateVariableFromValue( 223 type_.additional_properties, 224 '(&it.value())', 225 'tmp', 226 'false')) 227 .Append('out->additional_properties[it.key()] = tmp;') 228 .Eblock('}') 229 ) 230 c.Append('return true;') 231 (c.Eblock('}') 232 .Substitute({'namespace': cpp_namespace, 'name': classname})) 233 return c 234 235 def _GenerateTypePopulateProperty(self, prop, src, dst): 236 """Generate the code to populate a single property in a type. 237 238 src: base::DictionaryValue* 239 dst: Type* 240 """ 241 c = Code() 242 value_var = prop.unix_name + '_value' 243 c.Append('const base::Value* %(value_var)s = NULL;') 244 if prop.optional: 245 (c.Sblock( 246 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {') 247 .Concat(self._GeneratePopulatePropertyFromValue( 248 prop, value_var, dst, 'false'))) 249 underlying_type = self._type_helper.FollowRef(prop.type_) 250 if underlying_type.property_type == PropertyType.ENUM: 251 (c.Append('} else {') 252 .Append('%%(dst)s->%%(name)s = %s;' % 253 self._type_helper.GetEnumNoneValue(prop.type_))) 254 c.Eblock('}') 255 else: 256 (c.Append( 257 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))') 258 .Append(' return false;') 259 .Concat(self._GeneratePopulatePropertyFromValue( 260 prop, value_var, dst, 'false')) 261 ) 262 c.Append() 263 c.Substitute({ 264 'value_var': value_var, 265 'key': prop.name, 266 'src': src, 267 'dst': dst, 268 'name': prop.unix_name 269 }) 270 return c 271 272 def _GenerateTypeFromValue(self, cpp_namespace, type_): 273 classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) 274 c = Code() 275 (c.Append('// static') 276 .Append('scoped_ptr<%s> %s::FromValue(const base::Value& value) {' % ( 277 classname, cpp_namespace)) 278 .Append(' scoped_ptr<%s> out(new %s());' % (classname, classname)) 279 .Append(' if (!Populate(value, out.get()))') 280 .Append(' return scoped_ptr<%s>();' % classname) 281 .Append(' return out.Pass();') 282 .Append('}') 283 ) 284 return c 285 286 def _GenerateTypeToValue(self, cpp_namespace, type_): 287 """Generates a function that serializes the type into a base::Value. 288 E.g. for type "Foo" generates Foo::ToValue() 289 """ 290 if type_.property_type == PropertyType.OBJECT: 291 return self._GenerateObjectTypeToValue(cpp_namespace, type_) 292 elif type_.property_type == PropertyType.CHOICES: 293 return self._GenerateChoiceTypeToValue(cpp_namespace, type_) 294 else: 295 raise ValueError("Unsupported property type %s" % type_.type_) 296 297 def _GenerateObjectTypeToValue(self, cpp_namespace, type_): 298 """Generates a function that serializes an object-representing type 299 into a base::DictionaryValue. 300 """ 301 c = Code() 302 (c.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' % 303 cpp_namespace) 304 .Append('scoped_ptr<base::DictionaryValue> value(' 305 'new base::DictionaryValue());') 306 .Append() 307 ) 308 309 for prop in type_.properties.values(): 310 if prop.optional: 311 # Optional enum values are generated with a NONE enum value. 312 underlying_type = self._type_helper.FollowRef(prop.type_) 313 if underlying_type.property_type == PropertyType.ENUM: 314 c.Sblock('if (%s != %s) {' % 315 (prop.unix_name, 316 self._type_helper.GetEnumNoneValue(prop.type_))) 317 else: 318 c.Sblock('if (%s.get()) {' % prop.unix_name) 319 320 # ANY is a base::Value which is abstract and cannot be a direct member, so 321 # it will always be a pointer. 322 is_ptr = prop.optional or prop.type_.property_type == PropertyType.ANY 323 c.Append('value->SetWithoutPathExpansion("%s", %s);' % ( 324 prop.name, 325 self._CreateValueFromType(prop.type_, 326 'this->%s' % prop.unix_name, 327 is_ptr=is_ptr))) 328 329 if prop.optional: 330 c.Eblock('}'); 331 332 if type_.additional_properties is not None: 333 if type_.additional_properties.property_type == PropertyType.ANY: 334 c.Append('value->MergeDictionary(&additional_properties);') 335 else: 336 # Non-copyable types will be wrapped in a linked_ptr for inclusion in 337 # maps, so we need to unwrap them. 338 needs_unwrap = ( 339 not self._type_helper.IsCopyable(type_.additional_properties)) 340 cpp_type = self._type_helper.GetCppType(type_.additional_properties, 341 is_in_container=True) 342 (c.Sblock('for (std::map<std::string, %s>::const_iterator it =' % 343 cpp_util.PadForGenerics(cpp_type)) 344 .Append(' additional_properties.begin();') 345 .Append(' it != additional_properties.end(); ++it) {') 346 .Append('value->SetWithoutPathExpansion(it->first, %s);' % 347 self._CreateValueFromType( 348 type_.additional_properties, 349 '%sit->second' % ('*' if needs_unwrap else ''))) 350 .Eblock('}') 351 ) 352 353 return (c.Append() 354 .Append('return value.Pass();') 355 .Eblock('}')) 356 357 def _GenerateChoiceTypeToValue(self, cpp_namespace, type_): 358 """Generates a function that serializes a choice-representing type 359 into a base::Value. 360 """ 361 c = Code() 362 c.Sblock('scoped_ptr<base::Value> %s::ToValue() const {' % cpp_namespace) 363 c.Append('scoped_ptr<base::Value> result;'); 364 for choice in type_.choices: 365 choice_var = 'as_%s' % choice.unix_name 366 (c.Sblock('if (%s) {' % choice_var) 367 .Append('DCHECK(!result) << "Cannot set multiple choices for %s";' % 368 type_.unix_name) 369 .Append('result.reset(%s);' % 370 self._CreateValueFromType(choice, '*%s' % choice_var)) 371 .Eblock('}') 372 ) 373 (c.Append('DCHECK(result) << "Must set at least one choice for %s";' % 374 type_.unix_name) 375 .Append('return result.Pass();') 376 .Eblock('}') 377 ) 378 return c 379 380 def _GenerateFunction(self, function): 381 """Generates the definitions for function structs. 382 """ 383 c = Code() 384 385 # TODO(kalman): use function.unix_name not Classname. 386 function_namespace = cpp_util.Classname(function.name) 387 """Windows has a #define for SendMessage, so to avoid any issues, we need 388 to not use the name. 389 """ 390 if function_namespace == 'SendMessage': 391 function_namespace = 'PassMessage' 392 (c.Append('namespace %s {' % function_namespace) 393 .Append() 394 ) 395 396 # Params::Populate function 397 if function.params: 398 c.Concat(self._GeneratePropertyFunctions('Params', function.params)) 399 (c.Append('Params::Params() {}') 400 .Append('Params::~Params() {}') 401 .Append() 402 .Cblock(self._GenerateFunctionParamsCreate(function)) 403 ) 404 405 # Results::Create function 406 if function.callback: 407 c.Concat(self._GenerateCreateCallbackArguments('Results', 408 function.callback)) 409 410 c.Append('} // namespace %s' % function_namespace) 411 return c 412 413 def _GenerateEvent(self, event): 414 # TODO(kalman): use event.unix_name not Classname. 415 c = Code() 416 event_namespace = cpp_util.Classname(event.name) 417 (c.Append('namespace %s {' % event_namespace) 418 .Append() 419 .Cblock(self._GenerateCreateCallbackArguments(None, event)) 420 .Append('} // namespace %s' % event_namespace) 421 ) 422 return c 423 424 def _CreateValueFromType(self, type_, var, is_ptr=False): 425 """Creates a base::Value given a type. Generated code passes ownership 426 to caller. 427 428 var: variable or variable* 429 430 E.g for std::string, generate base::Value::CreateStringValue(var) 431 """ 432 underlying_type = self._type_helper.FollowRef(type_) 433 if (underlying_type.property_type == PropertyType.CHOICES or 434 underlying_type.property_type == PropertyType.OBJECT): 435 if is_ptr: 436 return '(%s)->ToValue().release()' % var 437 else: 438 return '(%s).ToValue().release()' % var 439 elif (underlying_type.property_type == PropertyType.ANY or 440 underlying_type.property_type == PropertyType.FUNCTION): 441 if is_ptr: 442 vardot = '(%s)->' % var 443 else: 444 vardot = '(%s).' % var 445 return '%sDeepCopy()' % vardot 446 elif underlying_type.property_type == PropertyType.ENUM: 447 return 'base::Value::CreateStringValue(ToString(%s))' % var 448 elif underlying_type.property_type == PropertyType.BINARY: 449 if is_ptr: 450 vardot = var + '->' 451 else: 452 vardot = var + '.' 453 return ('base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())' % 454 (vardot, vardot)) 455 elif underlying_type.property_type == PropertyType.ARRAY: 456 return '%s.release()' % self._util_cc_helper.CreateValueFromArray( 457 underlying_type, 458 var, 459 is_ptr) 460 elif underlying_type.property_type.is_fundamental: 461 if is_ptr: 462 var = '*%s' % var 463 if underlying_type.property_type == PropertyType.STRING: 464 return 'new base::StringValue(%s)' % var 465 else: 466 return 'new base::FundamentalValue(%s)' % var 467 else: 468 raise NotImplementedError('Conversion of %s to base::Value not ' 469 'implemented' % repr(type_.type_)) 470 471 def _GenerateParamsCheck(self, function, var): 472 """Generates a check for the correct number of arguments when creating 473 Params. 474 """ 475 c = Code() 476 num_required = 0 477 for param in function.params: 478 if not param.optional: 479 num_required += 1 480 if num_required == len(function.params): 481 c.Append('if (%(var)s.GetSize() != %(total)d)') 482 elif not num_required: 483 c.Append('if (%(var)s.GetSize() > %(total)d)') 484 else: 485 c.Append('if (%(var)s.GetSize() < %(required)d' 486 ' || %(var)s.GetSize() > %(total)d)') 487 c.Append(' return scoped_ptr<Params>();') 488 c.Substitute({ 489 'var': var, 490 'required': num_required, 491 'total': len(function.params), 492 }) 493 return c 494 495 def _GenerateFunctionParamsCreate(self, function): 496 """Generate function to create an instance of Params. The generated 497 function takes a base::ListValue of arguments. 498 499 E.g for function "Bar", generate Bar::Params::Create() 500 """ 501 c = Code() 502 (c.Append('// static') 503 .Sblock('scoped_ptr<Params> ' 504 'Params::Create(const base::ListValue& args) {') 505 .Concat(self._GenerateParamsCheck(function, 'args')) 506 .Append('scoped_ptr<Params> params(new Params());') 507 ) 508 509 for param in function.params: 510 c.Concat(self._InitializePropertyToDefault(param, 'params')) 511 512 for i, param in enumerate(function.params): 513 # Any failure will cause this function to return. If any argument is 514 # incorrect or missing, those following it are not processed. Note that 515 # for optional arguments, we allow missing arguments and proceed because 516 # there may be other arguments following it. 517 failure_value = 'scoped_ptr<Params>()' 518 c.Append() 519 value_var = param.unix_name + '_value' 520 (c.Append('const base::Value* %(value_var)s = NULL;') 521 .Append('if (args.Get(%(i)s, &%(value_var)s) &&') 522 .Sblock(' !%(value_var)s->IsType(base::Value::TYPE_NULL)) {') 523 .Concat(self._GeneratePopulatePropertyFromValue( 524 param, value_var, 'params', failure_value)) 525 .Eblock('}') 526 ) 527 if not param.optional: 528 (c.Sblock('else {') 529 .Append('return %s;' % failure_value) 530 .Eblock('}') 531 ) 532 c.Substitute({'value_var': value_var, 'i': i}) 533 (c.Append() 534 .Append('return params.Pass();') 535 .Eblock('}') 536 .Append() 537 ) 538 539 return c 540 541 def _GeneratePopulatePropertyFromValue(self, 542 prop, 543 src_var, 544 dst_class_var, 545 failure_value): 546 """Generates code to populate property |prop| of |dst_class_var| (a 547 pointer) from a Value*. See |_GeneratePopulateVariableFromValue| for 548 semantics. 549 """ 550 return self._GeneratePopulateVariableFromValue(prop.type_, 551 src_var, 552 '%s->%s' % (dst_class_var, 553 prop.unix_name), 554 failure_value, 555 is_ptr=prop.optional) 556 557 def _GeneratePopulateVariableFromValue(self, 558 type_, 559 src_var, 560 dst_var, 561 failure_value, 562 is_ptr=False): 563 """Generates code to populate a variable |dst_var| of type |type_| from a 564 Value* at |src_var|. The Value* is assumed to be non-NULL. In the generated 565 code, if |dst_var| fails to be populated then Populate will return 566 |failure_value|. 567 """ 568 c = Code() 569 c.Sblock('{') 570 571 underlying_type = self._type_helper.FollowRef(type_) 572 573 if underlying_type.property_type.is_fundamental: 574 if is_ptr: 575 (c.Append('%(cpp_type)s temp;') 576 .Append('if (!%s)' % cpp_util.GetAsFundamentalValue( 577 self._type_helper.FollowRef(type_), src_var, '&temp')) 578 .Append(' return %(failure_value)s;') 579 .Append('%(dst_var)s.reset(new %(cpp_type)s(temp));') 580 ) 581 else: 582 (c.Append('if (!%s)' % cpp_util.GetAsFundamentalValue( 583 self._type_helper.FollowRef(type_), 584 src_var, 585 '&%s' % dst_var)) 586 .Append(' return %(failure_value)s;') 587 ) 588 elif underlying_type.property_type == PropertyType.OBJECT: 589 if is_ptr: 590 (c.Append('const base::DictionaryValue* dictionary = NULL;') 591 .Append('if (!%(src_var)s->GetAsDictionary(&dictionary))') 592 .Append(' return %(failure_value)s;') 593 .Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());') 594 .Append('if (!%(cpp_type)s::Populate(*dictionary, temp.get()))') 595 .Append(' return %(failure_value)s;') 596 .Append('%(dst_var)s = temp.Pass();') 597 ) 598 else: 599 (c.Append('const base::DictionaryValue* dictionary = NULL;') 600 .Append('if (!%(src_var)s->GetAsDictionary(&dictionary))') 601 .Append(' return %(failure_value)s;') 602 .Append('if (!%(cpp_type)s::Populate(*dictionary, &%(dst_var)s))') 603 .Append(' return %(failure_value)s;') 604 ) 605 elif underlying_type.property_type == PropertyType.FUNCTION: 606 if is_ptr: 607 c.Append('%(dst_var)s.reset(new base::DictionaryValue());') 608 elif underlying_type.property_type == PropertyType.ANY: 609 c.Append('%(dst_var)s.reset(%(src_var)s->DeepCopy());') 610 elif underlying_type.property_type == PropertyType.ARRAY: 611 # util_cc_helper deals with optional and required arrays 612 (c.Append('const base::ListValue* list = NULL;') 613 .Append('if (!%(src_var)s->GetAsList(&list))') 614 .Append(' return %(failure_value)s;')) 615 item_type = underlying_type.item_type 616 if item_type.property_type == PropertyType.ENUM: 617 c.Concat(self._GenerateListValueToEnumArrayConversion( 618 item_type, 619 'list', 620 dst_var, 621 failure_value, 622 is_ptr=is_ptr)) 623 else: 624 (c.Append('if (!%s)' % self._util_cc_helper.PopulateArrayFromList( 625 underlying_type, 626 'list', 627 dst_var, 628 is_ptr)) 629 .Append(' return %(failure_value)s;') 630 ) 631 elif underlying_type.property_type == PropertyType.CHOICES: 632 if is_ptr: 633 (c.Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());') 634 .Append('if (!%(cpp_type)s::Populate(*%(src_var)s, temp.get()))') 635 .Append(' return %(failure_value)s;') 636 .Append('%(dst_var)s = temp.Pass();') 637 ) 638 else: 639 (c.Append('if (!%(cpp_type)s::Populate(*%(src_var)s, &%(dst_var)s))') 640 .Append(' return %(failure_value)s;') 641 ) 642 elif underlying_type.property_type == PropertyType.ENUM: 643 c.Concat(self._GenerateStringToEnumConversion(type_, 644 src_var, 645 dst_var, 646 failure_value)) 647 elif underlying_type.property_type == PropertyType.BINARY: 648 (c.Append('if (!%(src_var)s->IsType(%(value_type)s))') 649 .Append(' return %(failure_value)s;') 650 .Append('const base::BinaryValue* binary_value =') 651 .Append(' static_cast<const base::BinaryValue*>(%(src_var)s);') 652 ) 653 if is_ptr: 654 (c.Append('%(dst_var)s.reset(') 655 .Append(' new std::string(binary_value->GetBuffer(),') 656 .Append(' binary_value->GetSize()));') 657 ) 658 else: 659 (c.Append('%(dst_var)s.assign(binary_value->GetBuffer(),') 660 .Append(' binary_value->GetSize());') 661 ) 662 else: 663 raise NotImplementedError(type_) 664 665 sub = { 666 'cpp_type': self._type_helper.GetCppType(type_), 667 'src_var': src_var, 668 'dst_var': dst_var, 669 'failure_value': failure_value, 670 } 671 672 if underlying_type.property_type not in (PropertyType.ANY, 673 PropertyType.CHOICES): 674 sub['value_type'] = cpp_util.GetValueType(underlying_type) 675 676 return c.Eblock('}').Substitute(sub) 677 678 def _GenerateListValueToEnumArrayConversion(self, 679 item_type, 680 src_var, 681 dst_var, 682 failure_value, 683 is_ptr=False): 684 """Returns Code that converts a ListValue of string constants from 685 |src_var| into an array of enums of |type_| in |dst_var|. On failure, 686 returns |failure_value|. 687 """ 688 c = Code() 689 accessor = '.' 690 if is_ptr: 691 accessor = '->' 692 cpp_type = self._type_helper.GetCppType(item_type, is_in_container=True) 693 c.Append('%s.reset(new std::vector<%s>);' % 694 (dst_var, cpp_util.PadForGenerics(cpp_type))) 695 (c.Sblock('for (base::ListValue::const_iterator it = %s->begin(); ' 696 'it != %s->end(); ++it) {' % (src_var, src_var)) 697 .Append('%s tmp;' % self._type_helper.GetCppType(item_type)) 698 .Concat(self._GenerateStringToEnumConversion(item_type, 699 '(*it)', 700 'tmp', 701 failure_value)) 702 .Append('%s%spush_back(tmp);' % (dst_var, accessor)) 703 .Eblock('}') 704 ) 705 return c 706 707 def _GenerateStringToEnumConversion(self, 708 type_, 709 src_var, 710 dst_var, 711 failure_value): 712 """Returns Code that converts a string type in |src_var| to an enum with 713 type |type_| in |dst_var|. In the generated code, if |src_var| is not 714 a valid enum name then the function will return |failure_value|. 715 """ 716 c = Code() 717 enum_as_string = '%s_as_string' % type_.unix_name 718 (c.Append('std::string %s;' % enum_as_string) 719 .Append('if (!%s->GetAsString(&%s))' % (src_var, enum_as_string)) 720 .Append(' return %s;' % failure_value) 721 .Append('%s = Parse%s(%s);' % (dst_var, 722 self._type_helper.GetCppType(type_), 723 enum_as_string)) 724 .Append('if (%s == %s)' % (dst_var, 725 self._type_helper.GetEnumNoneValue(type_))) 726 .Append(' return %s;' % failure_value) 727 ) 728 return c 729 730 def _GeneratePropertyFunctions(self, namespace, params): 731 """Generates the member functions for a list of parameters. 732 """ 733 return self._GenerateTypes(namespace, (param.type_ for param in params)) 734 735 def _GenerateTypes(self, namespace, types): 736 """Generates the member functions for a list of types. 737 """ 738 c = Code() 739 for type_ in types: 740 c.Cblock(self._GenerateType(namespace, type_)) 741 return c 742 743 def _GenerateEnumToString(self, cpp_namespace, type_): 744 """Generates ToString() which gets the string representation of an enum. 745 """ 746 c = Code() 747 classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) 748 749 if cpp_namespace is not None: 750 c.Append('// static') 751 maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace 752 753 c.Sblock('std::string %sToString(%s enum_param) {' % 754 (maybe_namespace, classname)) 755 c.Sblock('switch (enum_param) {') 756 for enum_value in self._type_helper.FollowRef(type_).enum_values: 757 (c.Append('case %s: ' % self._type_helper.GetEnumValue(type_, enum_value)) 758 .Append(' return "%s";' % enum_value)) 759 (c.Append('case %s:' % self._type_helper.GetEnumNoneValue(type_)) 760 .Append(' return "";') 761 .Eblock('}') 762 .Append('NOTREACHED();') 763 .Append('return "";') 764 .Eblock('}') 765 ) 766 return c 767 768 def _GenerateEnumFromString(self, cpp_namespace, type_): 769 """Generates FromClassNameString() which gets an enum from its string 770 representation. 771 """ 772 c = Code() 773 classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) 774 775 if cpp_namespace is not None: 776 c.Append('// static') 777 maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace 778 779 c.Sblock('%s%s %sParse%s(const std::string& enum_string) {' % 780 (maybe_namespace, classname, maybe_namespace, classname)) 781 for i, enum_value in enumerate( 782 self._type_helper.FollowRef(type_).enum_values): 783 # This is broken up into all ifs with no else ifs because we get 784 # "fatal error C1061: compiler limit : blocks nested too deeply" 785 # on Windows. 786 (c.Append('if (enum_string == "%s")' % enum_value) 787 .Append(' return %s;' % 788 self._type_helper.GetEnumValue(type_, enum_value))) 789 (c.Append('return %s;' % self._type_helper.GetEnumNoneValue(type_)) 790 .Eblock('}') 791 ) 792 return c 793 794 def _GenerateCreateCallbackArguments(self, function_scope, callback): 795 """Generate all functions to create Value parameters for a callback. 796 797 E.g for function "Bar", generate Bar::Results::Create 798 E.g for event "Baz", generate Baz::Create 799 800 function_scope: the function scope path, e.g. Foo::Bar for the function 801 Foo::Bar::Baz(). May be None if there is no function scope. 802 callback: the Function object we are creating callback arguments for. 803 """ 804 c = Code() 805 params = callback.params 806 c.Concat(self._GeneratePropertyFunctions(function_scope, params)) 807 808 (c.Sblock('scoped_ptr<base::ListValue> %(function_scope)s' 809 'Create(%(declaration_list)s) {') 810 .Append('scoped_ptr<base::ListValue> create_results(' 811 'new base::ListValue());') 812 ) 813 declaration_list = [] 814 for param in params: 815 declaration_list.append(cpp_util.GetParameterDeclaration( 816 param, self._type_helper.GetCppType(param.type_))) 817 c.Append('create_results->Append(%s);' % 818 self._CreateValueFromType(param.type_, param.unix_name)) 819 c.Append('return create_results.Pass();') 820 c.Eblock('}') 821 c.Substitute({ 822 'function_scope': ('%s::' % function_scope) if function_scope else '', 823 'declaration_list': ', '.join(declaration_list), 824 'param_names': ', '.join(param.unix_name for param in params) 825 }) 826 return c 827 828 def _InitializePropertyToDefault(self, prop, dst): 829 """Initialize a model.Property to its default value inside an object. 830 831 E.g for optional enum "state", generate dst->state = STATE_NONE; 832 833 dst: Type* 834 """ 835 c = Code() 836 underlying_type = self._type_helper.FollowRef(prop.type_) 837 if (underlying_type.property_type == PropertyType.ENUM and 838 prop.optional): 839 c.Append('%s->%s = %s;' % ( 840 dst, 841 prop.unix_name, 842 self._type_helper.GetEnumNoneValue(prop.type_))) 843 return c 844