cc_generator.py revision 5821806d5e7f356e8fa4b058a389a808ea183019
1# Copyright (c) 2012 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5from code import Code
6from model import PropertyType
7import any_helper
8import cpp_util
9import model
10import schema_util
11import sys
12import util_cc_helper
13
14class CCGenerator(object):
15  """A .cc generator for a namespace.
16  """
17  def __init__(self, namespace, cpp_type_generator):
18    self._cpp_type_generator = cpp_type_generator
19    self._namespace = namespace
20    self._target_namespace = (
21        self._cpp_type_generator.GetCppNamespaceName(self._namespace))
22    self._util_cc_helper = (
23        util_cc_helper.UtilCCHelper(self._cpp_type_generator))
24    self._any_helper = any_helper.AnyHelper()
25
26  def Generate(self):
27    """Generates a Code object with the .cc for a single namespace.
28    """
29    c = Code()
30    (c.Append(cpp_util.CHROMIUM_LICENSE)
31      .Append()
32      .Append(cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file)
33      .Append()
34      .Append(self._util_cc_helper.GetIncludePath())
35      .Append('#include "%s/%s.h"' %
36          (self._namespace.source_file_dir, self._namespace.unix_name))
37    )
38    includes = self._cpp_type_generator.GenerateIncludes()
39    if not includes.IsEmpty():
40      (c.Concat(includes)
41        .Append()
42      )
43
44    (c.Append()
45      .Concat(self._cpp_type_generator.GetRootNamespaceStart())
46      .Concat(self._cpp_type_generator.GetNamespaceStart())
47      .Append()
48    )
49    if self._namespace.properties:
50      (c.Append('//')
51        .Append('// Properties')
52        .Append('//')
53        .Append()
54      )
55      for property in self._namespace.properties.values():
56        property_code = self._cpp_type_generator.GeneratePropertyValues(
57            property,
58            'const %(type)s %(name)s = %(value)s;',
59            nodoc=True)
60        if property_code:
61          c.Concat(property_code).Append()
62    if self._namespace.types:
63      (c.Append('//')
64        .Append('// Types')
65        .Append('//')
66        .Append()
67      )
68    for type_ in self._namespace.types.values():
69      (c.Concat(self._GenerateType(
70        schema_util.StripSchemaNamespace(type_.name), type_)).Append()
71      )
72    if self._namespace.functions:
73      (c.Append('//')
74        .Append('// Functions')
75        .Append('//')
76        .Append()
77      )
78    for function in self._namespace.functions.values():
79      (c.Concat(self._GenerateFunction(
80          cpp_util.Classname(function.name), function))
81        .Append()
82      )
83    if self._namespace.events:
84      (c.Append('//')
85        .Append('// Events')
86        .Append('//')
87        .Append()
88      )
89    for event in self._namespace.events.values():
90      (c.Concat(self._GenerateCreateCallbackArguments(
91          cpp_util.Classname(event.name), event, generate_to_json=True))
92        .Append()
93      )
94    (c.Concat(self._cpp_type_generator.GetNamespaceEnd())
95      .Concat(self._cpp_type_generator.GetRootNamespaceEnd())
96      .Append()
97    )
98    return c
99
100  def _GenerateType(self, cpp_namespace, type_):
101    """Generates the function definitions for a type.
102    """
103    classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name))
104    c = Code()
105
106    if type_.functions:
107      for function in type_.functions.values():
108        (c.Concat(
109            self._GenerateFunction(
110                cpp_namespace + '::' + cpp_util.Classname(function.name),
111                function))
112          .Append())
113    elif type_.type_ == PropertyType.OBJECT:
114      (c.Concat(self._GeneratePropertyFunctions(
115          cpp_namespace, type_.properties.values()))
116        .Sblock('%(namespace)s::%(classname)s()')
117        .Concat(self._GenerateInitializersAndBody(type_))
118        .Eblock('%(namespace)s::~%(classname)s() {}')
119        .Append())
120      if type_.from_json:
121        (c.Concat(self._GenerateTypePopulate(cpp_namespace, type_))
122          .Append())
123      if type_.from_client:
124        (c.Concat(self._GenerateTypeToValue(cpp_namespace, type_))
125          .Append())
126    elif self._cpp_type_generator.IsEnumOrEnumRef(type_):
127      (c.Concat(self._GenerateCreateEnumTypeValue(cpp_namespace, type_))
128        .Append()
129        .Concat(self._GenerateEnumFromString(cpp_namespace, type_))
130        .Append()
131        .Concat(self._GenerateEnumToString(cpp_namespace, type_))
132        .Append())
133    c.Substitute({'classname': classname, 'namespace': cpp_namespace})
134
135    return c
136
137  def _GenerateInitializersAndBody(self, type_):
138    items = []
139    for prop in type_.properties.values():
140      if prop.optional:
141        continue
142
143      t = prop.type_
144      if t == PropertyType.INTEGER:
145        items.append('%s(0)' % prop.unix_name)
146      elif t == PropertyType.DOUBLE:
147        items.append('%s(0.0)' % prop.unix_name)
148      elif t == PropertyType.BOOLEAN:
149        items.append('%s(false)' % prop.unix_name)
150      elif t == PropertyType.BINARY:
151        items.append('%s(NULL)' % prop.unix_name)
152      elif (t == PropertyType.ADDITIONAL_PROPERTIES or
153            t == PropertyType.ANY or
154            t == PropertyType.ARRAY or
155            t == PropertyType.CHOICES or
156            t == PropertyType.ENUM or
157            t == PropertyType.OBJECT or
158            t == PropertyType.FUNCTION or
159            t == PropertyType.REF or
160            t == PropertyType.STRING):
161        # TODO(miket): It would be nice to initialize CHOICES and ENUM, but we
162        # don't presently have the semantics to indicate which one of a set
163        # should be the default.
164        continue
165      else:
166        sys.exit("Unhandled PropertyType: %s" % t)
167
168    if items:
169      s = ': %s' % (', '.join(items))
170    else:
171      s = ''
172    s = s + ' {}'
173    return Code().Append(s)
174
175  def _GenerateTypePopulate(self, cpp_namespace, type_):
176    """Generates the function for populating a type given a pointer to it.
177
178    E.g for type "Foo", generates Foo::Populate()
179    """
180    classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name))
181    c = Code()
182    (c.Append('// static')
183      .Sblock('bool %(namespace)s::Populate'
184              '(const base::Value& value, %(name)s* out) {')
185        .Append('if (!value.IsType(base::Value::TYPE_DICTIONARY))')
186        .Append('  return false;')
187    )
188    if type_.properties:
189      (c.Append('const base::DictionaryValue* dict = '
190                'static_cast<const base::DictionaryValue*>(&value);')
191        .Append()
192      )
193      for prop in type_.properties.values():
194        c.Concat(self._InitializePropertyToDefault(prop, 'out'))
195      for prop in type_.properties.values():
196        if prop.type_ == PropertyType.ADDITIONAL_PROPERTIES:
197          c.Append('out->additional_properties.MergeDictionary(dict);')
198          # remove all keys that are actual properties
199          for cur_prop in type_.properties.values():
200            if prop != cur_prop:
201              c.Append('out->additional_properties'
202                  '.RemoveWithoutPathExpansion("%s", NULL);' % cur_prop.name)
203          c.Append()
204        else:
205          c.Concat(self._GenerateTypePopulateProperty(prop, 'dict', 'out'))
206    (c.Append('return true;')
207      .Eblock('}')
208    )
209    c.Substitute({'namespace': cpp_namespace, 'name': classname})
210    return c
211
212  def _GenerateTypePopulateProperty(self, prop, src, dst):
213    """Generate the code to populate a single property in a type.
214
215    src: base::DictionaryValue*
216    dst: Type*
217    """
218    c = Code()
219    value_var = prop.unix_name + '_value'
220    c.Append('const base::Value* %(value_var)s = NULL;')
221    if prop.optional:
222      (c.Sblock(
223          'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {')
224        .Concat(self._GeneratePopulatePropertyFromValue(
225            prop, value_var, dst, 'false')))
226      if self._cpp_type_generator.IsEnumOrEnumRef(prop):
227        (c.Append('} else {')
228          .Append('%%(dst)s->%%(name)s = %s;' %
229              self._cpp_type_generator.GetEnumNoneValue(prop)))
230      c.Eblock('}')
231    else:
232      (c.Append(
233          'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))')
234        .Append('  return false;')
235        .Concat(self._GeneratePopulatePropertyFromValue(
236            prop, value_var, dst, 'false'))
237      )
238    c.Append()
239    c.Substitute({
240      'value_var': value_var,
241      'key': prop.name,
242      'src': src,
243      'dst': dst,
244      'name': prop.unix_name
245    })
246    return c
247
248  def _GenerateTypeToValue(self, cpp_namespace, type_):
249    """Generates a function that serializes the type into a
250    |base::DictionaryValue|.
251
252    E.g. for type "Foo" generates Foo::ToValue()
253    """
254    c = Code()
255    (c.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' %
256          cpp_namespace)
257        .Append('scoped_ptr<base::DictionaryValue> value('
258                'new base::DictionaryValue());')
259        .Append()
260    )
261    for prop in type_.properties.values():
262      if prop.type_ == PropertyType.ADDITIONAL_PROPERTIES:
263        c.Append('value->MergeDictionary(&%s);' % prop.unix_name)
264      else:
265        if prop.optional:
266          if self._cpp_type_generator.IsEnumOrEnumRef(prop):
267            c.Sblock('if (%s != %s) {' %
268                (prop.unix_name,
269                 self._cpp_type_generator.GetEnumNoneValue(prop)))
270          elif prop.type_ == PropertyType.CHOICES:
271            c.Sblock('if (%s_type != %s) {' %
272                (prop.unix_name,
273                 self._cpp_type_generator.GetEnumNoneValue(prop)))
274          else:
275            c.Sblock('if (%s.get()) {' % prop.unix_name)
276
277        if prop.type_ == prop.compiled_type:
278          c.Append('value->SetWithoutPathExpansion("%s", %s);' % (
279              prop.name,
280              self._CreateValueFromProperty(prop, 'this->' + prop.unix_name)))
281        else:
282          conversion_src = 'this->' + prop.unix_name
283          if prop.optional:
284            conversion_src = '*' + conversion_src
285          (c.Append('%s %s;' % (self._cpp_type_generator.GetType(prop),
286                                prop.unix_name))
287            .Append(cpp_util.GenerateCompiledTypeToTypeConversion(
288                self._cpp_type_generator.GetReferencedProperty(prop),
289                conversion_src,
290                prop.unix_name) + ';')
291            .Append('value->SetWithoutPathExpansion("%s", %s);' % (
292                prop.unix_name,
293                self._CreateValueFromProperty(prop, prop.unix_name)))
294          )
295        if prop.optional:
296          c.Eblock('}');
297    (c.Append()
298      .Append('return value.Pass();')
299      .Eblock('}')
300    )
301    return c
302
303  def _GenerateFunction(self, cpp_namespace, function):
304    """Generates the definitions for function structs.
305    """
306    c = Code()
307
308    # Params::Populate function
309    if function.params:
310      c.Concat(self._GeneratePropertyFunctions(cpp_namespace + '::Params',
311          function.params))
312      (c.Append('%(cpp_namespace)s::Params::Params() {}')
313        .Append('%(cpp_namespace)s::Params::~Params() {}')
314        .Append()
315        .Concat(self._GenerateFunctionParamsCreate(cpp_namespace, function))
316        .Append()
317      )
318
319    # Results::Create function
320    if function.callback:
321      c.Concat(self._GenerateCreateCallbackArguments(
322          "%s::Results" % cpp_namespace, function.callback))
323
324    c.Substitute({'cpp_namespace': cpp_namespace})
325
326    return c
327
328  def _CreateValueFromProperty(self, prop, var):
329    """Creates a base::Value given a property. Generated code passes ownership
330    to caller.
331
332    var: variable or variable*
333
334    E.g for std::string, generate base::Value::CreateStringValue(var)
335    """
336    if prop.type_ == PropertyType.CHOICES:
337      return 'Get%sChoiceValue().release()' % cpp_util.Classname(prop.name)
338    elif self._IsObjectOrObjectRef(prop):
339      if prop.optional:
340        return '%s->ToValue().release()' % var
341      else:
342        return '%s.ToValue().release()' % var
343    elif prop.type_ == PropertyType.ANY:
344      return '%s.DeepCopy()' % self._any_helper.GetValue(prop, var)
345    elif prop.type_ == PropertyType.ADDITIONAL_PROPERTIES:
346      return '%s.DeepCopy()' % var
347    elif prop.type_ == PropertyType.FUNCTION:
348      if prop.optional:
349        vardot = var + '->'
350      else:
351        vardot = var + '.'
352      return '%sDeepCopy()' % vardot
353    elif self._cpp_type_generator.IsEnumOrEnumRef(prop):
354      return 'base::Value::CreateStringValue(ToString(%s))' % var
355    elif prop.type_ == PropertyType.BINARY:
356      if prop.optional:
357        vardot = var + '->'
358      else:
359        vardot = var + '.'
360      return ('base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())' %
361              (vardot, vardot))
362    elif self._IsArrayOrArrayRef(prop):
363      return '%s.release()' % self._util_cc_helper.CreateValueFromArray(
364          self._cpp_type_generator.GetReferencedProperty(prop), var,
365          prop.optional)
366    elif self._IsFundamentalOrFundamentalRef(prop):
367      # If prop.type != prop.compiled_type, then no asterisk is necessary
368      # because the target is a local variable and not a dereferenced scoped
369      # pointer. The asterisk is instead prepended to conversion_src around line
370      # 273.
371      if prop.optional and prop.type_ == prop.compiled_type:
372        var = '*' + var
373      prop = self._cpp_type_generator.GetReferencedProperty(prop);
374      return {
375          PropertyType.STRING: 'base::Value::CreateStringValue(%s)',
376          PropertyType.BOOLEAN: 'base::Value::CreateBooleanValue(%s)',
377          PropertyType.INTEGER: 'base::Value::CreateIntegerValue(%s)',
378          PropertyType.DOUBLE: 'base::Value::CreateDoubleValue(%s)',
379      }[prop.type_] % var
380    else:
381      raise NotImplementedError('Conversion of %s to base::Value not '
382          'implemented' % repr(prop.type_))
383
384  def _GenerateParamsCheck(self, function, var):
385    """Generates a check for the correct number of arguments when creating
386    Params.
387    """
388    c = Code()
389    num_required = 0
390    for param in function.params:
391      if not param.optional:
392        num_required += 1
393    if num_required == len(function.params):
394      c.Append('if (%(var)s.GetSize() != %(total)d)')
395    elif not num_required:
396      c.Append('if (%(var)s.GetSize() > %(total)d)')
397    else:
398      c.Append('if (%(var)s.GetSize() < %(required)d'
399          ' || %(var)s.GetSize() > %(total)d)')
400    c.Append('  return scoped_ptr<Params>();')
401    c.Substitute({
402        'var': var,
403        'required': num_required,
404        'total': len(function.params),
405    })
406    return c
407
408  def _GenerateFunctionParamsCreate(self, cpp_namespace, function):
409    """Generate function to create an instance of Params. The generated
410    function takes a base::ListValue of arguments.
411
412    E.g for function "Bar", generate Bar::Params::Create()
413    """
414    c = Code()
415    (c.Append('// static')
416      .Sblock('scoped_ptr<%(cpp_namespace)s::Params> '
417        '%(cpp_namespace)s::Params::Create(const base::ListValue& args) {')
418      .Concat(self._GenerateParamsCheck(function, 'args'))
419      .Append('scoped_ptr<Params> params(new Params());')
420    )
421    c.Substitute({'cpp_namespace': cpp_namespace})
422
423    for param in function.params:
424      c.Concat(self._InitializePropertyToDefault(param, 'params'))
425
426    for i, param in enumerate(function.params):
427      # Any failure will cause this function to return. If any argument is
428      # incorrect or missing, those following it are not processed. Note that
429      # for optional arguments, we allow missing arguments and proceed because
430      # there may be other arguments following it.
431      failure_value = 'scoped_ptr<Params>()'
432      c.Append()
433      value_var = param.unix_name + '_value'
434      (c.Append('const base::Value* %(value_var)s = NULL;')
435        .Append('if (args.Get(%(i)s, &%(value_var)s) &&\n'
436                '    !%(value_var)s->IsType(base::Value::TYPE_NULL))')
437        .Sblock('{')
438        .Concat(self._GeneratePopulatePropertyFromValue(
439            param, value_var, 'params', failure_value))
440        .Eblock('}')
441      )
442      if not param.optional:
443        (c.Sblock('else {')
444          .Append('return %s;' % failure_value)
445          .Eblock('}')
446        )
447      c.Substitute({'value_var': value_var, 'i': i})
448    (c.Append()
449      .Append('return params.Pass();')
450      .Eblock('}')
451      .Append()
452    )
453
454    return c
455
456  def _GeneratePopulatePropertyFromValue(
457      self, prop, value_var, dst, failure_value, check_type=True):
458    """Generates code to populate a model.Property given a base::Value*. The
459    existence of data inside the base::Value* is assumed so checks for existence
460    should be performed before the code this generates.
461
462    prop: the property the code is populating.
463    value_var: a base::Value* that should represent |prop|.
464    dst: the object with |prop| as a member.
465    failure_value: the value to return if |prop| cannot be extracted from
466    |value_var|
467    check_type: if true, will check if |value_var| is the correct
468    base::Value::Type
469    """
470    c = Code()
471    c.Sblock('{')
472
473    if self._IsFundamentalOrFundamentalRef(prop):
474      self._GenerateFundamentalOrFundamentalRefPopulate(c, prop, value_var, dst)
475    elif self._IsObjectOrObjectRef(prop):
476      self._GenerateObjectOrObjectRefPopulate(c, prop)
477    elif prop.type_ == PropertyType.FUNCTION:
478      self._GenerateFunctionPopulate(c, prop)
479    elif prop.type_ == PropertyType.ANY:
480      self._GenerateAnyPopulate(c, prop, value_var, dst)
481    elif self._IsArrayOrArrayRef(prop):
482      self._GenerateArrayOrArrayRefPopulate(c, prop, dst)
483    elif prop.type_ == PropertyType.CHOICES:
484      self._GenerateChoicePopulate(c, prop, value_var, dst, failure_value)
485    elif self._cpp_type_generator.IsEnumOrEnumRef(prop):
486      self._GenerateEnumPopulate(c, prop, value_var)
487    elif prop.type_ == PropertyType.BINARY:
488      self._GenerateBinaryPopulate(c, prop)
489    else:
490      raise NotImplementedError(prop.type_)
491    c.Eblock('}')
492    sub = {
493        'value_var': value_var,
494        'name': prop.unix_name,
495        'dst': dst,
496        'failure_value': failure_value,
497    }
498    if prop.type_ not in (PropertyType.CHOICES, PropertyType.ANY):
499      sub['ctype'] = self._cpp_type_generator.GetType(prop)
500      sub['compiled_ctype'] = self._cpp_type_generator.GetCompiledType(prop)
501      sub['value_type'] = cpp_util.GetValueType(self._cpp_type_generator
502          .GetReferencedProperty(prop).type_)
503    c.Substitute(sub)
504    return c
505
506  def _GenerateFundamentalOrFundamentalRefPopulate(self,
507                                                   c,
508                                                   prop,
509                                                   value_var,
510                                                   dst):
511    if prop.optional:
512      (c.Append('%(ctype)s temp;')
513        .Append('if (!%s)' %
514            cpp_util.GetAsFundamentalValue(
515                self._cpp_type_generator.GetReferencedProperty(prop),
516                value_var,
517                '&temp'))
518        .Append('  return %(failure_value)s;')
519      )
520      if prop.type_ != prop.compiled_type:
521        (c.Append('%(compiled_ctype)s temp2;')
522          .Append('if (!%s)' %
523               cpp_util.GenerateTypeToCompiledTypeConversion(
524                   self._cpp_type_generator.GetReferencedProperty(prop),
525                   'temp',
526                   'temp2'))
527          .Append('  return %(failure_value)s;')
528          .Append('%(dst)s->%(name)s.reset(new %(compiled_ctype)s(temp2));')
529        )
530      else:
531        c.Append('%(dst)s->%(name)s.reset(new %(ctype)s(temp));')
532
533    else:
534      if prop.type_ == prop.compiled_type:
535        assignment_target = '&%s->%s' % (dst, prop.unix_name)
536      else:
537        c.Append('%(ctype)s temp;')
538        assignment_target = '&temp'
539      (c.Append('if (!%s)' %
540          cpp_util.GetAsFundamentalValue(
541              self._cpp_type_generator.GetReferencedProperty(prop),
542              value_var,
543              assignment_target))
544        .Append('  return %(failure_value)s;')
545      )
546      if prop.type_ != prop.compiled_type:
547        (c.Append('if (!%s)' %
548            cpp_util.GenerateTypeToCompiledTypeConversion(
549                self._cpp_type_generator.GetReferencedProperty(prop),
550                'temp',
551                '%s->%s' % (dst, prop.unix_name)))
552          .Append('  return %(failure_value)s;')
553        )
554
555  def _GenerateObjectOrObjectRefPopulate(self, c, prop):
556    if prop.optional:
557      (c.Append('const base::DictionaryValue* dictionary = NULL;')
558        .Append('if (!%(value_var)s->GetAsDictionary(&dictionary))')
559        .Append('  return %(failure_value)s;')
560        .Append('scoped_ptr<%(ctype)s> temp(new %(ctype)s());')
561        .Append('if (!%(ctype)s::Populate(*dictionary, temp.get()))')
562        .Append('  return %(failure_value)s;')
563        .Append('%(dst)s->%(name)s = temp.Pass();')
564      )
565    else:
566      (c.Append('const base::DictionaryValue* dictionary = NULL;')
567        .Append('if (!%(value_var)s->GetAsDictionary(&dictionary))')
568        .Append('  return %(failure_value)s;')
569        .Append(
570            'if (!%(ctype)s::Populate(*dictionary, &%(dst)s->%(name)s))')
571        .Append('  return %(failure_value)s;')
572      )
573
574  def _GenerateFunctionPopulate(self, c, prop):
575    if prop.optional:
576      c.Append('%(dst)s->%(name)s.reset(new base::DictionaryValue());')
577
578  def _GenerateAnyPopulate(self, c, prop, value_var, dst):
579    if prop.optional:
580      c.Append('%(dst)s->%(name)s.reset(new ' + any_helper.ANY_CLASS + '());')
581    c.Append(self._any_helper.Init(prop, value_var, dst) + ';')
582
583  def _GenerateArrayOrArrayRefPopulate(self, c, prop, dst):
584    # util_cc_helper deals with optional and required arrays
585    (c.Append('const base::ListValue* list = NULL;')
586      .Append('if (!%(value_var)s->GetAsList(&list))')
587      .Append('  return %(failure_value)s;'))
588    if prop.item_type.type_ == PropertyType.ENUM:
589      self._GenerateListValueToEnumArrayConversion(c, prop)
590    else:
591      (c.Append('if (!%s)' % self._util_cc_helper.PopulateArrayFromList(
592            self._cpp_type_generator.GetReferencedProperty(prop), 'list',
593            dst + '->' + prop.unix_name, prop.optional))
594        .Append('  return %(failure_value)s;')
595      )
596
597  def _GenerateChoicePopulate(self, c, prop, value_var, dst, failure_value):
598    type_var = '%(dst)s->%(name)s_type'
599    c.Sblock('switch (%(value_var)s->GetType()) {')
600    for choice in self._cpp_type_generator.ExpandParams([prop]):
601      (c.Sblock('case %s: {' % cpp_util.GetValueType(
602          self._cpp_type_generator.GetReferencedProperty(choice).type_))
603          .Concat(self._GeneratePopulatePropertyFromValue(
604              choice, value_var, dst, failure_value, check_type=False))
605          .Append('%s = %s;' %
606              (type_var,
607               self._cpp_type_generator.GetEnumValue(
608                   prop, choice.type_.name)))
609          .Append('break;')
610        .Eblock('}')
611      )
612    (c.Append('default:')
613      .Append('  return %(failure_value)s;')
614    )
615    c.Eblock('}')
616
617  def _GenerateEnumPopulate(self, c, prop, value_var):
618    c.Sblock('{')
619    self._GenerateStringToEnumConversion(c, prop, value_var, 'enum_temp')
620    c.Append('%(dst)s->%(name)s = enum_temp;')
621    c.Eblock('}')
622
623  def _GenerateBinaryPopulate(self, c, prop):
624    (c.Append('if (!%(value_var)s->IsType(%(value_type)s))')
625      .Append('  return %(failure_value)s;')
626      .Append('const base::BinaryValue* binary_value =')
627      .Append('    static_cast<const base::BinaryValue*>(%(value_var)s);')
628     )
629    if prop.optional:
630      (c.Append('%(dst)s->%(name)s.reset(')
631        .Append('    new std::string(binary_value->GetBuffer(),')
632        .Append('                    binary_value->GetSize()));')
633       )
634    else:
635      (c.Append('%(dst)s->%(name)s.assign(binary_value->GetBuffer(),')
636        .Append('                         binary_value->GetSize());')
637       )
638
639  def _GenerateListValueToEnumArrayConversion(self, c, prop):
640      """Appends code that converts a ListValue of string contstants to
641      an array of enums in dst.
642      Leaves dst, name, and failure_value unsubstituted.
643
644      c: the Code object that is being appended to.
645      prop: the property that the code is populating.
646      """
647      accessor = '.'
648      if prop.optional:
649        c.Append('%(dst)s->%(name)s.reset(new std::vector<' + (
650          self._cpp_type_generator.GetType(prop.item_type) + '>);'))
651        accessor = '->'
652      c.Sblock('for (ListValue::const_iterator it = list->begin(); '
653                'it != list->end(); ++it) {')
654      self._GenerateStringToEnumConversion(
655          c, prop.item_type, '(*it)', 'enum_temp')
656      c.Append('%(dst)s->%(name)s' + accessor + 'push_back(enum_temp);')
657      c.Eblock('}')
658
659  def _GenerateStringToEnumConversion(self, c, prop, value_var, enum_temp):
660    """Appends code that converts a string to an enum.
661    Leaves failure_value unsubstituted.
662
663    c: the code that is appended to.
664    prop: the property that the code is populating.
665    value_var: the string value that is being converted.
666    enum_temp: the name used to store the temporary enum value.
667    """
668    (c.Append('std::string enum_as_string;')
669      .Append('if (!%s->GetAsString(&enum_as_string))' % value_var)
670      .Append('  return %(failure_value)s;')
671      .Append('%(type)s %(enum)s = From%(type)sString(enum_as_string);' % {
672        'type': self._cpp_type_generator.GetCompiledType(prop),
673        'enum': enum_temp
674      })
675      .Append('if (%s == %s)' %
676        (enum_temp, self._cpp_type_generator.GetEnumNoneValue(prop)))
677     .Append('  return %(failure_value)s;'))
678
679  def _GeneratePropertyFunctions(self, param_namespace, params):
680    """Generate the functions for structures generated by a property such as
681    CreateEnumValue for ENUMs and Populate/ToValue for Params/Results objects.
682    """
683    c = Code()
684    for param in params:
685      if param.type_ == PropertyType.OBJECT:
686        c.Concat(self._GenerateType(
687            param_namespace + '::' + cpp_util.Classname(param.name),
688            param))
689        c.Append()
690      elif param.type_ == PropertyType.ARRAY:
691        c.Concat(self._GeneratePropertyFunctions(
692            param_namespace, [param.item_type]))
693      elif param.type_ == PropertyType.CHOICES:
694        c.Concat(self._GeneratePropertyFunctions(
695            param_namespace, param.choices.values()))
696        if param.from_client:
697          c.Concat(self._GenerateGetChoiceValue(param_namespace, param))
698      elif param.type_ == PropertyType.ENUM:
699        (c.Concat(self._GenerateCreateEnumValue(param_namespace, param))
700          .Append()
701          .Concat(self._GenerateEnumFromString(param_namespace,
702                                               param,
703                                               use_namespace=True))
704          .Append()
705          .Concat(self._GenerateEnumToString(param_namespace,
706                                             param,
707                                             use_namespace=True))
708          .Append())
709    return c
710
711  def _GenerateGetChoiceValue(self, cpp_namespace, prop):
712    """Generates Get<Type>ChoiceValue() that returns a scoped_ptr<base::Value>
713    representing the choice value.
714    """
715    c = Code()
716    (c.Sblock('scoped_ptr<base::Value> '
717              '%(cpp_namespace)s::Get%(choice)sChoiceValue() const {')
718      .Sblock('switch (%s_type) {' % prop.unix_name)
719      .Concat(self._GenerateReturnCase(
720          self._cpp_type_generator.GetEnumNoneValue(prop),
721          'scoped_ptr<base::Value>()')))
722    for choice in self._cpp_type_generator.ExpandParams([prop]):
723      c.Concat(self._GenerateReturnCase(
724          self._cpp_type_generator.GetEnumValue(prop, choice.type_.name),
725          'make_scoped_ptr<base::Value>(%s)' %
726              self._CreateValueFromProperty(choice, choice.unix_name)))
727    (c.Eblock('}')
728      .Append('return scoped_ptr<base::Value>();')
729      .Eblock('}')
730      .Append()
731      .Substitute({
732        'cpp_namespace': cpp_namespace,
733        'choice': cpp_util.Classname(prop.name)
734      })
735    )
736    return c
737
738  def _GenerateCreateEnumTypeValue(self, cpp_namespace, prop):
739    """Generates CreateEnumValue() that returns the base::StringValue
740    representation of an enum type.
741    """
742    c = Code()
743    classname = cpp_util.Classname(schema_util.StripSchemaNamespace(prop.name))
744    (c.Sblock('scoped_ptr<base::Value> CreateEnumValue(%s %s) {' %
745        (classname, classname.lower()))
746      .Append('std::string enum_temp = ToString(%s);' % classname.lower())
747      .Append('if (enum_temp.empty())')
748      .Append('  return scoped_ptr<base::Value>();')
749      .Append('return scoped_ptr<base::Value>('
750              'base::Value::CreateStringValue(enum_temp));')
751      .Eblock('}'))
752    return c
753
754  def _GenerateEnumToString(self, cpp_namespace, prop, use_namespace=False):
755    """Generates ToString() which gets the string representation of an enum.
756    """
757    c = Code()
758    classname = cpp_util.Classname(schema_util.StripSchemaNamespace(prop.name))
759    if use_namespace:
760      namespace = '%s::' % cpp_namespace
761    else:
762      namespace = ''
763
764    (c.Append('// static')
765      .Sblock('std::string %(namespace)sToString(%(class)s enum_param) {'))
766    enum_prop = self._cpp_type_generator.GetReferencedProperty(prop)
767    c.Sblock('switch (enum_param) {')
768    for enum_value in enum_prop.enum_values:
769      c.Concat(self._GenerateReturnCase(
770          self._cpp_type_generator.GetEnumValue(prop, enum_value),
771          '"%s"' % enum_value))
772    (c.Append('case %s:' % self._cpp_type_generator.GetEnumNoneValue(prop))
773      .Append('  return "";')
774      .Eblock('}')
775      .Append('return "";')
776      .Eblock('}')
777      .Substitute({
778        'namespace': namespace,
779        'class': classname
780      }))
781    return c
782
783  def _GenerateEnumFromString(self, cpp_namespace, prop, use_namespace=False):
784    """Generates FromClassNameString() which gets an enum from its string
785    representation.
786    """
787    c = Code()
788    classname = cpp_util.Classname(schema_util.StripSchemaNamespace(prop.name))
789    if use_namespace:
790      namespace = '%s::' % cpp_namespace
791    else:
792      namespace = ''
793
794    (c.Append('// static')
795      .Sblock('%(namespace)s%(class)s'
796              ' %(namespace)sFrom%(class)sString('
797              'const std::string& enum_string) {'))
798    enum_prop = self._cpp_type_generator.GetReferencedProperty(prop)
799    for i, enum_value in enumerate(
800          self._cpp_type_generator.GetReferencedProperty(prop).enum_values):
801      # This is broken up into all ifs with no else ifs because we get
802      # "fatal error C1061: compiler limit : blocks nested too deeply"
803      # on Windows.
804      (c.Append('if (enum_string == "%s")' % enum_value)
805        .Append('  return %s;' %
806            self._cpp_type_generator.GetEnumValue(prop, enum_value)))
807    (c.Append('return %s;' %
808        self._cpp_type_generator.GetEnumNoneValue(prop))
809      .Eblock('}')
810      .Substitute({
811        'namespace': namespace,
812        'class': classname
813      }))
814    return c
815
816  # TODO(chebert): This is basically the same as GenerateCreateEnumTypeValue().
817  # The plan is to phase out the old-style enums, and make all enums into REF
818  # types.
819  def _GenerateCreateEnumValue(self, cpp_namespace, prop):
820    """Generates CreateEnumValue() that returns the base::StringValue
821    representation of an enum.
822    """
823    c = Code()
824    (c.Append('// static')
825      .Sblock('scoped_ptr<base::Value> %(cpp_namespace)s::CreateEnumValue('
826             '%(arg)s) {')
827      .Append('std::string enum_temp = ToString(%s);' % prop.unix_name)
828      .Append('if (enum_temp.empty())')
829      .Append('  return scoped_ptr<base::Value>();')
830      .Append('return scoped_ptr<base::Value>('
831              'base::Value::CreateStringValue(enum_temp));')
832      .Eblock('}')
833      .Substitute({
834        'cpp_namespace': cpp_namespace,
835        'arg': cpp_util.GetParameterDeclaration(
836            prop, self._cpp_type_generator.GetType(prop))
837      }))
838    return c
839
840  def _GenerateReturnCase(self, case_value, return_value):
841    """Generates a single return case for a switch block.
842    """
843    c = Code()
844    (c.Append('case %s:' % case_value)
845      .Append('  return %s;' % return_value)
846    )
847    return c
848
849  def _GenerateCreateCallbackArguments(self,
850                                       function_scope,
851                                       callback,
852                                       generate_to_json=False):
853    """Generate all functions to create Value parameters for a callback.
854
855    E.g for function "Bar", generate Bar::Results::Create
856    E.g for event "Baz", generate Baz::Create
857
858    function_scope: the function scope path, e.g. Foo::Bar for the function
859    Foo::Bar::Baz().
860    callback: the Function object we are creating callback arguments for.
861    generate_to_json: Generate a ToJson method.
862    """
863    c = Code()
864    params = callback.params
865    expanded_params = self._cpp_type_generator.ExpandParams(params)
866    c.Concat(self._GeneratePropertyFunctions(function_scope, expanded_params))
867
868    param_lists = self._cpp_type_generator.GetAllPossibleParameterLists(params)
869    for param_list in param_lists:
870      (c.Sblock('scoped_ptr<base::ListValue> %(function_scope)s::'
871                'Create(%(declaration_list)s) {')
872        .Append('scoped_ptr<base::ListValue> create_results('
873                'new base::ListValue());')
874      )
875      declaration_list = []
876      for param in param_list:
877        # We treat this argument as 'required' to avoid wrapping it in a
878        # scoped_ptr if it's optional.
879        param_copy = param.Copy()
880        param_copy.optional = False
881        declaration_list.append("const %s" % cpp_util.GetParameterDeclaration(
882            param_copy, self._cpp_type_generator.GetCompiledType(param_copy)))
883        param_name = param_copy.unix_name
884        if param_copy.type_ != param_copy.compiled_type:
885          param_name = 'temp_' + param_name
886          (c.Append('%s %s;' % (self._cpp_type_generator.GetType(param_copy),
887                                param_name))
888            .Append(cpp_util.GenerateCompiledTypeToTypeConversion(
889                 param_copy,
890                 param_copy.unix_name,
891                 param_name) + ';')
892          )
893        c.Append('create_results->Append(%s);' %
894            self._CreateValueFromProperty(param_copy, param_name))
895
896      c.Append('return create_results.Pass();')
897      c.Eblock('}')
898      if generate_to_json:
899        c.Append()
900        (c.Sblock('std::string %(function_scope)s::'
901                  'ToJson(%(declaration_list)s) {')
902          .Append('scoped_ptr<base::ListValue> create_results = '
903                  '%(function_scope)s::Create(%(param_list)s);')
904          .Append('std::string json;')
905          .Append('base::JSONWriter::Write(create_results.get(), &json);')
906          .Append('return json;')
907        )
908        c.Eblock('}')
909
910      c.Substitute({
911          'function_scope': function_scope,
912          'declaration_list': ', '.join(declaration_list),
913          'param_list': ', '.join(param.unix_name for param in param_list)
914      })
915
916    return c
917
918  def _InitializePropertyToDefault(self, prop, dst):
919    """Initialize a model.Property to its default value inside an object.
920
921    E.g for optional enum "state", generate dst->state = STATE_NONE;
922
923    dst: Type*
924    """
925    c = Code()
926    if (self._cpp_type_generator.IsEnumOrEnumRef(prop) or
927        prop.type_ == PropertyType.CHOICES):
928      if prop.optional:
929        prop_name = prop.unix_name
930        if prop.type_ == PropertyType.CHOICES:
931          prop_name = prop.unix_name + '_type'
932        c.Append('%s->%s = %s;' % (
933          dst,
934          prop_name,
935          self._cpp_type_generator.GetEnumNoneValue(prop)))
936    return c
937
938  def _IsObjectOrObjectRef(self, prop):
939    """Determines if this property is an Object or is a ref to an Object.
940    """
941    return (self._cpp_type_generator.GetReferencedProperty(prop).type_ ==
942        PropertyType.OBJECT)
943
944  def _IsArrayOrArrayRef(self, prop):
945    """Determines if this property is an Array or is a ref to an Array.
946    """
947    return (self._cpp_type_generator.GetReferencedProperty(prop).type_ ==
948        PropertyType.ARRAY)
949
950  def _IsFundamentalOrFundamentalRef(self, prop):
951    """Determines if this property is a Fundamental type or is a ref to a
952    Fundamental type.
953    """
954    return (self._cpp_type_generator.GetReferencedProperty(prop).type_.
955        is_fundamental)
956