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