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
10 from cpp_namespace_environment
import CppNamespaceEnvironment
12 class CCGenerator(object):
13 def __init__(self
, type_generator
):
14 self
._type
_generator
= type_generator
16 def Generate(self
, namespace
):
17 return _Generator(namespace
, self
._type
_generator
).Generate()
20 class _Generator(object):
21 """A .cc generator for a namespace.
23 def __init__(self
, namespace
, cpp_type_generator
):
24 assert type(namespace
.environment
) is CppNamespaceEnvironment
25 self
._namespace
= namespace
26 self
._type
_helper
= cpp_type_generator
27 self
._util
_cc
_helper
= (
28 util_cc_helper
.UtilCCHelper(self
._type
_helper
))
29 self
._generate
_error
_messages
= namespace
.compiler_options
.get(
30 'generate_error_messages', False)
33 """Generates a Code object with the .cc for a single namespace.
35 cpp_namespace
= cpp_util
.GetCppNamespace(
36 self
._namespace
.environment
.namespace_pattern
,
37 self
._namespace
.unix_name
)
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/stl_util.h"')
47 .Append('#include "base/strings/string_number_conversions.h"')
48 .Append('#include "base/strings/utf_string_conversions.h"')
49 .Append('#include "%s/%s.h"' %
50 (self
._namespace
.source_file_dir
, self
._namespace
.short_filename
))
51 .Append('#include <set>')
52 .Cblock(self
._type
_helper
.GenerateIncludes(include_soft
=True))
54 .Append('using base::UTF8ToUTF16;')
56 .Concat(cpp_util
.OpenNamespace(cpp_namespace
))
58 if self
._namespace
.properties
:
60 .Append('// Properties')
64 for prop
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
.Cblock(cpp_util
.CloseNamespace(cpp_namespace
))
98 def _GenerateType(self
, cpp_namespace
, type_
):
99 """Generates the function definitions for a type.
101 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
105 # Wrap functions within types in the type's namespace.
106 (c
.Append('namespace %s {' % classname
)
108 for function
in type_
.functions
.values():
109 c
.Cblock(self
._GenerateFunction
(function
))
110 c
.Append('} // namespace %s' % classname
)
111 elif type_
.property_type
== PropertyType
.ARRAY
:
112 c
.Cblock(self
._GenerateType
(cpp_namespace
, type_
.item_type
))
113 elif type_
.property_type
in (PropertyType
.CHOICES
,
114 PropertyType
.OBJECT
):
115 if cpp_namespace
is None:
116 classname_in_namespace
= classname
118 classname_in_namespace
= '%s::%s' % (cpp_namespace
, classname
)
120 if type_
.property_type
== PropertyType
.OBJECT
:
121 c
.Cblock(self
._GeneratePropertyFunctions
(classname_in_namespace
,
122 type_
.properties
.values()))
124 c
.Cblock(self
._GenerateTypes
(classname_in_namespace
, type_
.choices
))
126 (c
.Append('%s::%s()' % (classname_in_namespace
, classname
))
127 .Cblock(self
._GenerateInitializersAndBody
(type_
))
128 .Append('%s::~%s() {}' % (classname_in_namespace
, classname
))
131 if type_
.origin
.from_json
:
132 c
.Cblock(self
._GenerateTypePopulate
(classname_in_namespace
, type_
))
133 if cpp_namespace
is None: # only generate for top-level types
134 c
.Cblock(self
._GenerateTypeFromValue
(classname_in_namespace
, type_
))
135 if type_
.origin
.from_client
:
136 c
.Cblock(self
._GenerateTypeToValue
(classname_in_namespace
, type_
))
137 elif type_
.property_type
== PropertyType
.ENUM
:
138 (c
.Cblock(self
._GenerateEnumToString
(cpp_namespace
, type_
))
139 .Cblock(self
._GenerateEnumFromString
(cpp_namespace
, type_
))
144 def _GenerateInitializersAndBody(self
, type_
):
146 for prop
in type_
.properties
.values():
149 real_t
= self
._type
_helper
.FollowRef(t
)
150 if real_t
.property_type
== PropertyType
.ENUM
:
151 namespace_prefix
= ('%s::' % real_t
.namespace
.unix_name
152 if real_t
.namespace
!= self
._namespace
154 items
.append('%s(%s%s)' % (prop
.unix_name
,
156 self
._type
_helper
.GetEnumNoneValue(t
)))
159 elif t
.property_type
== PropertyType
.INTEGER
:
160 items
.append('%s(0)' % prop
.unix_name
)
161 elif t
.property_type
== PropertyType
.DOUBLE
:
162 items
.append('%s(0.0)' % prop
.unix_name
)
163 elif t
.property_type
== PropertyType
.BOOLEAN
:
164 items
.append('%s(false)' % prop
.unix_name
)
165 elif (t
.property_type
== PropertyType
.ANY
or
166 t
.property_type
== PropertyType
.ARRAY
or
167 t
.property_type
== PropertyType
.BINARY
or
168 t
.property_type
== PropertyType
.CHOICES
or
169 t
.property_type
== PropertyType
.OBJECT
or
170 t
.property_type
== PropertyType
.FUNCTION
or
171 t
.property_type
== PropertyType
.REF
or
172 t
.property_type
== PropertyType
.STRING
):
173 # TODO(miket): It would be nice to initialize CHOICES, but we
174 # don't presently have the semantics to indicate which one of a set
175 # should be the default.
181 s
= ': %s' % (', '.join(items
))
185 return Code().Append(s
)
187 def _GenerateTypePopulate(self
, cpp_namespace
, type_
):
188 """Generates the function for populating a type given a pointer to it.
190 E.g for type "Foo", generates Foo::Populate()
192 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
194 (c
.Append('// static')
195 .Append('bool %(namespace)s::Populate(')
196 .Sblock(' %s) {' % self
._GenerateParams
(
197 ('const base::Value& value', '%(name)s* out'))))
199 if self
._generate
_error
_messages
:
200 c
.Append('DCHECK(error);')
202 if type_
.property_type
== PropertyType
.CHOICES
:
203 for choice
in type_
.choices
:
204 (c
.Sblock('if (%s) {' % self
._GenerateValueIsTypeExpression
('value',
206 .Concat(self
._GeneratePopulateVariableFromValue
(
209 'out->as_%s' % choice
.unix_name
,
212 .Append('return true;')
215 (c
.Concat(self
._GenerateError
(
216 '"expected %s, got " + %s' %
217 (" or ".join(choice
.name
for choice
in type_
.choices
),
218 self
._util
_cc
_helper
.GetValueTypeString('value'))))
219 .Append('return false;'))
220 elif type_
.property_type
== PropertyType
.OBJECT
:
221 (c
.Sblock('if (!value.IsType(base::Value::TYPE_DICTIONARY)) {')
222 .Concat(self
._GenerateError
(
223 '"expected dictionary, got " + ' +
224 self
._util
_cc
_helper
.GetValueTypeString('value')))
225 .Append('return false;')
228 if type_
.properties
or type_
.additional_properties
is not None:
229 c
.Append('const base::DictionaryValue* dict = '
230 'static_cast<const base::DictionaryValue*>(&value);')
231 if self
._generate
_error
_messages
:
232 c
.Append('std::set<std::string> keys;')
233 for prop
in type_
.properties
.itervalues():
234 c
.Concat(self
._InitializePropertyToDefault
(prop
, 'out'))
235 for prop
in type_
.properties
.itervalues():
236 if self
._generate
_error
_messages
:
237 c
.Append('keys.insert("%s");' % (prop
.name
))
238 c
.Concat(self
._GenerateTypePopulateProperty
(prop
, 'dict', 'out'))
239 # Check for extra values.
240 if self
._generate
_error
_messages
:
241 (c
.Sblock('for (base::DictionaryValue::Iterator it(*dict); '
242 '!it.IsAtEnd(); it.Advance()) {')
243 .Sblock('if (!keys.count(it.key())) {')
244 .Concat(self
._GenerateError
('"found unexpected key \'" + '
249 if type_
.additional_properties
is not None:
250 if type_
.additional_properties
.property_type
== PropertyType
.ANY
:
251 c
.Append('out->additional_properties.MergeDictionary(dict);')
253 cpp_type
= self
._type
_helper
.GetCppType(type_
.additional_properties
,
254 is_in_container
=True)
255 (c
.Append('for (base::DictionaryValue::Iterator it(*dict);')
256 .Sblock(' !it.IsAtEnd(); it.Advance()) {')
257 .Append('%s tmp;' % cpp_type
)
258 .Concat(self
._GeneratePopulateVariableFromValue
(
259 type_
.additional_properties
,
263 .Append('out->additional_properties[it.key()] = tmp;')
266 c
.Append('return true;')
268 .Substitute({'namespace': cpp_namespace
, 'name': classname
}))
271 def _GenerateValueIsTypeExpression(self
, var
, type_
):
272 real_type
= self
._type
_helper
.FollowRef(type_
)
273 if real_type
.property_type
is PropertyType
.CHOICES
:
274 return '(%s)' % ' || '.join(self
._GenerateValueIsTypeExpression
(var
,
276 for choice
in real_type
.choices
)
277 return '%s.IsType(%s)' % (var
, cpp_util
.GetValueType(real_type
))
279 def _GenerateTypePopulateProperty(self
, prop
, src
, dst
):
280 """Generate the code to populate a single property in a type.
282 src: base::DictionaryValue*
286 value_var
= prop
.unix_name
+ '_value'
287 c
.Append('const base::Value* %(value_var)s = NULL;')
290 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {')
291 .Concat(self
._GeneratePopulatePropertyFromValue
(
292 prop
, value_var
, dst
, 'false')))
293 underlying_type
= self
._type
_helper
.FollowRef(prop
.type_
)
294 if underlying_type
.property_type
== PropertyType
.ENUM
:
295 namespace_prefix
= ('%s::' % underlying_type
.namespace
.unix_name
296 if underlying_type
.namespace
!= self
._namespace
298 (c
.Append('} else {')
299 .Append('%%(dst)s->%%(name)s = %s%s;' %
301 self
._type
_helper
.GetEnumNoneValue(prop
.type_
))))
305 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {')
306 .Concat(self
._GenerateError
('"\'%%(key)s\' is required"'))
307 .Append('return false;')
309 .Concat(self
._GeneratePopulatePropertyFromValue
(
310 prop
, value_var
, dst
, 'false'))
314 'value_var': value_var
,
318 'name': prop
.unix_name
322 def _GenerateTypeFromValue(self
, cpp_namespace
, type_
):
323 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
325 (c
.Append('// static')
326 .Append('scoped_ptr<%s> %s::FromValue(%s) {' % (classname
,
327 cpp_namespace
, self
._GenerateParams
(('const base::Value& value',))))
329 if self
._generate
_error
_messages
:
330 c
.Append('DCHECK(error);')
331 (c
.Append(' scoped_ptr<%s> out(new %s());' % (classname
, classname
))
332 .Append(' if (!Populate(%s))' % self
._GenerateArgs
(
333 ('value', 'out.get()')))
334 .Append(' return scoped_ptr<%s>();' % classname
)
335 .Append(' return out.Pass();')
340 def _GenerateTypeToValue(self
, cpp_namespace
, type_
):
341 """Generates a function that serializes the type into a base::Value.
342 E.g. for type "Foo" generates Foo::ToValue()
344 if type_
.property_type
== PropertyType
.OBJECT
:
345 return self
._GenerateObjectTypeToValue
(cpp_namespace
, type_
)
346 elif type_
.property_type
== PropertyType
.CHOICES
:
347 return self
._GenerateChoiceTypeToValue
(cpp_namespace
, type_
)
349 raise ValueError("Unsupported property type %s" % type_
.type_
)
351 def _GenerateObjectTypeToValue(self
, cpp_namespace
, type_
):
352 """Generates a function that serializes an object-representing type
353 into a base::DictionaryValue.
356 (c
.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' %
358 .Append('scoped_ptr<base::DictionaryValue> value('
359 'new base::DictionaryValue());')
363 for prop
in type_
.properties
.values():
364 prop_var
= 'this->%s' % prop
.unix_name
366 underlying_type
= self
._type
_helper
.FollowRef(prop
.type_
)
367 if underlying_type
.property_type
== PropertyType
.ENUM
:
368 # Optional enum values are generated with a NONE enum value,
369 # potentially from another namespace.
371 if underlying_type
.namespace
!= self
._namespace
:
372 maybe_namespace
= '%s::' % underlying_type
.namespace
.unix_name
373 c
.Sblock('if (%s != %s%s) {' %
376 self
._type
_helper
.GetEnumNoneValue(prop
.type_
)))
378 c
.Sblock('if (%s.get()) {' % prop_var
)
380 # ANY is a base::Value which is abstract and cannot be a direct member, so
381 # it will always be a pointer.
382 is_ptr
= prop
.optional
or prop
.type_
.property_type
== PropertyType
.ANY
383 c
.Cblock(self
._CreateValueFromType
(
384 'value->SetWithoutPathExpansion("%s", %%s);' % prop
.name
,
393 if type_
.additional_properties
is not None:
394 if type_
.additional_properties
.property_type
== PropertyType
.ANY
:
395 c
.Append('value->MergeDictionary(&additional_properties);')
397 # Non-copyable types will be wrapped in a linked_ptr for inclusion in
398 # maps, so we need to unwrap them.
400 not self
._type
_helper
.IsCopyable(type_
.additional_properties
))
401 (c
.Sblock('for (const auto& it : additional_properties) {')
402 .Cblock(self
._CreateValueFromType
(
403 'value->SetWithoutPathExpansion(it.first, %s);',
404 type_
.additional_properties
.name
,
405 type_
.additional_properties
,
406 '%sit.second' % ('*' if needs_unwrap
else '')))
411 .Append('return value.Pass();')
414 def _GenerateChoiceTypeToValue(self
, cpp_namespace
, type_
):
415 """Generates a function that serializes a choice-representing type
419 c
.Sblock('scoped_ptr<base::Value> %s::ToValue() const {' % cpp_namespace
)
420 c
.Append('scoped_ptr<base::Value> result;')
421 for choice
in type_
.choices
:
422 choice_var
= 'as_%s' % choice
.unix_name
423 # Enums cannot be wrapped with scoped_ptr, but the XXX_NONE enum value
425 (c
.Sblock('if (%s) {' % choice_var
)
426 .Append('DCHECK(!result) << "Cannot set multiple choices for %s";' %
428 .Cblock(self
._CreateValueFromType
('result.reset(%s);',
435 (c
.Append('DCHECK(result) << "Must set at least one choice for %s";' %
437 .Append('return result.Pass();')
442 def _GenerateFunction(self
, function
):
443 """Generates the definitions for function structs.
447 # TODO(kalman): use function.unix_name not Classname.
448 function_namespace
= cpp_util
.Classname(function
.name
)
449 # Windows has a #define for SendMessage, so to avoid any issues, we need
450 # to not use the name.
451 if function_namespace
== 'SendMessage':
452 function_namespace
= 'PassMessage'
453 (c
.Append('namespace %s {' % function_namespace
)
457 # Params::Populate function
459 c
.Concat(self
._GeneratePropertyFunctions
('Params', function
.params
))
460 (c
.Append('Params::Params() {}')
461 .Append('Params::~Params() {}')
463 .Cblock(self
._GenerateFunctionParamsCreate
(function
))
466 # Results::Create function
467 if function
.callback
:
468 c
.Concat(self
._GenerateCreateCallbackArguments
('Results',
471 c
.Append('} // namespace %s' % function_namespace
)
474 def _GenerateEvent(self
, event
):
475 # TODO(kalman): use event.unix_name not Classname.
477 event_namespace
= cpp_util
.Classname(event
.name
)
478 (c
.Append('namespace %s {' % event_namespace
)
480 .Cblock(self
._GenerateEventNameConstant
(event
))
481 .Cblock(self
._GenerateCreateCallbackArguments
(None, event
))
482 .Append('} // namespace %s' % event_namespace
)
486 def _CreateValueFromType(self
, code
, prop_name
, type_
, var
, is_ptr
=False):
487 """Creates a base::Value given a type. Generated code passes ownership
490 var: variable or variable*
492 E.g for std::string, generate new base::StringValue(var)
495 underlying_type
= self
._type
_helper
.FollowRef(type_
)
496 if underlying_type
.property_type
== PropertyType
.ARRAY
:
497 # Enums are treated specially because C++ templating thinks that they're
498 # ints, but really they're strings. So we create a vector of strings and
499 # populate it with the names of the enum in the array. The |ToString|
500 # function of the enum can be in another namespace when the enum is
501 # referenced. Templates can not be used here because C++ templating does
502 # not support passing a namespace as an argument.
503 item_type
= self
._type
_helper
.FollowRef(underlying_type
.item_type
)
504 if item_type
.property_type
== PropertyType
.ENUM
:
505 varname
= ('*' if is_ptr
else '') + '(%s)' % var
508 if type_
.item_type
.property_type
== PropertyType
.REF
:
509 maybe_namespace
= '%s::' % item_type
.namespace
.unix_name
511 enum_list_var
= '%s_list' % prop_name
512 # Scope the std::vector variable declaration inside braces.
514 .Append('std::vector<std::string> %s;' % enum_list_var
)
515 .Append('for (const auto& it : %s) {' % varname
)
516 .Append('%s.push_back(%sToString(it));' % (enum_list_var
,
520 # Because the std::vector above is always created for both required and
521 # optional enum arrays, |is_ptr| is set to false and uses the
522 # std::vector to create the values.
524 self
._GenerateCreateValueFromType
(type_
, enum_list_var
, False))
528 c
.Append(code
% self
._GenerateCreateValueFromType
(type_
, var
, is_ptr
))
531 def _GenerateCreateValueFromType(self
, type_
, var
, is_ptr
):
532 """Generates the statement to create a base::Value given a type.
534 type_: The type of the values being converted.
535 var: The name of the variable.
536 is_ptr: Whether |type_| is optional.
538 underlying_type
= self
._type
_helper
.FollowRef(type_
)
539 if (underlying_type
.property_type
== PropertyType
.CHOICES
or
540 underlying_type
.property_type
== PropertyType
.OBJECT
):
542 return '(%s)->ToValue().release()' % var
544 return '(%s).ToValue().release()' % var
545 elif (underlying_type
.property_type
== PropertyType
.ANY
or
546 underlying_type
.property_type
== PropertyType
.FUNCTION
):
548 vardot
= '(%s)->' % var
550 vardot
= '(%s).' % var
551 return '%sDeepCopy()' % vardot
552 elif underlying_type
.property_type
== PropertyType
.ENUM
:
554 if type_
.property_type
== PropertyType
.REF
:
555 maybe_namespace
= '%s::' % underlying_type
.namespace
.unix_name
556 return 'new base::StringValue(%sToString(%s))' % (maybe_namespace
, var
)
557 elif underlying_type
.property_type
== PropertyType
.BINARY
:
564 return ('base::BinaryValue::CreateWithCopiedBuffer(vector_as_array(%s),'
565 ' %ssize())' % (ref
, vardot
))
566 elif underlying_type
.property_type
== PropertyType
.ARRAY
:
567 return '%s.release()' % self
._util
_cc
_helper
.CreateValueFromArray(
570 elif underlying_type
.property_type
.is_fundamental
:
573 if underlying_type
.property_type
== PropertyType
.STRING
:
574 return 'new base::StringValue(%s)' % var
576 return 'new base::FundamentalValue(%s)' % var
578 raise NotImplementedError('Conversion of %s to base::Value not '
579 'implemented' % repr(type_
.type_
))
581 def _GenerateParamsCheck(self
, function
, var
):
582 """Generates a check for the correct number of arguments when creating
587 for param
in function
.params
:
588 if not param
.optional
:
590 if num_required
== len(function
.params
):
591 c
.Sblock('if (%(var)s.GetSize() != %(total)d) {')
592 elif not num_required
:
593 c
.Sblock('if (%(var)s.GetSize() > %(total)d) {')
595 c
.Sblock('if (%(var)s.GetSize() < %(required)d'
596 ' || %(var)s.GetSize() > %(total)d) {')
597 (c
.Concat(self
._GenerateError
(
598 '"expected %%(total)d arguments, got " '
599 '+ base::IntToString(%%(var)s.GetSize())'))
600 .Append('return scoped_ptr<Params>();')
604 'required': num_required
,
605 'total': len(function
.params
),
609 def _GenerateFunctionParamsCreate(self
, function
):
610 """Generate function to create an instance of Params. The generated
611 function takes a base::ListValue of arguments.
613 E.g for function "Bar", generate Bar::Params::Create()
616 (c
.Append('// static')
617 .Sblock('scoped_ptr<Params> Params::Create(%s) {' % self
._GenerateParams
(
618 ['const base::ListValue& args']))
620 if self
._generate
_error
_messages
:
621 c
.Append('DCHECK(error);')
622 (c
.Concat(self
._GenerateParamsCheck
(function
, 'args'))
623 .Append('scoped_ptr<Params> params(new Params());')
626 for param
in function
.params
:
627 c
.Concat(self
._InitializePropertyToDefault
(param
, 'params'))
629 for i
, param
in enumerate(function
.params
):
630 # Any failure will cause this function to return. If any argument is
631 # incorrect or missing, those following it are not processed. Note that
632 # for optional arguments, we allow missing arguments and proceed because
633 # there may be other arguments following it.
634 failure_value
= 'scoped_ptr<Params>()'
636 value_var
= param
.unix_name
+ '_value'
637 (c
.Append('const base::Value* %(value_var)s = NULL;')
638 .Append('if (args.Get(%(i)s, &%(value_var)s) &&')
639 .Sblock(' !%(value_var)s->IsType(base::Value::TYPE_NULL)) {')
640 .Concat(self
._GeneratePopulatePropertyFromValue
(
641 param
, value_var
, 'params', failure_value
))
644 if not param
.optional
:
646 .Concat(self
._GenerateError
('"\'%%(key)s\' is required"'))
647 .Append('return %s;' % failure_value
)
649 c
.Substitute({'value_var': value_var
, 'i': i
, 'key': param
.name
})
651 .Append('return params.Pass();')
658 def _GeneratePopulatePropertyFromValue(self
,
663 """Generates code to populate property |prop| of |dst_class_var| (a
664 pointer) from a Value*. See |_GeneratePopulateVariableFromValue| for
667 return self
._GeneratePopulateVariableFromValue
(prop
.type_
,
669 '%s->%s' % (dst_class_var
,
672 is_ptr
=prop
.optional
)
674 def _GeneratePopulateVariableFromValue(self
,
680 """Generates code to populate a variable |dst_var| of type |type_| from a
681 Value* at |src_var|. The Value* is assumed to be non-NULL. In the generated
682 code, if |dst_var| fails to be populated then Populate will return
687 underlying_type
= self
._type
_helper
.FollowRef(type_
)
689 if underlying_type
.property_type
.is_fundamental
:
691 (c
.Append('%(cpp_type)s temp;')
692 .Sblock('if (!%s) {' % cpp_util
.GetAsFundamentalValue(
693 self
._type
_helper
.FollowRef(type_
), src_var
, '&temp'))
694 .Concat(self
._GenerateError
(
695 '"\'%%(key)s\': expected ' + '%s, got " + %s' % (
697 self
._util
_cc
_helper
.GetValueTypeString(
698 '%%(src_var)s', True)))))
699 c
.Append('%(dst_var)s.reset();')
700 if not self
._generate
_error
_messages
:
701 c
.Append('return %(failure_value)s;')
704 .Append(' %(dst_var)s.reset(new %(cpp_type)s(temp));')
707 (c
.Sblock('if (!%s) {' % cpp_util
.GetAsFundamentalValue(
708 self
._type
_helper
.FollowRef(type_
),
711 .Concat(self
._GenerateError
(
712 '"\'%%(key)s\': expected ' + '%s, got " + %s' % (
714 self
._util
_cc
_helper
.GetValueTypeString(
715 '%%(src_var)s', True))))
716 .Append('return %(failure_value)s;')
719 elif underlying_type
.property_type
== PropertyType
.OBJECT
:
721 (c
.Append('const base::DictionaryValue* dictionary = NULL;')
722 .Sblock('if (!%(src_var)s->GetAsDictionary(&dictionary)) {')
723 .Concat(self
._GenerateError
(
724 '"\'%%(key)s\': expected dictionary, got " + ' +
725 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True))))
726 # If an optional property fails to populate, the population can still
727 # succeed with a warning. If no error messages are generated, this
728 # warning is not set and we fail out instead.
729 if not self
._generate
_error
_messages
:
730 c
.Append('return %(failure_value)s;')
733 .Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());')
734 .Append('if (!%%(cpp_type)s::Populate(%s)) {' % self
._GenerateArgs
(
735 ('*dictionary', 'temp.get()')))
736 .Append(' return %(failure_value)s;')
740 .Append(' %(dst_var)s = temp.Pass();')
744 (c
.Append('const base::DictionaryValue* dictionary = NULL;')
745 .Sblock('if (!%(src_var)s->GetAsDictionary(&dictionary)) {')
746 .Concat(self
._GenerateError
(
747 '"\'%%(key)s\': expected dictionary, got " + ' +
748 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
749 .Append('return %(failure_value)s;')
751 .Append('if (!%%(cpp_type)s::Populate(%s)) {' % self
._GenerateArgs
(
752 ('*dictionary', '&%(dst_var)s')))
753 .Append(' return %(failure_value)s;')
756 elif underlying_type
.property_type
== PropertyType
.FUNCTION
:
758 c
.Append('%(dst_var)s.reset(new base::DictionaryValue());')
759 elif underlying_type
.property_type
== PropertyType
.ANY
:
760 c
.Append('%(dst_var)s.reset(%(src_var)s->DeepCopy());')
761 elif underlying_type
.property_type
== PropertyType
.ARRAY
:
762 # util_cc_helper deals with optional and required arrays
763 (c
.Append('const base::ListValue* list = NULL;')
764 .Sblock('if (!%(src_var)s->GetAsList(&list)) {')
765 .Concat(self
._GenerateError
(
766 '"\'%%(key)s\': expected list, got " + ' +
767 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
769 if is_ptr
and self
._generate
_error
_messages
:
770 c
.Append('%(dst_var)s.reset();')
772 c
.Append('return %(failure_value)s;')
775 item_type
= self
._type
_helper
.FollowRef(underlying_type
.item_type
)
776 if item_type
.property_type
== PropertyType
.ENUM
:
777 c
.Concat(self
._GenerateListValueToEnumArrayConversion
(
784 c
.Sblock('if (!%s(%s)) {' % (
785 self
._util
_cc
_helper
.PopulateArrayFromListFunction(is_ptr
),
786 self
._GenerateArgs
(('*list', '&%(dst_var)s'))))
787 c
.Concat(self
._GenerateError
(
788 '"unable to populate array \'%%(parent_key)s\'"'))
789 if is_ptr
and self
._generate
_error
_messages
:
790 c
.Append('%(dst_var)s.reset();')
792 c
.Append('return %(failure_value)s;')
795 elif underlying_type
.property_type
== PropertyType
.CHOICES
:
797 (c
.Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());')
798 .Append('if (!%%(cpp_type)s::Populate(%s))' % self
._GenerateArgs
(
799 ('*%(src_var)s', 'temp.get()')))
800 .Append(' return %(failure_value)s;')
801 .Append('%(dst_var)s = temp.Pass();')
804 (c
.Append('if (!%%(cpp_type)s::Populate(%s))' % self
._GenerateArgs
(
805 ('*%(src_var)s', '&%(dst_var)s')))
806 .Append(' return %(failure_value)s;'))
807 elif underlying_type
.property_type
== PropertyType
.ENUM
:
808 c
.Concat(self
._GenerateStringToEnumConversion
(underlying_type
,
812 elif underlying_type
.property_type
== PropertyType
.BINARY
:
813 (c
.Append('const base::BinaryValue* binary_value = NULL;')
814 .Sblock('if (!%(src_var)s->IsType(base::Value::TYPE_BINARY)) {')
815 .Concat(self
._GenerateError
(
816 '"\'%%(key)s\': expected binary, got " + ' +
817 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
819 if not self
._generate
_error
_messages
:
820 c
.Append('return %(failure_value)s;')
823 .Append(' binary_value =')
824 .Append(' static_cast<const base::BinaryValue*>(%(src_var)s);')
827 (c
.Append('%(dst_var)s.reset(new std::vector<char>(')
828 .Append(' binary_value->GetBuffer(),')
829 .Append(' binary_value->GetBuffer() + binary_value->GetSize()));')
832 (c
.Append('%(dst_var)s.assign(')
833 .Append(' binary_value->GetBuffer(),')
834 .Append(' binary_value->GetBuffer() + binary_value->GetSize());')
838 raise NotImplementedError(type_
)
841 return Code().Sblock('{').Concat(c
.Substitute({
842 'cpp_type': self
._type
_helper
.GetCppType(type_
),
845 'failure_value': failure_value
,
847 'parent_key': type_
.parent
.name
,
850 def _GenerateListValueToEnumArrayConversion(self
,
856 """Returns Code that converts a ListValue of string constants from
857 |src_var| into an array of enums of |type_| in |dst_var|. On failure,
858 returns |failure_value|.
864 cpp_type
= self
._type
_helper
.GetCppType(item_type
, is_in_container
=True)
865 c
.Append('%s.reset(new std::vector<%s>);' %
866 (dst_var
, cpp_util
.PadForGenerics(cpp_type
)))
867 (c
.Sblock('for (const auto& it : *(%s)) {' % src_var
)
868 .Append('%s tmp;' % self
._type
_helper
.GetCppType(item_type
))
869 .Concat(self
._GenerateStringToEnumConversion
(item_type
,
873 .Append('%s%spush_back(tmp);' % (dst_var
, accessor
))
878 def _GenerateStringToEnumConversion(self
,
883 """Returns Code that converts a string type in |src_var| to an enum with
884 type |type_| in |dst_var|. In the generated code, if |src_var| is not
885 a valid enum name then the function will return |failure_value|.
887 if type_
.property_type
!= PropertyType
.ENUM
:
888 raise TypeError(type_
)
890 enum_as_string
= '%s_as_string' % type_
.unix_name
891 cpp_type_namespace
= ''
892 if type_
.namespace
!= self
._namespace
:
893 cpp_type_namespace
= '%s::' % type_
.namespace
.unix_name
894 (c
.Append('std::string %s;' % enum_as_string
)
895 .Sblock('if (!%s->GetAsString(&%s)) {' % (src_var
, enum_as_string
))
896 .Concat(self
._GenerateError
(
897 '"\'%%(key)s\': expected string, got " + ' +
898 self
._util
_cc
_helper
.GetValueTypeString('%%(src_var)s', True)))
899 .Append('return %s;' % failure_value
)
901 .Append('%s = %sParse%s(%s);' % (dst_var
,
903 cpp_util
.Classname(type_
.name
),
905 .Sblock('if (%s == %s%s) {' % (dst_var
,
907 self
._type
_helper
.GetEnumNoneValue(type_
)))
908 .Concat(self
._GenerateError
(
909 '\"\'%%(key)s\': expected \\"' +
912 for enum_value
in self
._type
_helper
.FollowRef(type_
).enum_values
) +
913 '\\", got \\"" + %s + "\\""' % enum_as_string
))
914 .Append('return %s;' % failure_value
)
916 .Substitute({'src_var': src_var
, 'key': type_
.name
})
920 def _GeneratePropertyFunctions(self
, namespace
, params
):
921 """Generates the member functions for a list of parameters.
923 return self
._GenerateTypes
(namespace
, (param
.type_
for param
in params
))
925 def _GenerateTypes(self
, namespace
, types
):
926 """Generates the member functions for a list of types.
930 c
.Cblock(self
._GenerateType
(namespace
, type_
))
933 def _GenerateEnumToString(self
, cpp_namespace
, type_
):
934 """Generates ToString() which gets the string representation of an enum.
937 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
939 if cpp_namespace
is not None:
940 c
.Append('// static')
941 maybe_namespace
= '' if cpp_namespace
is None else '%s::' % cpp_namespace
943 c
.Sblock('std::string %sToString(%s enum_param) {' %
944 (maybe_namespace
, classname
))
945 c
.Sblock('switch (enum_param) {')
946 for enum_value
in self
._type
_helper
.FollowRef(type_
).enum_values
:
947 name
= enum_value
.name
948 if 'camel_case_enum_to_string' in self
._namespace
.compiler_options
:
949 name
= enum_value
.CamelName()
950 (c
.Append('case %s: ' % self
._type
_helper
.GetEnumValue(type_
, enum_value
))
951 .Append(' return "%s";' % name
))
952 (c
.Append('case %s:' % self
._type
_helper
.GetEnumNoneValue(type_
))
953 .Append(' return "";')
955 .Append('NOTREACHED();')
956 .Append('return "";')
961 def _GenerateEnumFromString(self
, cpp_namespace
, type_
):
962 """Generates FromClassNameString() which gets an enum from its string
966 classname
= cpp_util
.Classname(schema_util
.StripNamespace(type_
.name
))
968 if cpp_namespace
is not None:
969 c
.Append('// static')
970 maybe_namespace
= '' if cpp_namespace
is None else '%s::' % cpp_namespace
972 c
.Sblock('%s%s %sParse%s(const std::string& enum_string) {' %
973 (maybe_namespace
, classname
, maybe_namespace
, classname
))
974 for _
, enum_value
in enumerate(
975 self
._type
_helper
.FollowRef(type_
).enum_values
):
976 # This is broken up into all ifs with no else ifs because we get
977 # "fatal error C1061: compiler limit : blocks nested too deeply"
979 name
= enum_value
.name
980 if 'camel_case_enum_to_string' in self
._namespace
.compiler_options
:
981 name
= enum_value
.CamelName()
982 (c
.Append('if (enum_string == "%s")' % name
)
983 .Append(' return %s;' %
984 self
._type
_helper
.GetEnumValue(type_
, enum_value
)))
985 (c
.Append('return %s;' % self
._type
_helper
.GetEnumNoneValue(type_
))
990 def _GenerateCreateCallbackArguments(self
,
993 """Generate all functions to create Value parameters for a callback.
995 E.g for function "Bar", generate Bar::Results::Create
996 E.g for event "Baz", generate Baz::Create
998 function_scope: the function scope path, e.g. Foo::Bar for the function
999 Foo::Bar::Baz(). May be None if there is no function scope.
1000 callback: the Function object we are creating callback arguments for.
1003 params
= callback
.params
1004 c
.Concat(self
._GeneratePropertyFunctions
(function_scope
, params
))
1006 (c
.Sblock('scoped_ptr<base::ListValue> %(function_scope)s'
1007 'Create(%(declaration_list)s) {')
1008 .Append('scoped_ptr<base::ListValue> create_results('
1009 'new base::ListValue());')
1011 declaration_list
= []
1012 for param
in params
:
1013 declaration_list
.append(cpp_util
.GetParameterDeclaration(
1014 param
, self
._type
_helper
.GetCppType(param
.type_
)))
1015 c
.Cblock(self
._CreateValueFromType
('create_results->Append(%s);',
1019 c
.Append('return create_results.Pass();')
1022 'function_scope': ('%s::' % function_scope
) if function_scope
else '',
1023 'declaration_list': ', '.join(declaration_list
),
1024 'param_names': ', '.join(param
.unix_name
for param
in params
)
1028 def _GenerateEventNameConstant(self
, event
):
1029 """Generates a constant string array for the event name.
1032 c
.Append('const char kEventName[] = "%s.%s";' % (
1033 self
._namespace
.name
, event
.name
))
1036 def _InitializePropertyToDefault(self
, prop
, dst
):
1037 """Initialize a model.Property to its default value inside an object.
1039 E.g for optional enum "state", generate dst->state = STATE_NONE;
1044 underlying_type
= self
._type
_helper
.FollowRef(prop
.type_
)
1045 if (underlying_type
.property_type
== PropertyType
.ENUM
and
1047 namespace_prefix
= ('%s::' % underlying_type
.namespace
.unix_name
1048 if underlying_type
.namespace
!= self
._namespace
1050 c
.Append('%s->%s = %s%s;' % (
1054 self
._type
_helper
.GetEnumNoneValue(prop
.type_
)))
1057 def _GenerateError(self
, body
):
1058 """Generates an error message pertaining to population failure.
1060 E.g 'expected bool, got int'
1063 if not self
._generate
_error
_messages
:
1065 (c
.Append('if (error->length())')
1066 .Append(' error->append(UTF8ToUTF16("; "));')
1067 .Append('error->append(UTF8ToUTF16(%s));' % body
))
1070 def _GenerateParams(self
, params
):
1071 """Builds the parameter list for a function, given an array of parameters.
1073 if self
._generate
_error
_messages
:
1074 params
= list(params
) + ['base::string16* error']
1075 return ', '.join(str(p
) for p
in params
)
1077 def _GenerateArgs(self
, args
):
1078 """Builds the argument list for a function, given an array of arguments.
1080 if self
._generate
_error
_messages
:
1081 args
= list(args
) + ['error']
1082 return ', '.join(str(a
) for a
in args
)