cc_generator.py revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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 in (PropertyType.CHOICES, 110 PropertyType.OBJECT): 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 (c.Sblock('if (%s) {' % self._GenerateValueIsTypeExpression('value', 191 choice)) 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 _GenerateValueIsTypeExpression(self, var, type_): 236 real_type = self._type_helper.FollowRef(type_) 237 if real_type.property_type is PropertyType.CHOICES: 238 return '(%s)' % ' || '.join(self._GenerateValueIsTypeExpression(var, 239 choice) 240 for choice in real_type.choices) 241 return '%s.IsType(%s)' % (var, cpp_util.GetValueType(real_type)) 242 243 def _GenerateTypePopulateProperty(self, prop, src, dst): 244 """Generate the code to populate a single property in a type. 245 246 src: base::DictionaryValue* 247 dst: Type* 248 """ 249 c = Code() 250 value_var = prop.unix_name + '_value' 251 c.Append('const base::Value* %(value_var)s = NULL;') 252 if prop.optional: 253 (c.Sblock( 254 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {') 255 .Concat(self._GeneratePopulatePropertyFromValue( 256 prop, value_var, dst, 'false'))) 257 underlying_type = self._type_helper.FollowRef(prop.type_) 258 if underlying_type.property_type == PropertyType.ENUM: 259 (c.Append('} else {') 260 .Append('%%(dst)s->%%(name)s = %s;' % 261 self._type_helper.GetEnumNoneValue(prop.type_))) 262 c.Eblock('}') 263 else: 264 (c.Append( 265 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))') 266 .Append(' return false;') 267 .Concat(self._GeneratePopulatePropertyFromValue( 268 prop, value_var, dst, 'false')) 269 ) 270 c.Append() 271 c.Substitute({ 272 'value_var': value_var, 273 'key': prop.name, 274 'src': src, 275 'dst': dst, 276 'name': prop.unix_name 277 }) 278 return c 279 280 def _GenerateTypeFromValue(self, cpp_namespace, type_): 281 classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) 282 c = Code() 283 (c.Append('// static') 284 .Append('scoped_ptr<%s> %s::FromValue(const base::Value& value) {' % ( 285 classname, cpp_namespace)) 286 .Append(' scoped_ptr<%s> out(new %s());' % (classname, classname)) 287 .Append(' if (!Populate(value, out.get()))') 288 .Append(' return scoped_ptr<%s>();' % classname) 289 .Append(' return out.Pass();') 290 .Append('}') 291 ) 292 return c 293 294 def _GenerateTypeToValue(self, cpp_namespace, type_): 295 """Generates a function that serializes the type into a base::Value. 296 E.g. for type "Foo" generates Foo::ToValue() 297 """ 298 if type_.property_type == PropertyType.OBJECT: 299 return self._GenerateObjectTypeToValue(cpp_namespace, type_) 300 elif type_.property_type == PropertyType.CHOICES: 301 return self._GenerateChoiceTypeToValue(cpp_namespace, type_) 302 else: 303 raise ValueError("Unsupported property type %s" % type_.type_) 304 305 def _GenerateObjectTypeToValue(self, cpp_namespace, type_): 306 """Generates a function that serializes an object-representing type 307 into a base::DictionaryValue. 308 """ 309 c = Code() 310 (c.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' % 311 cpp_namespace) 312 .Append('scoped_ptr<base::DictionaryValue> value(' 313 'new base::DictionaryValue());') 314 .Append() 315 ) 316 317 for prop in type_.properties.values(): 318 if prop.optional: 319 # Optional enum values are generated with a NONE enum value. 320 underlying_type = self._type_helper.FollowRef(prop.type_) 321 if underlying_type.property_type == PropertyType.ENUM: 322 c.Sblock('if (%s != %s) {' % 323 (prop.unix_name, 324 self._type_helper.GetEnumNoneValue(prop.type_))) 325 else: 326 c.Sblock('if (%s.get()) {' % prop.unix_name) 327 328 # ANY is a base::Value which is abstract and cannot be a direct member, so 329 # it will always be a pointer. 330 is_ptr = prop.optional or prop.type_.property_type == PropertyType.ANY 331 c.Append('value->SetWithoutPathExpansion("%s", %s);' % ( 332 prop.name, 333 self._CreateValueFromType(prop.type_, 334 'this->%s' % prop.unix_name, 335 is_ptr=is_ptr))) 336 337 if prop.optional: 338 c.Eblock('}'); 339 340 if type_.additional_properties is not None: 341 if type_.additional_properties.property_type == PropertyType.ANY: 342 c.Append('value->MergeDictionary(&additional_properties);') 343 else: 344 # Non-copyable types will be wrapped in a linked_ptr for inclusion in 345 # maps, so we need to unwrap them. 346 needs_unwrap = ( 347 not self._type_helper.IsCopyable(type_.additional_properties)) 348 cpp_type = self._type_helper.GetCppType(type_.additional_properties, 349 is_in_container=True) 350 (c.Sblock('for (std::map<std::string, %s>::const_iterator it =' % 351 cpp_util.PadForGenerics(cpp_type)) 352 .Append(' additional_properties.begin();') 353 .Append(' it != additional_properties.end(); ++it) {') 354 .Append('value->SetWithoutPathExpansion(it->first, %s);' % 355 self._CreateValueFromType( 356 type_.additional_properties, 357 '%sit->second' % ('*' if needs_unwrap else ''))) 358 .Eblock('}') 359 ) 360 361 return (c.Append() 362 .Append('return value.Pass();') 363 .Eblock('}')) 364 365 def _GenerateChoiceTypeToValue(self, cpp_namespace, type_): 366 """Generates a function that serializes a choice-representing type 367 into a base::Value. 368 """ 369 c = Code() 370 c.Sblock('scoped_ptr<base::Value> %s::ToValue() const {' % cpp_namespace) 371 c.Append('scoped_ptr<base::Value> result;'); 372 for choice in type_.choices: 373 choice_var = 'as_%s' % choice.unix_name 374 (c.Sblock('if (%s) {' % choice_var) 375 .Append('DCHECK(!result) << "Cannot set multiple choices for %s";' % 376 type_.unix_name) 377 .Append('result.reset(%s);' % 378 self._CreateValueFromType(choice, '*%s' % choice_var)) 379 .Eblock('}') 380 ) 381 (c.Append('DCHECK(result) << "Must set at least one choice for %s";' % 382 type_.unix_name) 383 .Append('return result.Pass();') 384 .Eblock('}') 385 ) 386 return c 387 388 def _GenerateFunction(self, function): 389 """Generates the definitions for function structs. 390 """ 391 c = Code() 392 393 # TODO(kalman): use function.unix_name not Classname. 394 function_namespace = cpp_util.Classname(function.name) 395 """Windows has a #define for SendMessage, so to avoid any issues, we need 396 to not use the name. 397 """ 398 if function_namespace == 'SendMessage': 399 function_namespace = 'PassMessage' 400 (c.Append('namespace %s {' % function_namespace) 401 .Append() 402 ) 403 404 # Params::Populate function 405 if function.params: 406 c.Concat(self._GeneratePropertyFunctions('Params', function.params)) 407 (c.Append('Params::Params() {}') 408 .Append('Params::~Params() {}') 409 .Append() 410 .Cblock(self._GenerateFunctionParamsCreate(function)) 411 ) 412 413 # Results::Create function 414 if function.callback: 415 c.Concat(self._GenerateCreateCallbackArguments('Results', 416 function.callback)) 417 418 c.Append('} // namespace %s' % function_namespace) 419 return c 420 421 def _GenerateEvent(self, event): 422 # TODO(kalman): use event.unix_name not Classname. 423 c = Code() 424 event_namespace = cpp_util.Classname(event.name) 425 (c.Append('namespace %s {' % event_namespace) 426 .Append() 427 .Cblock(self._GenerateCreateCallbackArguments(None, event)) 428 .Append('} // namespace %s' % event_namespace) 429 ) 430 return c 431 432 def _CreateValueFromType(self, type_, var, is_ptr=False): 433 """Creates a base::Value given a type. Generated code passes ownership 434 to caller. 435 436 var: variable or variable* 437 438 E.g for std::string, generate base::Value::CreateStringValue(var) 439 """ 440 underlying_type = self._type_helper.FollowRef(type_) 441 if (underlying_type.property_type == PropertyType.CHOICES or 442 underlying_type.property_type == PropertyType.OBJECT): 443 if is_ptr: 444 return '(%s)->ToValue().release()' % var 445 else: 446 return '(%s).ToValue().release()' % var 447 elif (underlying_type.property_type == PropertyType.ANY or 448 underlying_type.property_type == PropertyType.FUNCTION): 449 if is_ptr: 450 vardot = '(%s)->' % var 451 else: 452 vardot = '(%s).' % var 453 return '%sDeepCopy()' % vardot 454 elif underlying_type.property_type == PropertyType.ENUM: 455 return 'base::Value::CreateStringValue(ToString(%s))' % var 456 elif underlying_type.property_type == PropertyType.BINARY: 457 if is_ptr: 458 vardot = var + '->' 459 else: 460 vardot = var + '.' 461 return ('base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())' % 462 (vardot, vardot)) 463 elif underlying_type.property_type == PropertyType.ARRAY: 464 return '%s.release()' % self._util_cc_helper.CreateValueFromArray( 465 underlying_type, 466 var, 467 is_ptr) 468 elif underlying_type.property_type.is_fundamental: 469 if is_ptr: 470 var = '*%s' % var 471 if underlying_type.property_type == PropertyType.STRING: 472 return 'new base::StringValue(%s)' % var 473 else: 474 return 'new base::FundamentalValue(%s)' % var 475 else: 476 raise NotImplementedError('Conversion of %s to base::Value not ' 477 'implemented' % repr(type_.type_)) 478 479 def _GenerateParamsCheck(self, function, var): 480 """Generates a check for the correct number of arguments when creating 481 Params. 482 """ 483 c = Code() 484 num_required = 0 485 for param in function.params: 486 if not param.optional: 487 num_required += 1 488 if num_required == len(function.params): 489 c.Append('if (%(var)s.GetSize() != %(total)d)') 490 elif not num_required: 491 c.Append('if (%(var)s.GetSize() > %(total)d)') 492 else: 493 c.Append('if (%(var)s.GetSize() < %(required)d' 494 ' || %(var)s.GetSize() > %(total)d)') 495 c.Append(' return scoped_ptr<Params>();') 496 c.Substitute({ 497 'var': var, 498 'required': num_required, 499 'total': len(function.params), 500 }) 501 return c 502 503 def _GenerateFunctionParamsCreate(self, function): 504 """Generate function to create an instance of Params. The generated 505 function takes a base::ListValue of arguments. 506 507 E.g for function "Bar", generate Bar::Params::Create() 508 """ 509 c = Code() 510 (c.Append('// static') 511 .Sblock('scoped_ptr<Params> ' 512 'Params::Create(const base::ListValue& args) {') 513 .Concat(self._GenerateParamsCheck(function, 'args')) 514 .Append('scoped_ptr<Params> params(new Params());') 515 ) 516 517 for param in function.params: 518 c.Concat(self._InitializePropertyToDefault(param, 'params')) 519 520 for i, param in enumerate(function.params): 521 # Any failure will cause this function to return. If any argument is 522 # incorrect or missing, those following it are not processed. Note that 523 # for optional arguments, we allow missing arguments and proceed because 524 # there may be other arguments following it. 525 failure_value = 'scoped_ptr<Params>()' 526 c.Append() 527 value_var = param.unix_name + '_value' 528 (c.Append('const base::Value* %(value_var)s = NULL;') 529 .Append('if (args.Get(%(i)s, &%(value_var)s) &&') 530 .Sblock(' !%(value_var)s->IsType(base::Value::TYPE_NULL)) {') 531 .Concat(self._GeneratePopulatePropertyFromValue( 532 param, value_var, 'params', failure_value)) 533 .Eblock('}') 534 ) 535 if not param.optional: 536 (c.Sblock('else {') 537 .Append('return %s;' % failure_value) 538 .Eblock('}') 539 ) 540 c.Substitute({'value_var': value_var, 'i': i}) 541 (c.Append() 542 .Append('return params.Pass();') 543 .Eblock('}') 544 .Append() 545 ) 546 547 return c 548 549 def _GeneratePopulatePropertyFromValue(self, 550 prop, 551 src_var, 552 dst_class_var, 553 failure_value): 554 """Generates code to populate property |prop| of |dst_class_var| (a 555 pointer) from a Value*. See |_GeneratePopulateVariableFromValue| for 556 semantics. 557 """ 558 return self._GeneratePopulateVariableFromValue(prop.type_, 559 src_var, 560 '%s->%s' % (dst_class_var, 561 prop.unix_name), 562 failure_value, 563 is_ptr=prop.optional) 564 565 def _GeneratePopulateVariableFromValue(self, 566 type_, 567 src_var, 568 dst_var, 569 failure_value, 570 is_ptr=False): 571 """Generates code to populate a variable |dst_var| of type |type_| from a 572 Value* at |src_var|. The Value* is assumed to be non-NULL. In the generated 573 code, if |dst_var| fails to be populated then Populate will return 574 |failure_value|. 575 """ 576 c = Code() 577 c.Sblock('{') 578 579 underlying_type = self._type_helper.FollowRef(type_) 580 581 if underlying_type.property_type.is_fundamental: 582 if is_ptr: 583 (c.Append('%(cpp_type)s temp;') 584 .Append('if (!%s)' % cpp_util.GetAsFundamentalValue( 585 self._type_helper.FollowRef(type_), src_var, '&temp')) 586 .Append(' return %(failure_value)s;') 587 .Append('%(dst_var)s.reset(new %(cpp_type)s(temp));') 588 ) 589 else: 590 (c.Append('if (!%s)' % cpp_util.GetAsFundamentalValue( 591 self._type_helper.FollowRef(type_), 592 src_var, 593 '&%s' % dst_var)) 594 .Append(' return %(failure_value)s;') 595 ) 596 elif underlying_type.property_type == PropertyType.OBJECT: 597 if is_ptr: 598 (c.Append('const base::DictionaryValue* dictionary = NULL;') 599 .Append('if (!%(src_var)s->GetAsDictionary(&dictionary))') 600 .Append(' return %(failure_value)s;') 601 .Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());') 602 .Append('if (!%(cpp_type)s::Populate(*dictionary, temp.get()))') 603 .Append(' return %(failure_value)s;') 604 .Append('%(dst_var)s = temp.Pass();') 605 ) 606 else: 607 (c.Append('const base::DictionaryValue* dictionary = NULL;') 608 .Append('if (!%(src_var)s->GetAsDictionary(&dictionary))') 609 .Append(' return %(failure_value)s;') 610 .Append('if (!%(cpp_type)s::Populate(*dictionary, &%(dst_var)s))') 611 .Append(' return %(failure_value)s;') 612 ) 613 elif underlying_type.property_type == PropertyType.FUNCTION: 614 if is_ptr: 615 c.Append('%(dst_var)s.reset(new base::DictionaryValue());') 616 elif underlying_type.property_type == PropertyType.ANY: 617 c.Append('%(dst_var)s.reset(%(src_var)s->DeepCopy());') 618 elif underlying_type.property_type == PropertyType.ARRAY: 619 # util_cc_helper deals with optional and required arrays 620 (c.Append('const base::ListValue* list = NULL;') 621 .Append('if (!%(src_var)s->GetAsList(&list))') 622 .Append(' return %(failure_value)s;')) 623 item_type = underlying_type.item_type 624 if item_type.property_type == PropertyType.ENUM: 625 c.Concat(self._GenerateListValueToEnumArrayConversion( 626 item_type, 627 'list', 628 dst_var, 629 failure_value, 630 is_ptr=is_ptr)) 631 else: 632 (c.Append('if (!%s)' % self._util_cc_helper.PopulateArrayFromList( 633 underlying_type, 634 'list', 635 dst_var, 636 is_ptr)) 637 .Append(' return %(failure_value)s;') 638 ) 639 elif underlying_type.property_type == PropertyType.CHOICES: 640 if is_ptr: 641 (c.Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());') 642 .Append('if (!%(cpp_type)s::Populate(*%(src_var)s, temp.get()))') 643 .Append(' return %(failure_value)s;') 644 .Append('%(dst_var)s = temp.Pass();') 645 ) 646 else: 647 (c.Append('if (!%(cpp_type)s::Populate(*%(src_var)s, &%(dst_var)s))') 648 .Append(' return %(failure_value)s;') 649 ) 650 elif underlying_type.property_type == PropertyType.ENUM: 651 c.Concat(self._GenerateStringToEnumConversion(type_, 652 src_var, 653 dst_var, 654 failure_value)) 655 elif underlying_type.property_type == PropertyType.BINARY: 656 (c.Append('if (!%(src_var)s->IsType(base::Value::TYPE_BINARY))') 657 .Append(' return %(failure_value)s;') 658 .Append('const base::BinaryValue* binary_value =') 659 .Append(' static_cast<const base::BinaryValue*>(%(src_var)s);') 660 ) 661 if is_ptr: 662 (c.Append('%(dst_var)s.reset(') 663 .Append(' new std::string(binary_value->GetBuffer(),') 664 .Append(' binary_value->GetSize()));') 665 ) 666 else: 667 (c.Append('%(dst_var)s.assign(binary_value->GetBuffer(),') 668 .Append(' binary_value->GetSize());') 669 ) 670 else: 671 raise NotImplementedError(type_) 672 return c.Eblock('}').Substitute({ 673 'cpp_type': self._type_helper.GetCppType(type_), 674 'src_var': src_var, 675 'dst_var': dst_var, 676 'failure_value': failure_value, 677 }) 678 679 def _GenerateListValueToEnumArrayConversion(self, 680 item_type, 681 src_var, 682 dst_var, 683 failure_value, 684 is_ptr=False): 685 """Returns Code that converts a ListValue of string constants from 686 |src_var| into an array of enums of |type_| in |dst_var|. On failure, 687 returns |failure_value|. 688 """ 689 c = Code() 690 accessor = '.' 691 if is_ptr: 692 accessor = '->' 693 cpp_type = self._type_helper.GetCppType(item_type, is_in_container=True) 694 c.Append('%s.reset(new std::vector<%s>);' % 695 (dst_var, cpp_util.PadForGenerics(cpp_type))) 696 (c.Sblock('for (base::ListValue::const_iterator it = %s->begin(); ' 697 'it != %s->end(); ++it) {' % (src_var, src_var)) 698 .Append('%s tmp;' % self._type_helper.GetCppType(item_type)) 699 .Concat(self._GenerateStringToEnumConversion(item_type, 700 '(*it)', 701 'tmp', 702 failure_value)) 703 .Append('%s%spush_back(tmp);' % (dst_var, accessor)) 704 .Eblock('}') 705 ) 706 return c 707 708 def _GenerateStringToEnumConversion(self, 709 type_, 710 src_var, 711 dst_var, 712 failure_value): 713 """Returns Code that converts a string type in |src_var| to an enum with 714 type |type_| in |dst_var|. In the generated code, if |src_var| is not 715 a valid enum name then the function will return |failure_value|. 716 """ 717 c = Code() 718 enum_as_string = '%s_as_string' % type_.unix_name 719 (c.Append('std::string %s;' % enum_as_string) 720 .Append('if (!%s->GetAsString(&%s))' % (src_var, enum_as_string)) 721 .Append(' return %s;' % failure_value) 722 .Append('%s = Parse%s(%s);' % (dst_var, 723 self._type_helper.GetCppType(type_), 724 enum_as_string)) 725 .Append('if (%s == %s)' % (dst_var, 726 self._type_helper.GetEnumNoneValue(type_))) 727 .Append(' return %s;' % failure_value) 728 ) 729 return c 730 731 def _GeneratePropertyFunctions(self, namespace, params): 732 """Generates the member functions for a list of parameters. 733 """ 734 return self._GenerateTypes(namespace, (param.type_ for param in params)) 735 736 def _GenerateTypes(self, namespace, types): 737 """Generates the member functions for a list of types. 738 """ 739 c = Code() 740 for type_ in types: 741 c.Cblock(self._GenerateType(namespace, type_)) 742 return c 743 744 def _GenerateEnumToString(self, cpp_namespace, type_): 745 """Generates ToString() which gets the string representation of an enum. 746 """ 747 c = Code() 748 classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) 749 750 if cpp_namespace is not None: 751 c.Append('// static') 752 maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace 753 754 c.Sblock('std::string %sToString(%s enum_param) {' % 755 (maybe_namespace, classname)) 756 c.Sblock('switch (enum_param) {') 757 for enum_value in self._type_helper.FollowRef(type_).enum_values: 758 (c.Append('case %s: ' % self._type_helper.GetEnumValue(type_, enum_value)) 759 .Append(' return "%s";' % enum_value)) 760 (c.Append('case %s:' % self._type_helper.GetEnumNoneValue(type_)) 761 .Append(' return "";') 762 .Eblock('}') 763 .Append('NOTREACHED();') 764 .Append('return "";') 765 .Eblock('}') 766 ) 767 return c 768 769 def _GenerateEnumFromString(self, cpp_namespace, type_): 770 """Generates FromClassNameString() which gets an enum from its string 771 representation. 772 """ 773 c = Code() 774 classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) 775 776 if cpp_namespace is not None: 777 c.Append('// static') 778 maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace 779 780 c.Sblock('%s%s %sParse%s(const std::string& enum_string) {' % 781 (maybe_namespace, classname, maybe_namespace, classname)) 782 for i, enum_value in enumerate( 783 self._type_helper.FollowRef(type_).enum_values): 784 # This is broken up into all ifs with no else ifs because we get 785 # "fatal error C1061: compiler limit : blocks nested too deeply" 786 # on Windows. 787 (c.Append('if (enum_string == "%s")' % enum_value) 788 .Append(' return %s;' % 789 self._type_helper.GetEnumValue(type_, enum_value))) 790 (c.Append('return %s;' % self._type_helper.GetEnumNoneValue(type_)) 791 .Eblock('}') 792 ) 793 return c 794 795 def _GenerateCreateCallbackArguments(self, function_scope, callback): 796 """Generate all functions to create Value parameters for a callback. 797 798 E.g for function "Bar", generate Bar::Results::Create 799 E.g for event "Baz", generate Baz::Create 800 801 function_scope: the function scope path, e.g. Foo::Bar for the function 802 Foo::Bar::Baz(). May be None if there is no function scope. 803 callback: the Function object we are creating callback arguments for. 804 """ 805 c = Code() 806 params = callback.params 807 c.Concat(self._GeneratePropertyFunctions(function_scope, params)) 808 809 (c.Sblock('scoped_ptr<base::ListValue> %(function_scope)s' 810 'Create(%(declaration_list)s) {') 811 .Append('scoped_ptr<base::ListValue> create_results(' 812 'new base::ListValue());') 813 ) 814 declaration_list = [] 815 for param in params: 816 declaration_list.append(cpp_util.GetParameterDeclaration( 817 param, self._type_helper.GetCppType(param.type_))) 818 c.Append('create_results->Append(%s);' % 819 self._CreateValueFromType(param.type_, param.unix_name)) 820 c.Append('return create_results.Pass();') 821 c.Eblock('}') 822 c.Substitute({ 823 'function_scope': ('%s::' % function_scope) if function_scope else '', 824 'declaration_list': ', '.join(declaration_list), 825 'param_names': ', '.join(param.unix_name for param in params) 826 }) 827 return c 828 829 def _InitializePropertyToDefault(self, prop, dst): 830 """Initialize a model.Property to its default value inside an object. 831 832 E.g for optional enum "state", generate dst->state = STATE_NONE; 833 834 dst: Type* 835 """ 836 c = Code() 837 underlying_type = self._type_helper.FollowRef(prop.type_) 838 if (underlying_type.property_type == PropertyType.ENUM and 839 prop.optional): 840 c.Append('%s->%s = %s;' % ( 841 dst, 842 prop.unix_name, 843 self._type_helper.GetEnumNoneValue(prop.type_))) 844 return c 845