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