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
.short_filename
))
50 .Append('#include <set>')
51 .Cblock(self
._type
_helper
.GenerateIncludes(include_soft
=True))
53 .Append('using base::UTF8ToUTF16;')
55 .Concat(cpp_util
.OpenNamespace(self
._cpp
_namespace
))
56 .Cblock(self
._type
_helper
.GetNamespaceStart())
58 if self
._namespace
.properties
:
60 .Append('// Properties')
64 for property in self
._namespace
.properties
.values():
65 property_code
= self
._type
_helper
.GeneratePropertyValues(
67 'const %(type)s %(name)s = %(value)s;',
70 c
.Cblock(property_code
)
71 if self
._namespace
.types
:
76 .Cblock(self
._GenerateTypes
(None, self
._namespace
.types
.values()))
78 if self
._namespace
.functions
:
80 .Append('// Functions')
84 for function
in self
._namespace
.functions
.values():
85 c
.Cblock(self
._GenerateFunction
(function
))
86 if self
._namespace
.events
:
92 for event
in self
._namespace
.events
.values():
93 c
.Cblock(self
._GenerateEvent
(event
))
94 (c
.Concat(self
._type
_helper
.GetNamespaceEnd())
95 .Cblock(cpp_util
.CloseNamespace(self
._cpp
_namespace
))
100 def _GenerateType(self
, cpp_namespace
, type_
):
101 """Generates the function definitions for a type.
103 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
107 # Wrap functions within types in the type's namespace.
108 (c
.Append('namespace %s {' % classname
)
110 for function
in type_
.functions
.values():
111 c
.Cblock(self
._GenerateFunction
(function
))
112 c
.Append('} // namespace %s' % classname
)
113 elif type_
.property_type
== PropertyType
.ARRAY
:
114 c
.Cblock(self
._GenerateType
(cpp_namespace
, type_
.item_type
))
115 elif type_
.property_type
in (PropertyType
.CHOICES
,
116 PropertyType
.OBJECT
):
117 if cpp_namespace
is None:
118 classname_in_namespace
= classname
120 classname_in_namespace
= '%s::%s' % (cpp_namespace
, classname
)
122 if type_
.property_type
== PropertyType
.OBJECT
:
123 c
.Cblock(self
._GeneratePropertyFunctions
(classname_in_namespace
,
124 type_
.properties
.values()))
126 c
.Cblock(self
._GenerateTypes
(classname_in_namespace
, type_
.choices
))
128 (c
.Append('%s::%s()' % (classname_in_namespace
, classname
))
129 .Cblock(self
._GenerateInitializersAndBody
(type_
))
130 .Append('%s::~%s() {}' % (classname_in_namespace
, classname
))
133 if type_
.origin
.from_json
:
134 c
.Cblock(self
._GenerateTypePopulate
(classname_in_namespace
, type_
))
135 if cpp_namespace
is None: # only generate for top-level types
136 c
.Cblock(self
._GenerateTypeFromValue
(classname_in_namespace
, type_
))
137 if type_
.origin
.from_client
:
138 c
.Cblock(self
._GenerateTypeToValue
(classname_in_namespace
, type_
))
139 elif type_
.property_type
== PropertyType
.ENUM
:
140 (c
.Cblock(self
._GenerateEnumToString
(cpp_namespace
, type_
))
141 .Cblock(self
._GenerateEnumFromString
(cpp_namespace
, type_
))
146 def _GenerateInitializersAndBody(self
, type_
):
148 for prop
in type_
.properties
.values():
153 if t
.property_type
== PropertyType
.INTEGER
:
154 items
.append('%s(0)' % prop
.unix_name
)
155 elif t
.property_type
== PropertyType
.DOUBLE
:
156 items
.append('%s(0.0)' % prop
.unix_name
)
157 elif t
.property_type
== PropertyType
.BOOLEAN
:
158 items
.append('%s(false)' % prop
.unix_name
)
159 elif (t
.property_type
== PropertyType
.ANY
or
160 t
.property_type
== PropertyType
.ARRAY
or
161 t
.property_type
== PropertyType
.BINARY
or # mapped to std::string
162 t
.property_type
== PropertyType
.CHOICES
or
163 t
.property_type
== PropertyType
.ENUM
or
164 t
.property_type
== PropertyType
.OBJECT
or
165 t
.property_type
== PropertyType
.FUNCTION
or
166 t
.property_type
== PropertyType
.REF
or
167 t
.property_type
== PropertyType
.STRING
):
168 # TODO(miket): It would be nice to initialize CHOICES and ENUM, but we
169 # don't presently have the semantics to indicate which one of a set
170 # should be the default.
176 s
= ': %s' % (', '.join(items
))
180 return Code().Append(s
)
182 def _GenerateTypePopulate(self
, cpp_namespace
, type_
):
183 """Generates the function for populating a type given a pointer to it.
185 E.g for type "Foo", generates Foo::Populate()
187 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
189 (c
.Append('// static')
190 .Append('bool %(namespace)s::Populate(')
191 .Sblock(' %s) {' % self
._GenerateParams
(
192 ('const base::Value& value', '%(name)s* out'))))
194 if self
._generate
_error
_messages
:
195 c
.Append('DCHECK(error);')
197 if type_
.property_type
== PropertyType
.CHOICES
:
198 for choice
in type_
.choices
:
199 (c
.Sblock('if (%s) {' % self
._GenerateValueIsTypeExpression
('value',
201 .Concat(self
._GeneratePopulateVariableFromValue
(
204 'out->as_%s' % choice
.unix_name
,
207 .Append('return true;')
210 (c
.Concat(self
._GenerateError
(
211 '"expected %s, got " + %s' %
212 (" or ".join(choice
.name
for choice
in type_
.choices
),
213 self
._util
_cc
_helper
.GetValueTypeString('value'))))
214 .Append('return false;'))
215 elif type_
.property_type
== PropertyType
.OBJECT
:
216 (c
.Sblock('if (!value.IsType(base::Value::TYPE_DICTIONARY)) {')
217 .Concat(self
._GenerateError
(
218 '"expected dictionary, got " + ' +
219 self
._util
_cc
_helper
.GetValueTypeString('value')))
220 .Append('return false;')
223 if type_
.properties
or type_
.additional_properties
is not None:
224 c
.Append('const base::DictionaryValue* dict = '
225 'static_cast<const base::DictionaryValue*>(&value);')
226 if self
._generate
_error
_messages
:
227 c
.Append('std::set<std::string> keys;')
228 for prop
in type_
.properties
.itervalues():
229 c
.Concat(self
._InitializePropertyToDefault
(prop
, 'out'))
230 for prop
in type_
.properties
.itervalues():
231 if self
._generate
_error
_messages
:
232 c
.Append('keys.insert("%s");' % (prop
.name
))
233 c
.Concat(self
._GenerateTypePopulateProperty
(prop
, 'dict', 'out'))
234 # Check for extra values.
235 if self
._generate
_error
_messages
:
236 (c
.Sblock('for (base::DictionaryValue::Iterator it(*dict); '
237 '!it.IsAtEnd(); it.Advance()) {')
238 .Sblock('if (!keys.count(it.key())) {')
239 .Concat(self
._GenerateError
('"found unexpected key \'" + '
244 if type_
.additional_properties
is not None:
245 if type_
.additional_properties
.property_type
== PropertyType
.ANY
:
246 c
.Append('out->additional_properties.MergeDictionary(dict);')
248 cpp_type
= self
._type
_helper
.GetCppType(type_
.additional_properties
,
249 is_in_container
=True)
250 (c
.Append('for (base::DictionaryValue::Iterator it(*dict);')
251 .Sblock(' !it.IsAtEnd(); it.Advance()) {')
252 .Append('%s tmp;' % cpp_type
)
253 .Concat(self
._GeneratePopulateVariableFromValue
(
254 type_
.additional_properties
,
258 .Append('out->additional_properties[it.key()] = tmp;')
261 c
.Append('return true;')
263 .Substitute({'namespace': cpp_namespace
, 'name': classname
}))
266 def _GenerateValueIsTypeExpression(self
, var
, type_
):
267 real_type
= self
._type
_helper
.FollowRef(type_
)
268 if real_type
.property_type
is PropertyType
.CHOICES
:
269 return '(%s)' % ' || '.join(self
._GenerateValueIsTypeExpression
(var
,
271 for choice
in real_type
.choices
)
272 return '%s.IsType(%s)' % (var
, cpp_util
.GetValueType(real_type
))
274 def _GenerateTypePopulateProperty(self
, prop
, src
, dst
):
275 """Generate the code to populate a single property in a type.
277 src: base::DictionaryValue*
281 value_var
= prop
.unix_name
+ '_value'
282 c
.Append('const base::Value* %(value_var)s = NULL;')
285 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {')
286 .Concat(self
._GeneratePopulatePropertyFromValue
(
287 prop
, value_var
, dst
, 'false')))
288 underlying_type
= self
._type
_helper
.FollowRef(prop
.type_
)
289 if underlying_type
.property_type
== PropertyType
.ENUM
:
290 (c
.Append('} else {')
291 .Append('%%(dst)s->%%(name)s = %s;' %
292 self
._type
_helper
.GetEnumNoneValue(prop
.type_
)))
296 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {')
297 .Concat(self
._GenerateError
('"\'%%(key)s\' is required"'))
298 .Append('return false;')
300 .Concat(self
._GeneratePopulatePropertyFromValue
(
301 prop
, value_var
, dst
, 'false'))
305 'value_var': value_var
,
309 'name': prop
.unix_name
313 def _GenerateTypeFromValue(self
, cpp_namespace
, type_
):
314 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
316 (c
.Append('// static')
317 .Append('scoped_ptr<%s> %s::FromValue(%s) {' % (classname
,
318 cpp_namespace
, self
._GenerateParams
(('const base::Value& value',))))
320 if self
._generate
_error
_messages
:
321 c
.Append('DCHECK(error);')
322 (c
.Append(' scoped_ptr<%s> out(new %s());' % (classname
, classname
))
323 .Append(' if (!Populate(%s))' % self
._GenerateArgs
(
324 ('value', 'out.get()')))
325 .Append(' return scoped_ptr<%s>();' % classname
)
326 .Append(' return out.Pass();')
331 def _GenerateTypeToValue(self
, cpp_namespace
, type_
):
332 """Generates a function that serializes the type into a base::Value.
333 E.g. for type "Foo" generates Foo::ToValue()
335 if type_
.property_type
== PropertyType
.OBJECT
:
336 return self
._GenerateObjectTypeToValue
(cpp_namespace
, type_
)
337 elif type_
.property_type
== PropertyType
.CHOICES
:
338 return self
._GenerateChoiceTypeToValue
(cpp_namespace
, type_
)
340 raise ValueError("Unsupported property type %s" % type_
.type_
)
342 def _GenerateObjectTypeToValue(self
, cpp_namespace
, type_
):
343 """Generates a function that serializes an object-representing type
344 into a base::DictionaryValue.
347 (c
.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' %
349 .Append('scoped_ptr<base::DictionaryValue> value('
350 'new base::DictionaryValue());')
354 for prop
in type_
.properties
.values():
355 prop_var
= 'this->%s' % prop
.unix_name
357 # Optional enum values are generated with a NONE enum value.
358 underlying_type
= self
._type
_helper
.FollowRef(prop
.type_
)
359 if underlying_type
.property_type
== PropertyType
.ENUM
:
360 c
.Sblock('if (%s != %s) {' %
362 self
._type
_helper
.GetEnumNoneValue(prop
.type_
)))
364 c
.Sblock('if (%s.get()) {' % prop_var
)
366 # ANY is a base::Value which is abstract and cannot be a direct member, so
367 # it will always be a pointer.
368 is_ptr
= prop
.optional
or prop
.type_
.property_type
== PropertyType
.ANY
369 c
.Append('value->SetWithoutPathExpansion("%s", %s);' % (
371 self
._CreateValueFromType
(cpp_namespace
,
379 if type_
.additional_properties
is not None:
380 if type_
.additional_properties
.property_type
== PropertyType
.ANY
:
381 c
.Append('value->MergeDictionary(&additional_properties);')
383 # Non-copyable types will be wrapped in a linked_ptr for inclusion in
384 # maps, so we need to unwrap them.
386 not self
._type
_helper
.IsCopyable(type_
.additional_properties
))
387 cpp_type
= self
._type
_helper
.GetCppType(type_
.additional_properties
,
388 is_in_container
=True)
389 (c
.Sblock('for (std::map<std::string, %s>::const_iterator it =' %
390 cpp_util
.PadForGenerics(cpp_type
))
391 .Append(' additional_properties.begin();')
392 .Append(' it != additional_properties.end(); ++it) {')
393 .Append('value->SetWithoutPathExpansion(it->first, %s);' %
394 self
._CreateValueFromType
(
396 type_
.additional_properties
,
397 '%sit->second' % ('*' if needs_unwrap
else '')))
402 .Append('return value.Pass();')
405 def _GenerateChoiceTypeToValue(self
, cpp_namespace
, type_
):
406 """Generates a function that serializes a choice-representing type
410 c
.Sblock('scoped_ptr<base::Value> %s::ToValue() const {' % cpp_namespace
)
411 c
.Append('scoped_ptr<base::Value> result;')
412 for choice
in type_
.choices
:
413 choice_var
= 'as_%s' % choice
.unix_name
414 (c
.Sblock('if (%s) {' % choice_var
)
415 .Append('DCHECK(!result) << "Cannot set multiple choices for %s";' %
417 .Append('result.reset(%s);' % self
._CreateValueFromType
(
423 (c
.Append('DCHECK(result) << "Must set at least one choice for %s";' %
425 .Append('return result.Pass();')
430 def _GenerateFunction(self
, function
):
431 """Generates the definitions for function structs.
435 # TODO(kalman): use function.unix_name not Classname.
436 function_namespace
= cpp_util
.Classname(function
.name
)
437 # Windows has a #define for SendMessage, so to avoid any issues, we need
438 # to not use the name.
439 if function_namespace
== 'SendMessage':
440 function_namespace
= 'PassMessage'
441 (c
.Append('namespace %s {' % function_namespace
)
445 # Params::Populate function
447 c
.Concat(self
._GeneratePropertyFunctions
('Params', function
.params
))
448 (c
.Append('Params::Params() {}')
449 .Append('Params::~Params() {}')
451 .Cblock(self
._GenerateFunctionParamsCreate
(function
))
454 # Results::Create function
455 if function
.callback
:
456 c
.Concat(self
._GenerateCreateCallbackArguments
(function_namespace
,
460 c
.Append('} // namespace %s' % function_namespace
)
463 def _GenerateEvent(self
, event
):
464 # TODO(kalman): use event.unix_name not Classname.
466 event_namespace
= cpp_util
.Classname(event
.name
)
467 (c
.Append('namespace %s {' % event_namespace
)
469 .Cblock(self
._GenerateEventNameConstant
(None, event
))
470 .Cblock(self
._GenerateCreateCallbackArguments
(event_namespace
,
473 .Append('} // namespace %s' % event_namespace
)
477 def _CreateValueFromType(self
, cpp_namespace
, type_
, var
, is_ptr
=False):
478 """Creates a base::Value given a type. Generated code passes ownership
481 var: variable or variable*
483 E.g for std::string, generate new base::StringValue(var)
485 underlying_type
= self
._type
_helper
.FollowRef(type_
)
486 if (underlying_type
.property_type
== PropertyType
.CHOICES
or
487 underlying_type
.property_type
== PropertyType
.OBJECT
):
489 return '(%s)->ToValue().release()' % var
491 return '(%s).ToValue().release()' % var
492 elif (underlying_type
.property_type
== PropertyType
.ANY
or
493 underlying_type
.property_type
== PropertyType
.FUNCTION
):
495 vardot
= '(%s)->' % var
497 vardot
= '(%s).' % var
498 return '%sDeepCopy()' % vardot
499 elif underlying_type
.property_type
== PropertyType
.ENUM
:
501 if type_
.property_type
== PropertyType
.REF
:
502 maybe_namespace
= '%s::' % underlying_type
.namespace
.unix_name
503 return 'new base::StringValue(%sToString(%s))' % (maybe_namespace
, var
)
504 elif underlying_type
.property_type
== PropertyType
.BINARY
:
509 return ('base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())' %
511 elif underlying_type
.property_type
== PropertyType
.ARRAY
:
512 return '%s.release()' % self
._util
_cc
_helper
.CreateValueFromArray(
517 elif underlying_type
.property_type
.is_fundamental
:
520 if underlying_type
.property_type
== PropertyType
.STRING
:
521 return 'new base::StringValue(%s)' % var
523 return 'new base::FundamentalValue(%s)' % var
525 raise NotImplementedError('Conversion of %s to base::Value not '
526 'implemented' % repr(type_
.type_
))
528 def _GenerateParamsCheck(self
, function
, var
):
529 """Generates a check for the correct number of arguments when creating
534 for param
in function
.params
:
535 if not param
.optional
:
537 if num_required
== len(function
.params
):
538 c
.Sblock('if (%(var)s.GetSize() != %(total)d) {')
539 elif not num_required
:
540 c
.Sblock('if (%(var)s.GetSize() > %(total)d) {')
542 c
.Sblock('if (%(var)s.GetSize() < %(required)d'
543 ' || %(var)s.GetSize() > %(total)d) {')
544 (c
.Concat(self
._GenerateError
(
545 '"expected %%(total)d arguments, got " '
546 '+ base::IntToString(%%(var)s.GetSize())'))
547 .Append('return scoped_ptr<Params>();')
551 'required': num_required
,
552 'total': len(function
.params
),
556 def _GenerateFunctionParamsCreate(self
, function
):
557 """Generate function to create an instance of Params. The generated
558 function takes a base::ListValue of arguments.
560 E.g for function "Bar", generate Bar::Params::Create()
563 (c
.Append('// static')
564 .Sblock('scoped_ptr<Params> Params::Create(%s) {' % self
._GenerateParams
(
565 ['const base::ListValue& args']))
567 if self
._generate
_error
_messages
:
568 c
.Append('DCHECK(error);')
569 (c
.Concat(self
._GenerateParamsCheck
(function
, 'args'))
570 .Append('scoped_ptr<Params> params(new Params());')
573 for param
in function
.params
:
574 c
.Concat(self
._InitializePropertyToDefault
(param
, 'params'))
576 for i
, param
in enumerate(function
.params
):
577 # Any failure will cause this function to return. If any argument is
578 # incorrect or missing, those following it are not processed. Note that
579 # for optional arguments, we allow missing arguments and proceed because
580 # there may be other arguments following it.
581 failure_value
= 'scoped_ptr<Params>()'
583 value_var
= param
.unix_name
+ '_value'
584 (c
.Append('const base::Value* %(value_var)s = NULL;')
585 .Append('if (args.Get(%(i)s, &%(value_var)s) &&')
586 .Sblock(' !%(value_var)s->IsType(base::Value::TYPE_NULL)) {')
587 .Concat(self
._GeneratePopulatePropertyFromValue
(
588 param
, value_var
, 'params', failure_value
))
591 if not param
.optional
:
593 .Concat(self
._GenerateError
('"\'%%(key)s\' is required"'))
594 .Append('return %s;' % failure_value
)
596 c
.Substitute({'value_var': value_var
, 'i': i
, 'key': param
.name
})
598 .Append('return params.Pass();')
605 def _GeneratePopulatePropertyFromValue(self
,
610 """Generates code to populate property |prop| of |dst_class_var| (a
611 pointer) from a Value*. See |_GeneratePopulateVariableFromValue| for
614 return self
._GeneratePopulateVariableFromValue
(prop
.type_
,
616 '%s->%s' % (dst_class_var
,
619 is_ptr
=prop
.optional
)
621 def _GeneratePopulateVariableFromValue(self
,
627 """Generates code to populate a variable |dst_var| of type |type_| from a
628 Value* at |src_var|. The Value* is assumed to be non-NULL. In the generated
629 code, if |dst_var| fails to be populated then Populate will return
634 underlying_type
= self
._type
_helper
.FollowRef(type_
)
636 if underlying_type
.property_type
.is_fundamental
:
638 (c
.Append('%(cpp_type)s temp;')
639 .Sblock('if (!%s) {' % cpp_util
.GetAsFundamentalValue(
640 self
._type
_helper
.FollowRef(type_
), src_var
, '&temp'))
641 .Concat(self
._GenerateError
(
642 '"\'%%(key)s\': expected ' + '%s, got " + %s' % (
644 self
._util
_cc
_helper
.GetValueTypeString(
645 '%%(src_var)s', True)))))
646 c
.Append('%(dst_var)s.reset();')
647 if not self
._generate
_error
_messages
:
648 c
.Append('return %(failure_value)s;')
651 .Append(' %(dst_var)s.reset(new %(cpp_type)s(temp));')
654 (c
.Sblock('if (!%s) {' % cpp_util
.GetAsFundamentalValue(
655 self
._type
_helper
.FollowRef(type_
),
658 .Concat(self
._GenerateError
(
659 '"\'%%(key)s\': expected ' + '%s, got " + %s' % (
661 self
._util
_cc
_helper
.GetValueTypeString(
662 '%%(src_var)s', True))))
663 .Append('return %(failure_value)s;')
666 elif underlying_type
.property_type
== PropertyType
.OBJECT
:
668 (c
.Append('const base::DictionaryValue* dictionary = NULL;')
669 .Sblock('if (!%(src_var)s->GetAsDictionary(&dictionary)) {')
670 .Concat(self
._GenerateError
(
671 '"\'%%(key)s\': expected dictionary, got " + ' +
672 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True))))
673 # If an optional property fails to populate, the population can still
674 # succeed with a warning. If no error messages are generated, this
675 # warning is not set and we fail out instead.
676 if not self
._generate
_error
_messages
:
677 c
.Append('return %(failure_value)s;')
680 .Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());')
681 .Append('if (!%%(cpp_type)s::Populate(%s)) {' % self
._GenerateArgs
(
682 ('*dictionary', 'temp.get()')))
683 .Append(' return %(failure_value)s;')
687 .Append(' %(dst_var)s = temp.Pass();')
691 (c
.Append('const base::DictionaryValue* dictionary = NULL;')
692 .Sblock('if (!%(src_var)s->GetAsDictionary(&dictionary)) {')
693 .Concat(self
._GenerateError
(
694 '"\'%%(key)s\': expected dictionary, got " + ' +
695 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
696 .Append('return %(failure_value)s;')
698 .Append('if (!%%(cpp_type)s::Populate(%s)) {' % self
._GenerateArgs
(
699 ('*dictionary', '&%(dst_var)s')))
700 .Append(' return %(failure_value)s;')
703 elif underlying_type
.property_type
== PropertyType
.FUNCTION
:
705 c
.Append('%(dst_var)s.reset(new base::DictionaryValue());')
706 elif underlying_type
.property_type
== PropertyType
.ANY
:
707 c
.Append('%(dst_var)s.reset(%(src_var)s->DeepCopy());')
708 elif underlying_type
.property_type
== PropertyType
.ARRAY
:
709 # util_cc_helper deals with optional and required arrays
710 (c
.Append('const base::ListValue* list = NULL;')
711 .Sblock('if (!%(src_var)s->GetAsList(&list)) {')
712 .Concat(self
._GenerateError
(
713 '"\'%%(key)s\': expected list, got " + ' +
714 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
716 if is_ptr
and self
._generate
_error
_messages
:
717 c
.Append('%(dst_var)s.reset();')
719 c
.Append('return %(failure_value)s;')
722 item_type
= self
._type
_helper
.FollowRef(underlying_type
.item_type
)
723 if item_type
.property_type
== PropertyType
.ENUM
:
724 c
.Concat(self
._GenerateListValueToEnumArrayConversion
(
731 (c
.Sblock('if (!%s) {' % self
._util
_cc
_helper
.PopulateArrayFromList(
735 c
.Concat(self
._GenerateError
(
736 '"unable to populate array \'%%(parent_key)s\'"'))
737 if is_ptr
and self
._generate
_error
_messages
:
738 c
.Append('%(dst_var)s.reset();')
740 c
.Append('return %(failure_value)s;')
743 elif underlying_type
.property_type
== PropertyType
.CHOICES
:
745 (c
.Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());')
746 .Append('if (!%%(cpp_type)s::Populate(%s))' % self
._GenerateArgs
(
747 ('*%(src_var)s', 'temp.get()')))
748 .Append(' return %(failure_value)s;')
749 .Append('%(dst_var)s = temp.Pass();')
752 (c
.Append('if (!%%(cpp_type)s::Populate(%s))' % self
._GenerateArgs
(
753 ('*%(src_var)s', '&%(dst_var)s')))
754 .Append(' return %(failure_value)s;'))
755 elif underlying_type
.property_type
== PropertyType
.ENUM
:
756 c
.Concat(self
._GenerateStringToEnumConversion
(underlying_type
,
760 elif underlying_type
.property_type
== PropertyType
.BINARY
:
761 (c
.Append('const base::BinaryValue* binary_value = NULL;')
762 .Sblock('if (!%(src_var)s->IsType(base::Value::TYPE_BINARY)) {')
763 .Concat(self
._GenerateError
(
764 '"\'%%(key)s\': expected binary, got " + ' +
765 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
767 if not self
._generate
_error
_messages
:
768 c
.Append('return %(failure_value)s;')
771 .Append(' binary_value =')
772 .Append(' static_cast<const base::BinaryValue*>(%(src_var)s);')
775 (c
.Append('%(dst_var)s.reset(')
776 .Append(' new std::string(binary_value->GetBuffer(),')
777 .Append(' binary_value->GetSize()));')
780 (c
.Append('%(dst_var)s.assign(binary_value->GetBuffer(),')
781 .Append(' binary_value->GetSize());')
785 raise NotImplementedError(type_
)
788 return Code().Sblock('{').Concat(c
.Substitute({
789 'cpp_type': self
._type
_helper
.GetCppType(type_
),
792 'failure_value': failure_value
,
794 'parent_key': type_
.parent
.name
,
797 def _GenerateListValueToEnumArrayConversion(self
,
803 """Returns Code that converts a ListValue of string constants from
804 |src_var| into an array of enums of |type_| in |dst_var|. On failure,
805 returns |failure_value|.
811 cpp_type
= self
._type
_helper
.GetCppType(item_type
, is_in_container
=True)
812 c
.Append('%s.reset(new std::vector<%s>);' %
813 (dst_var
, cpp_util
.PadForGenerics(cpp_type
)))
814 (c
.Sblock('for (base::ListValue::const_iterator it = %s->begin(); '
815 'it != %s->end(); ++it) {' % (src_var
, src_var
))
816 .Append('%s tmp;' % self
._type
_helper
.GetCppType(item_type
))
817 .Concat(self
._GenerateStringToEnumConversion
(item_type
,
821 .Append('%s%spush_back(tmp);' % (dst_var
, accessor
))
826 def _GenerateStringToEnumConversion(self
,
831 """Returns Code that converts a string type in |src_var| to an enum with
832 type |type_| in |dst_var|. In the generated code, if |src_var| is not
833 a valid enum name then the function will return |failure_value|.
835 if type_
.property_type
!= PropertyType
.ENUM
:
836 raise TypeError(type_
)
838 enum_as_string
= '%s_as_string' % type_
.unix_name
839 cpp_type_namespace
= ''
840 if type_
.namespace
!= self
._namespace
:
841 cpp_type_namespace
= '%s::' % type_
.namespace
.unix_name
842 cpp_type_name
= self
._type
_helper
.GetCppType(type_
)
843 (c
.Append('std::string %s;' % enum_as_string
)
844 .Sblock('if (!%s->GetAsString(&%s)) {' % (src_var
, enum_as_string
))
845 .Concat(self
._GenerateError
(
846 '"\'%%(key)s\': expected string, got " + ' +
847 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
848 .Append('return %s;' % failure_value
)
850 .Append('%s = %sParse%s(%s);' % (dst_var
,
852 cpp_util
.Classname(type_
.name
),
854 .Sblock('if (%s == %s%s) {' % (dst_var
,
856 self
._type
_helper
.GetEnumNoneValue(type_
)))
857 .Concat(self
._GenerateError
(
858 '\"\'%%(key)s\': expected \\"' +
861 for enum_value
in self
._type
_helper
.FollowRef(type_
).enum_values
) +
862 '\\", got \\"" + %s + "\\""' % enum_as_string
))
863 .Append('return %s;' % failure_value
)
865 .Substitute({'src_var': src_var
, 'key': type_
.name
})
869 def _GeneratePropertyFunctions(self
, namespace
, params
):
870 """Generates the member functions for a list of parameters.
872 return self
._GenerateTypes
(namespace
, (param
.type_
for param
in params
))
874 def _GenerateTypes(self
, namespace
, types
):
875 """Generates the member functions for a list of types.
879 c
.Cblock(self
._GenerateType
(namespace
, type_
))
882 def _GenerateEnumToString(self
, cpp_namespace
, type_
):
883 """Generates ToString() which gets the string representation of an enum.
886 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
888 if cpp_namespace
is not None:
889 c
.Append('// static')
890 maybe_namespace
= '' if cpp_namespace
is None else '%s::' % cpp_namespace
892 c
.Sblock('std::string %sToString(%s enum_param) {' %
893 (maybe_namespace
, classname
))
894 c
.Sblock('switch (enum_param) {')
895 for enum_value
in self
._type
_helper
.FollowRef(type_
).enum_values
:
896 name
= enum_value
.name
897 if 'camel_case_enum_to_string' in self
._namespace
.compiler_options
:
898 name
= enum_value
.CamelName()
899 (c
.Append('case %s: ' % self
._type
_helper
.GetEnumValue(type_
, enum_value
))
900 .Append(' return "%s";' % name
))
901 (c
.Append('case %s:' % self
._type
_helper
.GetEnumNoneValue(type_
))
902 .Append(' return "";')
904 .Append('NOTREACHED();')
905 .Append('return "";')
910 def _GenerateEnumFromString(self
, cpp_namespace
, type_
):
911 """Generates FromClassNameString() which gets an enum from its string
915 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
917 if cpp_namespace
is not None:
918 c
.Append('// static')
919 maybe_namespace
= '' if cpp_namespace
is None else '%s::' % cpp_namespace
921 c
.Sblock('%s%s %sParse%s(const std::string& enum_string) {' %
922 (maybe_namespace
, classname
, maybe_namespace
, classname
))
923 for i
, enum_value
in enumerate(
924 self
._type
_helper
.FollowRef(type_
).enum_values
):
925 # This is broken up into all ifs with no else ifs because we get
926 # "fatal error C1061: compiler limit : blocks nested too deeply"
928 (c
.Append('if (enum_string == "%s")' % enum_value
.name
)
929 .Append(' return %s;' %
930 self
._type
_helper
.GetEnumValue(type_
, enum_value
)))
931 (c
.Append('return %s;' % self
._type
_helper
.GetEnumNoneValue(type_
))
936 def _GenerateCreateCallbackArguments(self
,
940 """Generate all functions to create Value parameters for a callback.
942 E.g for function "Bar", generate Bar::Results::Create
943 E.g for event "Baz", generate Baz::Create
945 function_scope: the function scope path, e.g. Foo::Bar for the function
946 Foo::Bar::Baz(). May be None if there is no function scope.
947 callback: the Function object we are creating callback arguments for.
950 params
= callback
.params
951 c
.Concat(self
._GeneratePropertyFunctions
(function_scope
, params
))
953 (c
.Sblock('scoped_ptr<base::ListValue> %(function_scope)s'
954 'Create(%(declaration_list)s) {')
955 .Append('scoped_ptr<base::ListValue> create_results('
956 'new base::ListValue());')
958 declaration_list
= []
960 declaration_list
.append(cpp_util
.GetParameterDeclaration(
961 param
, self
._type
_helper
.GetCppType(param
.type_
)))
962 c
.Append('create_results->Append(%s);' % self
._CreateValueFromType
(
966 c
.Append('return create_results.Pass();')
969 'function_scope': ('%s::' % function_scope
) if function_scope
else '',
970 'declaration_list': ', '.join(declaration_list
),
971 'param_names': ', '.join(param
.unix_name
for param
in params
)
975 def _GenerateEventNameConstant(self
, function_scope
, event
):
976 """Generates a constant string array for the event name.
979 c
.Append('const char kEventName[] = "%s.%s";' % (
980 self
._namespace
.name
, event
.name
))
983 def _InitializePropertyToDefault(self
, prop
, dst
):
984 """Initialize a model.Property to its default value inside an object.
986 E.g for optional enum "state", generate dst->state = STATE_NONE;
991 underlying_type
= self
._type
_helper
.FollowRef(prop
.type_
)
992 if (underlying_type
.property_type
== PropertyType
.ENUM
and
994 c
.Append('%s->%s = %s;' % (
997 self
._type
_helper
.GetEnumNoneValue(prop
.type_
)))
1000 def _GenerateError(self
, body
):
1001 """Generates an error message pertaining to population failure.
1003 E.g 'expected bool, got int'
1006 if not self
._generate
_error
_messages
:
1008 (c
.Append('if (error->length())')
1009 .Append(' error->append(UTF8ToUTF16("; "));')
1010 .Append('error->append(UTF8ToUTF16(%s));' % body
))
1013 def _GenerateParams(self
, params
):
1014 """Builds the parameter list for a function, given an array of parameters.
1016 if self
._generate
_error
_messages
:
1017 params
= list(params
) + ['base::string16* error']
1018 return ', '.join(str(p
) for p
in params
)
1020 def _GenerateArgs(self
, args
):
1021 """Builds the argument list for a function, given an array of arguments.
1023 if self
._generate
_error
_messages
:
1024 args
= list(args
) + ['error']
1025 return ', '.join(str(a
) for a
in args
)