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.
6 from model
import PropertyType
11 class CCGenerator(object):
12 def __init__(self
, type_generator
, cpp_namespace
):
13 self
._type
_generator
= type_generator
14 self
._cpp
_namespace
= cpp_namespace
16 def Generate(self
, namespace
):
17 return _Generator(namespace
,
19 self
._cpp
_namespace
).Generate()
22 class _Generator(object):
23 """A .cc generator for a namespace.
25 def __init__(self
, namespace
, cpp_type_generator
, cpp_namespace
):
26 self
._namespace
= namespace
27 self
._type
_helper
= cpp_type_generator
28 self
._cpp
_namespace
= cpp_namespace
29 self
._target
_namespace
= (
30 self
._type
_helper
.GetCppNamespaceName(self
._namespace
))
31 self
._util
_cc
_helper
= (
32 util_cc_helper
.UtilCCHelper(self
._type
_helper
))
33 self
._generate
_error
_messages
= namespace
.compiler_options
.get(
34 'generate_error_messages', False)
37 """Generates a Code object with the .cc for a single namespace.
40 (c
.Append(cpp_util
.CHROMIUM_LICENSE
)
42 .Append(cpp_util
.GENERATED_FILE_MESSAGE
% self
._namespace
.source_file
)
44 .Append(self
._util
_cc
_helper
.GetIncludePath())
45 .Append('#include "base/logging.h"')
46 .Append('#include "base/strings/string_number_conversions.h"')
47 .Append('#include "base/strings/utf_string_conversions.h"')
48 .Append('#include "%s/%s.h"' %
49 (self
._namespace
.source_file_dir
, self
._namespace
.unix_name
))
50 .Cblock(self
._type
_helper
.GenerateIncludes(include_soft
=True))
52 .Concat(cpp_util
.OpenNamespace(self
._cpp
_namespace
))
53 .Cblock(self
._type
_helper
.GetNamespaceStart())
55 if self
._namespace
.properties
:
57 .Append('// Properties')
61 for property in self
._namespace
.properties
.values():
62 property_code
= self
._type
_helper
.GeneratePropertyValues(
64 'const %(type)s %(name)s = %(value)s;',
67 c
.Cblock(property_code
)
68 if self
._namespace
.types
:
73 .Cblock(self
._GenerateTypes
(None, self
._namespace
.types
.values()))
75 if self
._namespace
.functions
:
77 .Append('// Functions')
81 for function
in self
._namespace
.functions
.values():
82 c
.Cblock(self
._GenerateFunction
(function
))
83 if self
._namespace
.events
:
89 for event
in self
._namespace
.events
.values():
90 c
.Cblock(self
._GenerateEvent
(event
))
91 (c
.Concat(self
._type
_helper
.GetNamespaceEnd())
92 .Cblock(cpp_util
.CloseNamespace(self
._cpp
_namespace
))
96 def _GenerateType(self
, cpp_namespace
, type_
):
97 """Generates the function definitions for a type.
99 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
103 # Wrap functions within types in the type's namespace.
104 (c
.Append('namespace %s {' % classname
)
106 for function
in type_
.functions
.values():
107 c
.Cblock(self
._GenerateFunction
(function
))
108 c
.Append('} // namespace %s' % classname
)
109 elif type_
.property_type
== PropertyType
.ARRAY
:
110 c
.Cblock(self
._GenerateType
(cpp_namespace
, type_
.item_type
))
111 elif type_
.property_type
in (PropertyType
.CHOICES
,
112 PropertyType
.OBJECT
):
113 if cpp_namespace
is None:
114 classname_in_namespace
= classname
116 classname_in_namespace
= '%s::%s' % (cpp_namespace
, classname
)
118 if type_
.property_type
== PropertyType
.OBJECT
:
119 c
.Cblock(self
._GeneratePropertyFunctions
(classname_in_namespace
,
120 type_
.properties
.values()))
122 c
.Cblock(self
._GenerateTypes
(classname_in_namespace
, type_
.choices
))
124 (c
.Append('%s::%s()' % (classname_in_namespace
, classname
))
125 .Cblock(self
._GenerateInitializersAndBody
(type_
))
126 .Append('%s::~%s() {}' % (classname_in_namespace
, classname
))
129 if type_
.origin
.from_json
:
130 c
.Cblock(self
._GenerateTypePopulate
(classname_in_namespace
, type_
))
131 if cpp_namespace
is None: # only generate for top-level types
132 c
.Cblock(self
._GenerateTypeFromValue
(classname_in_namespace
, type_
))
133 if type_
.origin
.from_client
:
134 c
.Cblock(self
._GenerateTypeToValue
(classname_in_namespace
, type_
))
135 elif type_
.property_type
== PropertyType
.ENUM
:
136 (c
.Cblock(self
._GenerateEnumToString
(cpp_namespace
, type_
))
137 .Cblock(self
._GenerateEnumFromString
(cpp_namespace
, type_
))
142 def _GenerateInitializersAndBody(self
, type_
):
144 for prop
in type_
.properties
.values():
149 if t
.property_type
== PropertyType
.INTEGER
:
150 items
.append('%s(0)' % prop
.unix_name
)
151 elif t
.property_type
== PropertyType
.DOUBLE
:
152 items
.append('%s(0.0)' % prop
.unix_name
)
153 elif t
.property_type
== PropertyType
.BOOLEAN
:
154 items
.append('%s(false)' % prop
.unix_name
)
155 elif (t
.property_type
== PropertyType
.ANY
or
156 t
.property_type
== PropertyType
.ARRAY
or
157 t
.property_type
== PropertyType
.BINARY
or # mapped to std::string
158 t
.property_type
== PropertyType
.CHOICES
or
159 t
.property_type
== PropertyType
.ENUM
or
160 t
.property_type
== PropertyType
.OBJECT
or
161 t
.property_type
== PropertyType
.FUNCTION
or
162 t
.property_type
== PropertyType
.REF
or
163 t
.property_type
== PropertyType
.STRING
):
164 # TODO(miket): It would be nice to initialize CHOICES and ENUM, but we
165 # don't presently have the semantics to indicate which one of a set
166 # should be the default.
172 s
= ': %s' % (', '.join(items
))
176 return Code().Append(s
)
178 def _GenerateTypePopulate(self
, cpp_namespace
, type_
):
179 """Generates the function for populating a type given a pointer to it.
181 E.g for type "Foo", generates Foo::Populate()
183 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
185 (c
.Append('// static')
186 .Append('bool %(namespace)s::Populate(')
187 .Sblock(' %s) {' % self
._GenerateParams
(
188 ('const base::Value& value', '%(name)s* out'))))
190 if type_
.property_type
== PropertyType
.CHOICES
:
191 for choice
in type_
.choices
:
192 (c
.Sblock('if (%s) {' % self
._GenerateValueIsTypeExpression
('value',
194 .Concat(self
._GeneratePopulateVariableFromValue
(
197 'out->as_%s' % choice
.unix_name
,
200 .Append('return true;')
203 (c
.Concat(self
._GenerateError
(
204 '"expected %s, got " + %s' %
205 (" or ".join(choice
.name
for choice
in type_
.choices
),
206 self
._util
_cc
_helper
.GetValueTypeString('value'))))
207 .Append('return false;'))
208 elif type_
.property_type
== PropertyType
.OBJECT
:
209 (c
.Sblock('if (!value.IsType(base::Value::TYPE_DICTIONARY)) {')
210 .Concat(self
._GenerateError
(
211 '"expected dictionary, got " + ' +
212 self
._util
_cc
_helper
.GetValueTypeString('value')))
213 .Append('return false;')
216 if type_
.properties
or type_
.additional_properties
is not None:
217 c
.Append('const base::DictionaryValue* dict = '
218 'static_cast<const base::DictionaryValue*>(&value);')
219 for prop
in type_
.properties
.values():
220 c
.Concat(self
._InitializePropertyToDefault
(prop
, 'out'))
221 for prop
in type_
.properties
.values():
222 c
.Concat(self
._GenerateTypePopulateProperty
(prop
, 'dict', 'out'))
223 if type_
.additional_properties
is not None:
224 if type_
.additional_properties
.property_type
== PropertyType
.ANY
:
225 c
.Append('out->additional_properties.MergeDictionary(dict);')
227 cpp_type
= self
._type
_helper
.GetCppType(type_
.additional_properties
,
228 is_in_container
=True)
229 (c
.Append('for (base::DictionaryValue::Iterator it(*dict);')
230 .Sblock(' !it.IsAtEnd(); it.Advance()) {')
231 .Append('%s tmp;' % cpp_type
)
232 .Concat(self
._GeneratePopulateVariableFromValue
(
233 type_
.additional_properties
,
237 .Append('out->additional_properties[it.key()] = tmp;')
240 c
.Append('return true;')
242 .Substitute({'namespace': cpp_namespace
, 'name': classname
}))
245 def _GenerateValueIsTypeExpression(self
, var
, type_
):
246 real_type
= self
._type
_helper
.FollowRef(type_
)
247 if real_type
.property_type
is PropertyType
.CHOICES
:
248 return '(%s)' % ' || '.join(self
._GenerateValueIsTypeExpression
(var
,
250 for choice
in real_type
.choices
)
251 return '%s.IsType(%s)' % (var
, cpp_util
.GetValueType(real_type
))
253 def _GenerateTypePopulateProperty(self
, prop
, src
, dst
):
254 """Generate the code to populate a single property in a type.
256 src: base::DictionaryValue*
260 value_var
= prop
.unix_name
+ '_value'
261 c
.Append('const base::Value* %(value_var)s = NULL;')
264 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {')
265 .Concat(self
._GeneratePopulatePropertyFromValue
(
266 prop
, value_var
, dst
, 'false')))
267 underlying_type
= self
._type
_helper
.FollowRef(prop
.type_
)
268 if underlying_type
.property_type
== PropertyType
.ENUM
:
269 (c
.Append('} else {')
270 .Append('%%(dst)s->%%(name)s = %s;' %
271 self
._type
_helper
.GetEnumNoneValue(prop
.type_
)))
275 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {')
276 .Concat(self
._GenerateError
('"\'%%(key)s\' is required"'))
277 .Append('return false;')
279 .Concat(self
._GeneratePopulatePropertyFromValue
(
280 prop
, value_var
, dst
, 'false'))
284 'value_var': value_var
,
288 'name': prop
.unix_name
292 def _GenerateTypeFromValue(self
, cpp_namespace
, type_
):
293 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
295 (c
.Append('// static')
296 .Append('scoped_ptr<%s> %s::FromValue(%s) {' % (classname
,
297 cpp_namespace
, self
._GenerateParams
(('const base::Value& value',))))
298 .Append(' scoped_ptr<%s> out(new %s());' % (classname
, classname
))
299 .Append(' if (!Populate(%s))' % self
._GenerateArgs
(
300 ('value', 'out.get()')))
301 .Append(' return scoped_ptr<%s>();' % classname
)
302 .Append(' return out.Pass();')
307 def _GenerateTypeToValue(self
, cpp_namespace
, type_
):
308 """Generates a function that serializes the type into a base::Value.
309 E.g. for type "Foo" generates Foo::ToValue()
311 if type_
.property_type
== PropertyType
.OBJECT
:
312 return self
._GenerateObjectTypeToValue
(cpp_namespace
, type_
)
313 elif type_
.property_type
== PropertyType
.CHOICES
:
314 return self
._GenerateChoiceTypeToValue
(cpp_namespace
, type_
)
316 raise ValueError("Unsupported property type %s" % type_
.type_
)
318 def _GenerateObjectTypeToValue(self
, cpp_namespace
, type_
):
319 """Generates a function that serializes an object-representing type
320 into a base::DictionaryValue.
323 (c
.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' %
325 .Append('scoped_ptr<base::DictionaryValue> value('
326 'new base::DictionaryValue());')
330 for prop
in type_
.properties
.values():
332 # Optional enum values are generated with a NONE enum value.
333 underlying_type
= self
._type
_helper
.FollowRef(prop
.type_
)
334 if underlying_type
.property_type
== PropertyType
.ENUM
:
335 c
.Sblock('if (%s != %s) {' %
337 self
._type
_helper
.GetEnumNoneValue(prop
.type_
)))
339 c
.Sblock('if (%s.get()) {' % prop
.unix_name
)
341 # ANY is a base::Value which is abstract and cannot be a direct member, so
342 # it will always be a pointer.
343 is_ptr
= prop
.optional
or prop
.type_
.property_type
== PropertyType
.ANY
344 c
.Append('value->SetWithoutPathExpansion("%s", %s);' % (
346 self
._CreateValueFromType
(prop
.type_
,
347 'this->%s' % prop
.unix_name
,
353 if type_
.additional_properties
is not None:
354 if type_
.additional_properties
.property_type
== PropertyType
.ANY
:
355 c
.Append('value->MergeDictionary(&additional_properties);')
357 # Non-copyable types will be wrapped in a linked_ptr for inclusion in
358 # maps, so we need to unwrap them.
360 not self
._type
_helper
.IsCopyable(type_
.additional_properties
))
361 cpp_type
= self
._type
_helper
.GetCppType(type_
.additional_properties
,
362 is_in_container
=True)
363 (c
.Sblock('for (std::map<std::string, %s>::const_iterator it =' %
364 cpp_util
.PadForGenerics(cpp_type
))
365 .Append(' additional_properties.begin();')
366 .Append(' it != additional_properties.end(); ++it) {')
367 .Append('value->SetWithoutPathExpansion(it->first, %s);' %
368 self
._CreateValueFromType
(
369 type_
.additional_properties
,
370 '%sit->second' % ('*' if needs_unwrap
else '')))
375 .Append('return value.Pass();')
378 def _GenerateChoiceTypeToValue(self
, cpp_namespace
, type_
):
379 """Generates a function that serializes a choice-representing type
383 c
.Sblock('scoped_ptr<base::Value> %s::ToValue() const {' % cpp_namespace
)
384 c
.Append('scoped_ptr<base::Value> result;')
385 for choice
in type_
.choices
:
386 choice_var
= 'as_%s' % choice
.unix_name
387 (c
.Sblock('if (%s) {' % choice_var
)
388 .Append('DCHECK(!result) << "Cannot set multiple choices for %s";' %
390 .Append('result.reset(%s);' %
391 self
._CreateValueFromType
(choice
, '*%s' % choice_var
))
394 (c
.Append('DCHECK(result) << "Must set at least one choice for %s";' %
396 .Append('return result.Pass();')
401 def _GenerateFunction(self
, function
):
402 """Generates the definitions for function structs.
406 # TODO(kalman): use function.unix_name not Classname.
407 function_namespace
= cpp_util
.Classname(function
.name
)
408 # Windows has a #define for SendMessage, so to avoid any issues, we need
409 # to not use the name.
410 if function_namespace
== 'SendMessage':
411 function_namespace
= 'PassMessage'
412 (c
.Append('namespace %s {' % function_namespace
)
416 # Params::Populate function
418 c
.Concat(self
._GeneratePropertyFunctions
('Params', function
.params
))
419 (c
.Append('Params::Params() {}')
420 .Append('Params::~Params() {}')
422 .Cblock(self
._GenerateFunctionParamsCreate
(function
))
425 # Results::Create function
426 if function
.callback
:
427 c
.Concat(self
._GenerateCreateCallbackArguments
('Results',
430 c
.Append('} // namespace %s' % function_namespace
)
433 def _GenerateEvent(self
, event
):
434 # TODO(kalman): use event.unix_name not Classname.
436 event_namespace
= cpp_util
.Classname(event
.name
)
437 (c
.Append('namespace %s {' % event_namespace
)
439 .Cblock(self
._GenerateEventNameConstant
(None, event
))
440 .Cblock(self
._GenerateCreateCallbackArguments
(None, event
))
441 .Append('} // namespace %s' % event_namespace
)
445 def _CreateValueFromType(self
, type_
, var
, is_ptr
=False):
446 """Creates a base::Value given a type. Generated code passes ownership
449 var: variable or variable*
451 E.g for std::string, generate new base::StringValue(var)
453 underlying_type
= self
._type
_helper
.FollowRef(type_
)
454 if (underlying_type
.property_type
== PropertyType
.CHOICES
or
455 underlying_type
.property_type
== PropertyType
.OBJECT
):
457 return '(%s)->ToValue().release()' % var
459 return '(%s).ToValue().release()' % var
460 elif (underlying_type
.property_type
== PropertyType
.ANY
or
461 underlying_type
.property_type
== PropertyType
.FUNCTION
):
463 vardot
= '(%s)->' % var
465 vardot
= '(%s).' % var
466 return '%sDeepCopy()' % vardot
467 elif underlying_type
.property_type
== PropertyType
.ENUM
:
468 return 'new base::StringValue(ToString(%s))' % var
469 elif underlying_type
.property_type
== PropertyType
.BINARY
:
474 return ('base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())' %
476 elif underlying_type
.property_type
== PropertyType
.ARRAY
:
477 return '%s.release()' % self
._util
_cc
_helper
.CreateValueFromArray(
481 elif underlying_type
.property_type
.is_fundamental
:
484 if underlying_type
.property_type
== PropertyType
.STRING
:
485 return 'new base::StringValue(%s)' % var
487 return 'new base::FundamentalValue(%s)' % var
489 raise NotImplementedError('Conversion of %s to base::Value not '
490 'implemented' % repr(type_
.type_
))
492 def _GenerateParamsCheck(self
, function
, var
):
493 """Generates a check for the correct number of arguments when creating
498 for param
in function
.params
:
499 if not param
.optional
:
501 if num_required
== len(function
.params
):
502 c
.Sblock('if (%(var)s.GetSize() != %(total)d) {')
503 elif not num_required
:
504 c
.Sblock('if (%(var)s.GetSize() > %(total)d) {')
506 c
.Sblock('if (%(var)s.GetSize() < %(required)d'
507 ' || %(var)s.GetSize() > %(total)d) {')
508 (c
.Concat(self
._GenerateError
(
509 '"expected %%(total)d arguments, got " '
510 '+ base::IntToString(%%(var)s.GetSize())'))
511 .Append('return scoped_ptr<Params>();')
515 'required': num_required
,
516 'total': len(function
.params
),
520 def _GenerateFunctionParamsCreate(self
, function
):
521 """Generate function to create an instance of Params. The generated
522 function takes a base::ListValue of arguments.
524 E.g for function "Bar", generate Bar::Params::Create()
527 (c
.Append('// static')
528 .Sblock('scoped_ptr<Params> Params::Create(%s) {' % self
._GenerateParams
(
529 ['const base::ListValue& args']))
530 .Concat(self
._GenerateParamsCheck
(function
, 'args'))
531 .Append('scoped_ptr<Params> params(new Params());'))
533 for param
in function
.params
:
534 c
.Concat(self
._InitializePropertyToDefault
(param
, 'params'))
536 for i
, param
in enumerate(function
.params
):
537 # Any failure will cause this function to return. If any argument is
538 # incorrect or missing, those following it are not processed. Note that
539 # for optional arguments, we allow missing arguments and proceed because
540 # there may be other arguments following it.
541 failure_value
= 'scoped_ptr<Params>()'
543 value_var
= param
.unix_name
+ '_value'
544 (c
.Append('const base::Value* %(value_var)s = NULL;')
545 .Append('if (args.Get(%(i)s, &%(value_var)s) &&')
546 .Sblock(' !%(value_var)s->IsType(base::Value::TYPE_NULL)) {')
547 .Concat(self
._GeneratePopulatePropertyFromValue
(
548 param
, value_var
, 'params', failure_value
))
551 if not param
.optional
:
553 .Concat(self
._GenerateError
('"\'%%(key)s\' is required"'))
554 .Append('return %s;' % failure_value
)
556 c
.Substitute({'value_var': value_var
, 'i': i
, 'key': param
.name
})
558 .Append('return params.Pass();')
565 def _GeneratePopulatePropertyFromValue(self
,
570 """Generates code to populate property |prop| of |dst_class_var| (a
571 pointer) from a Value*. See |_GeneratePopulateVariableFromValue| for
574 return self
._GeneratePopulateVariableFromValue
(prop
.type_
,
576 '%s->%s' % (dst_class_var
,
579 is_ptr
=prop
.optional
)
581 def _GeneratePopulateVariableFromValue(self
,
587 """Generates code to populate a variable |dst_var| of type |type_| from a
588 Value* at |src_var|. The Value* is assumed to be non-NULL. In the generated
589 code, if |dst_var| fails to be populated then Populate will return
595 underlying_type
= self
._type
_helper
.FollowRef(type_
)
597 if underlying_type
.property_type
.is_fundamental
:
599 (c
.Append('%(cpp_type)s temp;')
600 .Sblock('if (!%s) {' % cpp_util
.GetAsFundamentalValue(
601 self
._type
_helper
.FollowRef(type_
), src_var
, '&temp'))
602 .Concat(self
._GenerateError
(
603 '"\'%%(key)s\': expected ' + '%s, got " + %s' % (
605 self
._util
_cc
_helper
.GetValueTypeString(
606 '%%(src_var)s', True))))
607 .Append('return %(failure_value)s;')
609 .Append('%(dst_var)s.reset(new %(cpp_type)s(temp));')
612 (c
.Sblock('if (!%s) {' % cpp_util
.GetAsFundamentalValue(
613 self
._type
_helper
.FollowRef(type_
),
616 .Concat(self
._GenerateError
(
617 '"\'%%(key)s\': expected ' + '%s, got " + %s' % (
619 self
._util
_cc
_helper
.GetValueTypeString(
620 '%%(src_var)s', True))))
621 .Append('return %(failure_value)s;')
624 elif underlying_type
.property_type
== PropertyType
.OBJECT
:
626 (c
.Append('const base::DictionaryValue* dictionary = NULL;')
627 .Sblock('if (!%(src_var)s->GetAsDictionary(&dictionary)) {')
628 .Concat(self
._GenerateError
(
629 '"\'%%(key)s\': expected dictionary, got " + ' +
630 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
631 .Append('return %(failure_value)s;')
633 .Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());')
634 .Append('if (!%%(cpp_type)s::Populate(%s)) {' % self
._GenerateArgs
(
635 ('*dictionary', 'temp.get()')))
636 .Append(' return %(failure_value)s;')
638 .Append('%(dst_var)s = temp.Pass();')
641 (c
.Append('const base::DictionaryValue* dictionary = NULL;')
642 .Sblock('if (!%(src_var)s->GetAsDictionary(&dictionary)) {')
643 .Concat(self
._GenerateError
(
644 '"\'%%(key)s\': expected dictionary, got " + ' +
645 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
646 .Append('return %(failure_value)s;')
648 .Append('if (!%%(cpp_type)s::Populate(%s)) {' % self
._GenerateArgs
(
649 ('*dictionary', '&%(dst_var)s')))
650 .Append(' return %(failure_value)s;')
653 elif underlying_type
.property_type
== PropertyType
.FUNCTION
:
655 c
.Append('%(dst_var)s.reset(new base::DictionaryValue());')
656 elif underlying_type
.property_type
== PropertyType
.ANY
:
657 c
.Append('%(dst_var)s.reset(%(src_var)s->DeepCopy());')
658 elif underlying_type
.property_type
== PropertyType
.ARRAY
:
659 # util_cc_helper deals with optional and required arrays
660 (c
.Append('const base::ListValue* list = NULL;')
661 .Sblock('if (!%(src_var)s->GetAsList(&list)) {')
662 .Concat(self
._GenerateError
(
663 '"\'%%(key)s\': expected list, got " + ' +
664 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
665 .Append('return %(failure_value)s;')
667 item_type
= self
._type
_helper
.FollowRef(underlying_type
.item_type
)
668 if item_type
.property_type
== PropertyType
.ENUM
:
669 c
.Concat(self
._GenerateListValueToEnumArrayConversion
(
676 (c
.Sblock('if (!%s) {' % self
._util
_cc
_helper
.PopulateArrayFromList(
681 .Concat(self
._GenerateError
(
682 '"unable to populate array \'%%(parent_key)s\'"'))
683 .Append('return %(failure_value)s;')
686 elif underlying_type
.property_type
== PropertyType
.CHOICES
:
688 (c
.Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());')
689 .Append('if (!%%(cpp_type)s::Populate(%s))' % self
._GenerateArgs
(
690 ('*%(src_var)s', 'temp.get()')))
691 .Append(' return %(failure_value)s;')
692 .Append('%(dst_var)s = temp.Pass();')
695 (c
.Append('if (!%%(cpp_type)s::Populate(%s))' % self
._GenerateArgs
(
696 ('*%(src_var)s', '&%(dst_var)s')))
697 .Append(' return %(failure_value)s;'))
698 elif underlying_type
.property_type
== PropertyType
.ENUM
:
699 c
.Concat(self
._GenerateStringToEnumConversion
(type_
,
703 elif underlying_type
.property_type
== PropertyType
.BINARY
:
704 (c
.Sblock('if (!%(src_var)s->IsType(base::Value::TYPE_BINARY)) {')
705 .Concat(self
._GenerateError
(
706 '"\'%%(key)s\': expected binary, got " + ' +
707 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
708 .Append('return %(failure_value)s;')
710 .Append('const base::BinaryValue* binary_value =')
711 .Append(' static_cast<const base::BinaryValue*>(%(src_var)s);')
714 (c
.Append('%(dst_var)s.reset(')
715 .Append(' new std::string(binary_value->GetBuffer(),')
716 .Append(' binary_value->GetSize()));')
719 (c
.Append('%(dst_var)s.assign(binary_value->GetBuffer(),')
720 .Append(' binary_value->GetSize());')
723 raise NotImplementedError(type_
)
724 return c
.Eblock('}').Substitute({
725 'cpp_type': self
._type
_helper
.GetCppType(type_
),
728 'failure_value': failure_value
,
730 'parent_key': type_
.parent
.name
733 def _GenerateListValueToEnumArrayConversion(self
,
739 """Returns Code that converts a ListValue of string constants from
740 |src_var| into an array of enums of |type_| in |dst_var|. On failure,
741 returns |failure_value|.
747 cpp_type
= self
._type
_helper
.GetCppType(item_type
, is_in_container
=True)
748 c
.Append('%s.reset(new std::vector<%s>);' %
749 (dst_var
, cpp_util
.PadForGenerics(cpp_type
)))
750 (c
.Sblock('for (base::ListValue::const_iterator it = %s->begin(); '
751 'it != %s->end(); ++it) {' % (src_var
, src_var
))
752 .Append('%s tmp;' % self
._type
_helper
.GetCppType(item_type
))
753 .Concat(self
._GenerateStringToEnumConversion
(item_type
,
757 .Append('%s%spush_back(tmp);' % (dst_var
, accessor
))
762 def _GenerateStringToEnumConversion(self
,
767 """Returns Code that converts a string type in |src_var| to an enum with
768 type |type_| in |dst_var|. In the generated code, if |src_var| is not
769 a valid enum name then the function will return |failure_value|.
772 enum_as_string
= '%s_as_string' % type_
.unix_name
773 (c
.Append('std::string %s;' % enum_as_string
)
774 .Sblock('if (!%s->GetAsString(&%s)) {' % (src_var
, enum_as_string
))
775 .Concat(self
._GenerateError
(
776 '"\'%%(key)s\': expected string, got " + ' +
777 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
778 .Append('return %s;' % failure_value
)
780 .Append('%s = Parse%s(%s);' % (dst_var
,
781 self
._type
_helper
.GetCppType(type_
),
783 .Sblock('if (%s == %s) {' % (dst_var
,
784 self
._type
_helper
.GetEnumNoneValue(type_
)))
785 .Concat(self
._GenerateError
(
786 '\"\'%%(key)s\': expected \\"' +
787 '\\" or \\"'.join(self
._type
_helper
.FollowRef(type_
).enum_values
) +
788 '\\", got \\"" + %s + "\\""' % enum_as_string
))
789 .Append('return %s;' % failure_value
)
791 .Substitute({'src_var': src_var
, 'key': type_
.name
})
795 def _GeneratePropertyFunctions(self
, namespace
, params
):
796 """Generates the member functions for a list of parameters.
798 return self
._GenerateTypes
(namespace
, (param
.type_
for param
in params
))
800 def _GenerateTypes(self
, namespace
, types
):
801 """Generates the member functions for a list of types.
805 c
.Cblock(self
._GenerateType
(namespace
, type_
))
808 def _GenerateEnumToString(self
, cpp_namespace
, type_
):
809 """Generates ToString() which gets the string representation of an enum.
812 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
814 if cpp_namespace
is not None:
815 c
.Append('// static')
816 maybe_namespace
= '' if cpp_namespace
is None else '%s::' % cpp_namespace
818 c
.Sblock('std::string %sToString(%s enum_param) {' %
819 (maybe_namespace
, classname
))
820 c
.Sblock('switch (enum_param) {')
821 for enum_value
in self
._type
_helper
.FollowRef(type_
).enum_values
:
822 (c
.Append('case %s: ' % self
._type
_helper
.GetEnumValue(type_
, enum_value
))
823 .Append(' return "%s";' % enum_value
))
824 (c
.Append('case %s:' % self
._type
_helper
.GetEnumNoneValue(type_
))
825 .Append(' return "";')
827 .Append('NOTREACHED();')
828 .Append('return "";')
833 def _GenerateEnumFromString(self
, cpp_namespace
, type_
):
834 """Generates FromClassNameString() which gets an enum from its string
838 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
840 if cpp_namespace
is not None:
841 c
.Append('// static')
842 maybe_namespace
= '' if cpp_namespace
is None else '%s::' % cpp_namespace
844 c
.Sblock('%s%s %sParse%s(const std::string& enum_string) {' %
845 (maybe_namespace
, classname
, maybe_namespace
, classname
))
846 for i
, enum_value
in enumerate(
847 self
._type
_helper
.FollowRef(type_
).enum_values
):
848 # This is broken up into all ifs with no else ifs because we get
849 # "fatal error C1061: compiler limit : blocks nested too deeply"
851 (c
.Append('if (enum_string == "%s")' % enum_value
)
852 .Append(' return %s;' %
853 self
._type
_helper
.GetEnumValue(type_
, enum_value
)))
854 (c
.Append('return %s;' % self
._type
_helper
.GetEnumNoneValue(type_
))
859 def _GenerateCreateCallbackArguments(self
, function_scope
, callback
):
860 """Generate all functions to create Value parameters for a callback.
862 E.g for function "Bar", generate Bar::Results::Create
863 E.g for event "Baz", generate Baz::Create
865 function_scope: the function scope path, e.g. Foo::Bar for the function
866 Foo::Bar::Baz(). May be None if there is no function scope.
867 callback: the Function object we are creating callback arguments for.
870 params
= callback
.params
871 c
.Concat(self
._GeneratePropertyFunctions
(function_scope
, params
))
873 (c
.Sblock('scoped_ptr<base::ListValue> %(function_scope)s'
874 'Create(%(declaration_list)s) {')
875 .Append('scoped_ptr<base::ListValue> create_results('
876 'new base::ListValue());')
878 declaration_list
= []
880 declaration_list
.append(cpp_util
.GetParameterDeclaration(
881 param
, self
._type
_helper
.GetCppType(param
.type_
)))
882 c
.Append('create_results->Append(%s);' %
883 self
._CreateValueFromType
(param
.type_
, param
.unix_name
))
884 c
.Append('return create_results.Pass();')
887 'function_scope': ('%s::' % function_scope
) if function_scope
else '',
888 'declaration_list': ', '.join(declaration_list
),
889 'param_names': ', '.join(param
.unix_name
for param
in params
)
893 def _GenerateEventNameConstant(self
, function_scope
, event
):
894 """Generates a constant string array for the event name.
897 c
.Append('const char kEventName[] = "%s.%s";' % (
898 self
._namespace
.name
, event
.name
))
901 def _InitializePropertyToDefault(self
, prop
, dst
):
902 """Initialize a model.Property to its default value inside an object.
904 E.g for optional enum "state", generate dst->state = STATE_NONE;
909 underlying_type
= self
._type
_helper
.FollowRef(prop
.type_
)
910 if (underlying_type
.property_type
== PropertyType
.ENUM
and
912 c
.Append('%s->%s = %s;' % (
915 self
._type
_helper
.GetEnumNoneValue(prop
.type_
)))
918 def _GenerateError(self
, body
):
919 """Generates an error message pertaining to population failure.
921 E.g 'expected bool, got int'
924 if not self
._generate
_error
_messages
:
926 (c
.Append('if (error)')
927 .Append(' *error = UTF8ToUTF16(' + body
+ ');'))
930 def _GenerateParams(self
, params
):
931 """Builds the parameter list for a function, given an array of parameters.
933 if self
._generate
_error
_messages
:
934 params
= list(params
) + ['base::string16* error']
935 return ', '.join(str(p
) for p
in params
)
937 def _GenerateArgs(self
, args
):
938 """Builds the argument list for a function, given an array of arguments.
940 if self
._generate
_error
_messages
:
941 args
= list(args
) + ['error']
942 return ', '.join(str(a
) for a
in args
)