Пример #1
0
 def _GenerateListValueToEnumArrayConversion(self,
                                             item_type,
                                             src_var,
                                             dst_var,
                                             failure_value,
                                             is_ptr=False):
   """Returns Code that converts a ListValue of string constants from
   |src_var| into an array of enums of |type_| in |dst_var|. On failure,
   returns |failure_value|.
   """
   c = Code()
   accessor = '.'
   if is_ptr:
     accessor = '->'
     cpp_type = self._type_helper.GetCppType(item_type, is_in_container=True)
     c.Append('%s.reset(new std::vector<%s>);' %
                  (dst_var, cpp_util.PadForGenerics(cpp_type)))
   (c.Sblock('for (const auto& it : *(%s)) {' % src_var)
     .Append('%s tmp;' % self._type_helper.GetCppType(item_type))
     .Concat(self._GenerateStringToEnumConversion(item_type,
                                                  '(it)',
                                                  'tmp',
                                                  failure_value))
     .Append('%s%spush_back(tmp);' % (dst_var, accessor))
     .Eblock('}')
   )
   return c
Пример #2
0
  def _GenerateObjectTypeToValue(self, cpp_namespace, type_):
    """Generates a function that serializes an object-representing type
    into a base::DictionaryValue.
    """
    c = Code()
    (c.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' %
          cpp_namespace)
        .Append('scoped_ptr<base::DictionaryValue> value('
                    'new base::DictionaryValue());')
        .Append()
    )

    for prop in type_.properties.values():
      if prop.optional:
        # Optional enum values are generated with a NONE enum value.
        underlying_type = self._type_helper.FollowRef(prop.type_)
        if underlying_type.property_type == PropertyType.ENUM:
          c.Sblock('if (%s != %s) {' %
              (prop.unix_name,
               self._type_helper.GetEnumNoneValue(prop.type_)))
        else:
          c.Sblock('if (%s.get()) {' % prop.unix_name)

      # ANY is a base::Value which is abstract and cannot be a direct member, so
      # it will always be a pointer.
      is_ptr = prop.optional or prop.type_.property_type == PropertyType.ANY
      c.Append('value->SetWithoutPathExpansion("%s", %s);' % (
          prop.name,
          self._CreateValueFromType(prop.type_,
                                    'this->%s' % prop.unix_name,
                                    is_ptr=is_ptr)))

      if prop.optional:
        c.Eblock('}')

    if type_.additional_properties is not None:
      if type_.additional_properties.property_type == PropertyType.ANY:
        c.Append('value->MergeDictionary(&additional_properties);')
      else:
        # Non-copyable types will be wrapped in a linked_ptr for inclusion in
        # maps, so we need to unwrap them.
        needs_unwrap = (
            not self._type_helper.IsCopyable(type_.additional_properties))
        cpp_type = self._type_helper.GetCppType(type_.additional_properties,
                                                is_in_container=True)
        (c.Sblock('for (std::map<std::string, %s>::const_iterator it =' %
                      cpp_util.PadForGenerics(cpp_type))
          .Append('       additional_properties.begin();')
          .Append('   it != additional_properties.end(); ++it) {')
          .Append('value->SetWithoutPathExpansion(it->first, %s);' %
              self._CreateValueFromType(
                  type_.additional_properties,
                  '%sit->second' % ('*' if needs_unwrap else '')))
          .Eblock('}')
        )

    return (c.Append()
             .Append('return value.Pass();')
           .Eblock('}'))
Пример #3
0
    def GetCppType(self, type_, is_ptr=False, is_in_container=False):
        """Translates a model.Property or model.Type into its C++ type.

    If REF types from different namespaces are referenced, will resolve
    using self._schema_loader.

    Use |is_ptr| if the type is optional. This will wrap the type in a
    scoped_ptr if possible (it is not possible to wrap an enum).

    Use |is_in_container| if the type is appearing in a collection, e.g. a
    std::vector or std::map. This will wrap it in the correct type with spacing.
    """
        cpp_type = None
        if type_.property_type == PropertyType.REF:
            ref_type = self._FindType(type_.ref_type)
            if ref_type is None:
                raise KeyError('Cannot find referenced type: %s' %
                               type_.ref_type)
            cpp_type = self.GetCppType(ref_type)
        elif type_.property_type == PropertyType.BOOLEAN:
            cpp_type = 'bool'
        elif type_.property_type == PropertyType.INTEGER:
            cpp_type = 'int'
        elif type_.property_type == PropertyType.INT64:
            cpp_type = 'int64'
        elif type_.property_type == PropertyType.DOUBLE:
            cpp_type = 'double'
        elif type_.property_type == PropertyType.STRING:
            cpp_type = 'std::string'
        elif type_.property_type in (PropertyType.ENUM, PropertyType.OBJECT,
                                     PropertyType.CHOICES):
            if self._default_namespace is type_.namespace:
                cpp_type = cpp_util.Classname(type_.name)
            else:
                cpp_namespace = cpp_util.GetCppNamespace(
                    type_.namespace.environment.namespace_pattern,
                    type_.namespace.unix_name)
                cpp_type = '%s::%s' % (cpp_namespace,
                                       cpp_util.Classname(type_.name))
        elif type_.property_type == PropertyType.ANY:
            cpp_type = 'base::Value'
        elif type_.property_type == PropertyType.FUNCTION:
            # Functions come into the json schema compiler as empty objects. We can
            # record these as empty DictionaryValues so that we know if the function
            # was passed in or not.
            cpp_type = 'base::DictionaryValue'
        elif type_.property_type == PropertyType.ARRAY:
            item_cpp_type = self.GetCppType(type_.item_type,
                                            is_in_container=True)
            cpp_type = 'std::vector<%s>' % cpp_util.PadForGenerics(
                item_cpp_type)
        elif type_.property_type == PropertyType.BINARY:
            cpp_type = 'std::vector<char>'
        else:
            raise NotImplementedError('Cannot get type of %s' %
                                      type_.property_type)

        # HACK: optional ENUM is represented elsewhere with a _NONE value, so it
        # never needs to be wrapped in pointer shenanigans.
        # TODO(kalman): change this - but it's an exceedingly far-reaching change.
        if not self.FollowRef(type_).property_type == PropertyType.ENUM:
            if is_in_container and (is_ptr or not self.IsCopyable(type_)):
                cpp_type = 'linked_ptr<%s>' % cpp_util.PadForGenerics(cpp_type)
            elif is_ptr:
                cpp_type = 'scoped_ptr<%s>' % cpp_util.PadForGenerics(cpp_type)

        return cpp_type
Пример #4
0
    def _GenerateType(self, type_, is_toplevel=False, generate_typedefs=False):
        """Generates a struct for |type_|.

    |is_toplevel|       implies that the type was declared in the "types" field
                        of an API schema. This determines the correct function
                        modifier(s).
    |generate_typedefs| controls whether primitive types should be generated as
                        a typedef. This may not always be desired. If false,
                        primitive types are ignored.
    """
        classname = cpp_util.Classname(schema_util.StripNamespace(type_.name))
        c = Code()

        if type_.functions:
            # Wrap functions within types in the type's namespace.
            (c.Append('namespace %s {' % classname).Append())
            for function in type_.functions.values():
                c.Cblock(self._GenerateFunction(function))
            c.Append('}  // namespace %s' % classname)
        elif type_.property_type == PropertyType.ARRAY:
            if generate_typedefs and type_.description:
                c.Comment(type_.description)
            c.Cblock(
                self._GenerateType(type_.item_type, is_toplevel=is_toplevel))
            if generate_typedefs:
                (c.Append('typedef std::vector<%s > %s;' %
                          (self._type_helper.GetCppType(
                              type_.item_type), classname)))
        elif type_.property_type == PropertyType.STRING:
            if generate_typedefs:
                if type_.description:
                    c.Comment(type_.description)
                c.Append('typedef std::string %(classname)s;')
        elif type_.property_type == PropertyType.ENUM:
            if type_.description:
                c.Comment(type_.description)
            c.Cblock(self._GenerateEnumDeclaration(classname, type_))
            # Top level enums are in a namespace scope so the methods shouldn't be
            # static. On the other hand, those declared inline (e.g. in an object) do.
            maybe_static = '' if is_toplevel else 'static '
            (c.Append().Append(
                '%sstd::string ToString(%s as_enum);' %
                (maybe_static, classname)).Append(
                    '%s%s Parse%s(const std::string& as_string);' %
                    (maybe_static, classname, classname)))
        elif type_.property_type in (PropertyType.CHOICES,
                                     PropertyType.OBJECT):
            if type_.description:
                c.Comment(type_.description)
            (c.Sblock('struct %(classname)s {').Append(
                '%(classname)s();').Append('~%(classname)s();'))
            if type_.origin.from_json:
                (c.Append().Comment(
                    'Populates a %s object from a base::Value. Returns'
                    ' whether |out| was successfully populated.' %
                    classname).Append('static bool Populate(%s);' %
                                      self._GenerateParams(
                                          ('const base::Value& value',
                                           '%s* out' % classname))))
                if is_toplevel:
                    (c.Append().Comment(
                        'Creates a %s object from a base::Value, or NULL on '
                        'failure.' % classname).Append(
                            'static scoped_ptr<%s> FromValue(%s);' %
                            (classname,
                             self._GenerateParams(
                                 ('const base::Value& value', )))))
            if type_.origin.from_client:
                value_type = ('base::Value'
                              if type_.property_type is PropertyType.CHOICES
                              else 'base::DictionaryValue')
                (c.Append().Comment(
                    'Returns a new %s representing the serialized form of this '
                    '%s object.' % (value_type, classname)).Append(
                        'scoped_ptr<%s> ToValue() const;' % value_type))
            if type_.property_type == PropertyType.CHOICES:
                # Choices are modelled with optional fields for each choice. Exactly one
                # field of the choice is guaranteed to be set by the compiler.
                c.Cblock(self._GenerateTypes(type_.choices))
                c.Append('// Choices:')
                for choice_type in type_.choices:
                    c.Append('%s as_%s;' % (self._type_helper.GetCppType(
                        choice_type, is_ptr=True), choice_type.unix_name))
            else:
                properties = type_.properties.values()
                (c.Append().Cblock(
                    self._GenerateTypes(p.type_ for p in properties)).Cblock(
                        self._GenerateFields(properties)))
                if type_.additional_properties is not None:
                    # Most additionalProperties actually have type "any", which is better
                    # modelled as a DictionaryValue rather than a map of string -> Value.
                    if type_.additional_properties.property_type == PropertyType.ANY:
                        c.Append(
                            'base::DictionaryValue additional_properties;')
                    else:
                        (c.Cblock(
                            self._GenerateType(type_.additional_properties)).
                         Append(
                             'std::map<std::string, %s> additional_properties;'
                             % cpp_util.PadForGenerics(
                                 self._type_helper.GetCppType(
                                     type_.additional_properties,
                                     is_in_container=True))))
            (c.Eblock().Append().Sblock(' private:').Append(
                'DISALLOW_COPY_AND_ASSIGN(%(classname)s);').Eblock('};'))
        return c.Substitute({'classname': classname})