Home | History | Annotate | Download | only in generators
      1 # Copyright 2013 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 
      5 """Generates C++ source files from a mojom.Module."""
      6 
      7 import mojom.generate.generator as generator
      8 import mojom.generate.module as mojom
      9 import mojom.generate.pack as pack
     10 from mojom.generate.template_expander import UseJinja
     11 
     12 
     13 _kind_to_cpp_type = {
     14   mojom.BOOL:         "bool",
     15   mojom.INT8:         "int8_t",
     16   mojom.UINT8:        "uint8_t",
     17   mojom.INT16:        "int16_t",
     18   mojom.UINT16:       "uint16_t",
     19   mojom.INT32:        "int32_t",
     20   mojom.UINT32:       "uint32_t",
     21   mojom.FLOAT:        "float",
     22   mojom.HANDLE:       "mojo::Handle",
     23   mojom.DCPIPE:       "mojo::DataPipeConsumerHandle",
     24   mojom.DPPIPE:       "mojo::DataPipeProducerHandle",
     25   mojom.MSGPIPE:      "mojo::MessagePipeHandle",
     26   mojom.SHAREDBUFFER: "mojo::SharedBufferHandle",
     27   mojom.INT64:        "int64_t",
     28   mojom.UINT64:       "uint64_t",
     29   mojom.DOUBLE:       "double",
     30 }
     31 
     32 def DefaultValue(field):
     33   if field.default:
     34     if isinstance(field.kind, mojom.Struct):
     35       assert field.default == "default"
     36       return "%s::New()" % GetNameForKind(field.kind)
     37     return ExpressionToText(field.default)
     38   return ""
     39 
     40 def NamespaceToArray(namespace):
     41   return namespace.split('.') if namespace else []
     42 
     43 def GetNameForKind(kind, internal = False):
     44   parts = []
     45   if kind.imported_from:
     46     parts.extend(NamespaceToArray(kind.imported_from["namespace"]))
     47   if internal:
     48     parts.append("internal")
     49   if kind.parent_kind:
     50     parts.append(kind.parent_kind.name)
     51   parts.append(kind.name)
     52   return "::".join(parts)
     53 
     54 def GetCppType(kind):
     55   if isinstance(kind, mojom.Struct):
     56     return "%s_Data*" % GetNameForKind(kind, internal=True)
     57   if isinstance(kind, mojom.Array):
     58     return "mojo::internal::Array_Data<%s>*" % GetCppType(kind.kind)
     59   if isinstance(kind, mojom.Interface) or \
     60      isinstance(kind, mojom.InterfaceRequest):
     61     return "mojo::MessagePipeHandle"
     62   if isinstance(kind, mojom.Enum):
     63     return "int32_t"
     64   if kind.spec == 's':
     65     return "mojo::internal::String_Data*"
     66   return _kind_to_cpp_type[kind]
     67 
     68 def GetCppPodType(kind):
     69   if kind.spec == 's':
     70     return "char*"
     71   return _kind_to_cpp_type[kind]
     72 
     73 def GetCppArrayArgWrapperType(kind):
     74   if isinstance(kind, mojom.Enum):
     75     return GetNameForKind(kind)
     76   if isinstance(kind, mojom.Struct):
     77     return "%sPtr" % GetNameForKind(kind)
     78   if isinstance(kind, mojom.Array):
     79     return "mojo::Array<%s> " % GetCppArrayArgWrapperType(kind.kind)
     80   if isinstance(kind, mojom.Interface):
     81     raise Exception("Arrays of interfaces not yet supported!")
     82   if isinstance(kind, mojom.InterfaceRequest):
     83     raise Exception("Arrays of interface requests not yet supported!")
     84   if kind.spec == 's':
     85     return "mojo::String"
     86   if kind.spec == 'h':
     87     return "mojo::ScopedHandle"
     88   if kind.spec == 'h:d:c':
     89     return "mojo::ScopedDataPipeConsumerHandle"
     90   if kind.spec == 'h:d:p':
     91     return "mojo::ScopedDataPipeProducerHandle"
     92   if kind.spec == 'h:m':
     93     return "mojo::ScopedMessagePipeHandle"
     94   if kind.spec == 'h:s':
     95     return "mojo::ScopedSharedBufferHandle"
     96   return _kind_to_cpp_type[kind]
     97 
     98 def GetCppResultWrapperType(kind):
     99   if isinstance(kind, mojom.Enum):
    100     return GetNameForKind(kind)
    101   if isinstance(kind, mojom.Struct):
    102     return "%sPtr" % GetNameForKind(kind)
    103   if isinstance(kind, mojom.Array):
    104     return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind)
    105   if isinstance(kind, mojom.Interface):
    106     return "%sPtr" % GetNameForKind(kind)
    107   if isinstance(kind, mojom.InterfaceRequest):
    108     return "mojo::InterfaceRequest<%s>" % GetNameForKind(kind.kind)
    109   if kind.spec == 's':
    110     return "mojo::String"
    111   if kind.spec == 'h':
    112     return "mojo::ScopedHandle"
    113   if kind.spec == 'h:d:c':
    114     return "mojo::ScopedDataPipeConsumerHandle"
    115   if kind.spec == 'h:d:p':
    116     return "mojo::ScopedDataPipeProducerHandle"
    117   if kind.spec == 'h:m':
    118     return "mojo::ScopedMessagePipeHandle"
    119   if kind.spec == 'h:s':
    120     return "mojo::ScopedSharedBufferHandle"
    121   return _kind_to_cpp_type[kind]
    122 
    123 def GetCppWrapperType(kind):
    124   if isinstance(kind, mojom.Enum):
    125     return GetNameForKind(kind)
    126   if isinstance(kind, mojom.Struct):
    127     return "%sPtr" % GetNameForKind(kind)
    128   if isinstance(kind, mojom.Array):
    129     return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind)
    130   if isinstance(kind, mojom.Interface):
    131     return "mojo::ScopedMessagePipeHandle"
    132   if isinstance(kind, mojom.InterfaceRequest):
    133     raise Exception("InterfaceRequest fields not supported!")
    134   if kind.spec == 's':
    135     return "mojo::String"
    136   if kind.spec == 'h':
    137     return "mojo::ScopedHandle"
    138   if kind.spec == 'h:d:c':
    139     return "mojo::ScopedDataPipeConsumerHandle"
    140   if kind.spec == 'h:d:p':
    141     return "mojo::ScopedDataPipeProducerHandle"
    142   if kind.spec == 'h:m':
    143     return "mojo::ScopedMessagePipeHandle"
    144   if kind.spec == 'h:s':
    145     return "mojo::ScopedSharedBufferHandle"
    146   return _kind_to_cpp_type[kind]
    147 
    148 def GetCppConstWrapperType(kind):
    149   if isinstance(kind, mojom.Struct):
    150     return "%sPtr" % GetNameForKind(kind)
    151   if isinstance(kind, mojom.Array):
    152     return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind)
    153   if isinstance(kind, mojom.Interface):
    154     return "%sPtr" % GetNameForKind(kind)
    155   if isinstance(kind, mojom.InterfaceRequest):
    156     return "mojo::InterfaceRequest<%s>" % GetNameForKind(kind.kind)
    157   if isinstance(kind, mojom.Enum):
    158     return GetNameForKind(kind)
    159   if kind.spec == 's':
    160     return "const mojo::String&"
    161   if kind.spec == 'h':
    162     return "mojo::ScopedHandle"
    163   if kind.spec == 'h:d:c':
    164     return "mojo::ScopedDataPipeConsumerHandle"
    165   if kind.spec == 'h:d:p':
    166     return "mojo::ScopedDataPipeProducerHandle"
    167   if kind.spec == 'h:m':
    168     return "mojo::ScopedMessagePipeHandle"
    169   if kind.spec == 'h:s':
    170     return "mojo::ScopedSharedBufferHandle"
    171   if not kind in _kind_to_cpp_type:
    172     print "missing:", kind.spec
    173   return _kind_to_cpp_type[kind]
    174 
    175 def GetCppFieldType(kind):
    176   if isinstance(kind, mojom.Struct):
    177     return ("mojo::internal::StructPointer<%s_Data>" %
    178         GetNameForKind(kind, internal=True))
    179   if isinstance(kind, mojom.Array):
    180     return "mojo::internal::ArrayPointer<%s>" % GetCppType(kind.kind)
    181   if isinstance(kind, mojom.Interface) or \
    182      isinstance(kind, mojom.InterfaceRequest):
    183     return "mojo::MessagePipeHandle"
    184   if isinstance(kind, mojom.Enum):
    185     return GetNameForKind(kind)
    186   if kind.spec == 's':
    187     return "mojo::internal::StringPointer"
    188   return _kind_to_cpp_type[kind]
    189 
    190 def IsStructWithHandles(struct):
    191   for pf in struct.packed.packed_fields:
    192     if generator.IsHandleKind(pf.field.kind):
    193       return True
    194   return False
    195 
    196 def TranslateConstants(token):
    197   if isinstance(token, (mojom.NamedValue, mojom.EnumValue)):
    198     # Both variable and enum constants are constructed like:
    199     # Namespace::Struct::CONSTANT_NAME
    200     name = []
    201     if token.imported_from:
    202       name.extend(NamespaceToArray(token.namespace))
    203     if token.parent_kind:
    204       name.append(token.parent_kind.name)
    205     name.append(token.name)
    206     return "::".join(name)
    207   return token
    208 
    209 def ExpressionToText(value):
    210   return TranslateConstants(value)
    211 
    212 def HasCallbacks(interface):
    213   for method in interface.methods:
    214     if method.response_parameters != None:
    215       return True
    216   return False
    217 
    218 def ShouldInlineStruct(struct):
    219   # TODO(darin): Base this on the size of the wrapper class.
    220   if len(struct.fields) > 4:
    221     return False
    222   for field in struct.fields:
    223     if generator.IsHandleKind(field.kind) or generator.IsObjectKind(field.kind):
    224       return False
    225   return True
    226 
    227 _HEADER_SIZE = 8
    228 
    229 class Generator(generator.Generator):
    230 
    231   cpp_filters = {
    232     "cpp_const_wrapper_type": GetCppConstWrapperType,
    233     "cpp_field_type": GetCppFieldType,
    234     "cpp_pod_type": GetCppPodType,
    235     "cpp_result_type": GetCppResultWrapperType,
    236     "cpp_type": GetCppType,
    237     "cpp_wrapper_type": GetCppWrapperType,
    238     "default_value": DefaultValue,
    239     "expression_to_text": ExpressionToText,
    240     "get_name_for_kind": GetNameForKind,
    241     "get_pad": pack.GetPad,
    242     "has_callbacks": HasCallbacks,
    243     "should_inline": ShouldInlineStruct,
    244     "is_enum_kind": generator.IsEnumKind,
    245     "is_move_only_kind": generator.IsMoveOnlyKind,
    246     "is_handle_kind": generator.IsHandleKind,
    247     "is_interface_kind": generator.IsInterfaceKind,
    248     "is_interface_request_kind": generator.IsInterfaceRequestKind,
    249     "is_object_kind": generator.IsObjectKind,
    250     "is_string_kind": generator.IsStringKind,
    251     "is_struct_with_handles": IsStructWithHandles,
    252     "struct_size": lambda ps: ps.GetTotalSize() + _HEADER_SIZE,
    253     "struct_from_method": generator.GetStructFromMethod,
    254     "response_struct_from_method": generator.GetResponseStructFromMethod,
    255     "stylize_method": generator.StudlyCapsToCamel,
    256   }
    257 
    258   def GetJinjaExports(self):
    259     return {
    260       "module": self.module,
    261       "namespace": self.module.namespace,
    262       "namespaces_as_array": NamespaceToArray(self.module.namespace),
    263       "imports": self.module.imports,
    264       "kinds": self.module.kinds,
    265       "enums": self.module.enums,
    266       "structs": self.GetStructs(),
    267       "interfaces": self.module.interfaces,
    268     }
    269 
    270   @UseJinja("cpp_templates/module.h.tmpl", filters=cpp_filters)
    271   def GenerateModuleHeader(self):
    272     return self.GetJinjaExports()
    273 
    274   @UseJinja("cpp_templates/module-internal.h.tmpl", filters=cpp_filters)
    275   def GenerateModuleInternalHeader(self):
    276     return self.GetJinjaExports()
    277 
    278   @UseJinja("cpp_templates/module.cc.tmpl", filters=cpp_filters)
    279   def GenerateModuleSource(self):
    280     return self.GetJinjaExports()
    281 
    282   def GenerateFiles(self, args):
    283     self.Write(self.GenerateModuleHeader(), "%s.h" % self.module.name)
    284     self.Write(self.GenerateModuleInternalHeader(),
    285         "%s-internal.h" % self.module.name)
    286     self.Write(self.GenerateModuleSource(), "%s.cc" % self.module.name)
    287