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 7import mojom.generate.generator as generator 8import mojom.generate.module as mojom 9import mojom.generate.pack as pack 10from 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.NULLABLE_HANDLE: "mojo::Handle", 28 mojom.NULLABLE_DCPIPE: "mojo::DataPipeConsumerHandle", 29 mojom.NULLABLE_DPPIPE: "mojo::DataPipeProducerHandle", 30 mojom.NULLABLE_MSGPIPE: "mojo::MessagePipeHandle", 31 mojom.NULLABLE_SHAREDBUFFER: "mojo::SharedBufferHandle", 32 mojom.INT64: "int64_t", 33 mojom.UINT64: "uint64_t", 34 mojom.DOUBLE: "double", 35} 36 37_kind_to_cpp_literal_suffix = { 38 mojom.UINT8: "U", 39 mojom.UINT16: "U", 40 mojom.UINT32: "U", 41 mojom.FLOAT: "f", 42 mojom.UINT64: "ULL", 43} 44 45def ConstantValue(constant): 46 return ExpressionToText(constant.value, kind=constant.kind) 47 48def DefaultValue(field): 49 if field.default: 50 if mojom.IsStructKind(field.kind): 51 assert field.default == "default" 52 return "%s::New()" % GetNameForKind(field.kind) 53 return ExpressionToText(field.default, kind=field.kind) 54 return "" 55 56def NamespaceToArray(namespace): 57 return namespace.split('.') if namespace else [] 58 59def GetNameForKind(kind, internal = False): 60 parts = [] 61 if kind.imported_from: 62 parts.extend(NamespaceToArray(kind.imported_from["namespace"])) 63 if internal: 64 parts.append("internal") 65 if kind.parent_kind: 66 parts.append(kind.parent_kind.name) 67 parts.append(kind.name) 68 return "::".join(parts) 69 70def GetCppType(kind): 71 if mojom.IsStructKind(kind): 72 return "%s_Data*" % GetNameForKind(kind, internal=True) 73 if mojom.IsAnyArrayKind(kind): 74 return "mojo::internal::Array_Data<%s>*" % GetCppType(kind.kind) 75 if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): 76 return "mojo::MessagePipeHandle" 77 if mojom.IsEnumKind(kind): 78 return "int32_t" 79 if mojom.IsStringKind(kind): 80 return "mojo::internal::String_Data*" 81 return _kind_to_cpp_type[kind] 82 83def GetCppPodType(kind): 84 if mojom.IsStringKind(kind): 85 return "char*" 86 return _kind_to_cpp_type[kind] 87 88def GetCppArrayArgWrapperType(kind): 89 if mojom.IsEnumKind(kind): 90 return GetNameForKind(kind) 91 if mojom.IsStructKind(kind): 92 return "%sPtr" % GetNameForKind(kind) 93 if mojom.IsAnyArrayKind(kind): 94 return "mojo::Array<%s> " % GetCppArrayArgWrapperType(kind.kind) 95 if mojom.IsInterfaceKind(kind): 96 raise Exception("Arrays of interfaces not yet supported!") 97 if mojom.IsInterfaceRequestKind(kind): 98 raise Exception("Arrays of interface requests not yet supported!") 99 if mojom.IsStringKind(kind): 100 return "mojo::String" 101 if mojom.IsHandleKind(kind): 102 return "mojo::ScopedHandle" 103 if mojom.IsDataPipeConsumerKind(kind): 104 return "mojo::ScopedDataPipeConsumerHandle" 105 if mojom.IsDataPipeProducerKind(kind): 106 return "mojo::ScopedDataPipeProducerHandle" 107 if mojom.IsMessagePipeKind(kind): 108 return "mojo::ScopedMessagePipeHandle" 109 if mojom.IsSharedBufferKind(kind): 110 return "mojo::ScopedSharedBufferHandle" 111 return _kind_to_cpp_type[kind] 112 113def GetCppResultWrapperType(kind): 114 if mojom.IsEnumKind(kind): 115 return GetNameForKind(kind) 116 if mojom.IsStructKind(kind): 117 return "%sPtr" % GetNameForKind(kind) 118 if mojom.IsAnyArrayKind(kind): 119 return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind) 120 if mojom.IsInterfaceKind(kind): 121 return "%sPtr" % GetNameForKind(kind) 122 if mojom.IsInterfaceRequestKind(kind): 123 return "mojo::InterfaceRequest<%s>" % GetNameForKind(kind.kind) 124 if mojom.IsStringKind(kind): 125 return "mojo::String" 126 if mojom.IsHandleKind(kind): 127 return "mojo::ScopedHandle" 128 if mojom.IsDataPipeConsumerKind(kind): 129 return "mojo::ScopedDataPipeConsumerHandle" 130 if mojom.IsDataPipeProducerKind(kind): 131 return "mojo::ScopedDataPipeProducerHandle" 132 if mojom.IsMessagePipeKind(kind): 133 return "mojo::ScopedMessagePipeHandle" 134 if mojom.IsSharedBufferKind(kind): 135 return "mojo::ScopedSharedBufferHandle" 136 return _kind_to_cpp_type[kind] 137 138def GetCppWrapperType(kind): 139 if mojom.IsEnumKind(kind): 140 return GetNameForKind(kind) 141 if mojom.IsStructKind(kind): 142 return "%sPtr" % GetNameForKind(kind) 143 if mojom.IsAnyArrayKind(kind): 144 return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind) 145 if mojom.IsInterfaceKind(kind): 146 return "%sPtr" % GetNameForKind(kind) 147 if mojom.IsInterfaceRequestKind(kind): 148 raise Exception("InterfaceRequest fields not supported!") 149 if mojom.IsStringKind(kind): 150 return "mojo::String" 151 if mojom.IsHandleKind(kind): 152 return "mojo::ScopedHandle" 153 if mojom.IsDataPipeConsumerKind(kind): 154 return "mojo::ScopedDataPipeConsumerHandle" 155 if mojom.IsDataPipeProducerKind(kind): 156 return "mojo::ScopedDataPipeProducerHandle" 157 if mojom.IsMessagePipeKind(kind): 158 return "mojo::ScopedMessagePipeHandle" 159 if mojom.IsSharedBufferKind(kind): 160 return "mojo::ScopedSharedBufferHandle" 161 return _kind_to_cpp_type[kind] 162 163def GetCppConstWrapperType(kind): 164 if mojom.IsStructKind(kind): 165 return "%sPtr" % GetNameForKind(kind) 166 if mojom.IsAnyArrayKind(kind): 167 return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind) 168 if mojom.IsInterfaceKind(kind): 169 return "%sPtr" % GetNameForKind(kind) 170 if mojom.IsInterfaceRequestKind(kind): 171 return "mojo::InterfaceRequest<%s>" % GetNameForKind(kind.kind) 172 if mojom.IsEnumKind(kind): 173 return GetNameForKind(kind) 174 if mojom.IsStringKind(kind): 175 return "const mojo::String&" 176 if mojom.IsHandleKind(kind): 177 return "mojo::ScopedHandle" 178 if mojom.IsDataPipeConsumerKind(kind): 179 return "mojo::ScopedDataPipeConsumerHandle" 180 if mojom.IsDataPipeProducerKind(kind): 181 return "mojo::ScopedDataPipeProducerHandle" 182 if mojom.IsMessagePipeKind(kind): 183 return "mojo::ScopedMessagePipeHandle" 184 if mojom.IsSharedBufferKind(kind): 185 return "mojo::ScopedSharedBufferHandle" 186 if not kind in _kind_to_cpp_type: 187 print "missing:", kind.spec 188 return _kind_to_cpp_type[kind] 189 190def GetCppFieldType(kind): 191 if mojom.IsStructKind(kind): 192 return ("mojo::internal::StructPointer<%s_Data>" % 193 GetNameForKind(kind, internal=True)) 194 if mojom.IsAnyArrayKind(kind): 195 return "mojo::internal::ArrayPointer<%s>" % GetCppType(kind.kind) 196 if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): 197 return "mojo::MessagePipeHandle" 198 if mojom.IsEnumKind(kind): 199 return GetNameForKind(kind) 200 if mojom.IsStringKind(kind): 201 return "mojo::internal::StringPointer" 202 return _kind_to_cpp_type[kind] 203 204def IsStructWithHandles(struct): 205 for pf in struct.packed.packed_fields: 206 if mojom.IsAnyHandleKind(pf.field.kind): 207 return True 208 return False 209 210def TranslateConstants(token, kind): 211 if isinstance(token, mojom.NamedValue): 212 # Both variable and enum constants are constructed like: 213 # Namespace::Struct::CONSTANT_NAME 214 # For enums, CONSTANT_NAME is ENUM_NAME_ENUM_VALUE. 215 name = [] 216 if token.imported_from: 217 name.extend(NamespaceToArray(token.namespace)) 218 if token.parent_kind: 219 name.append(token.parent_kind.name) 220 if isinstance(token, mojom.EnumValue): 221 name.append( 222 "%s_%s" % (generator.CamelCaseToAllCaps(token.enum.name), token.name)) 223 else: 224 name.append(token.name) 225 return "::".join(name) 226 227 if isinstance(token, mojom.BuiltinValue): 228 if token.value == "double.INFINITY" or token.value == "float.INFINITY": 229 return "INFINITY"; 230 if token.value == "double.NEGATIVE_INFINITY" or \ 231 token.value == "float.NEGATIVE_INFINITY": 232 return "-INFINITY"; 233 if token.value == "double.NAN" or token.value == "float.NAN": 234 return "NAN"; 235 236 if (kind is not None and mojom.IsFloatKind(kind)): 237 return token if token.isdigit() else token + "f"; 238 239 return '%s%s' % (token, _kind_to_cpp_literal_suffix.get(kind, '')) 240 241def ExpressionToText(value, kind=None): 242 return TranslateConstants(value, kind) 243 244def ShouldInlineStruct(struct): 245 # TODO(darin): Base this on the size of the wrapper class. 246 if len(struct.fields) > 4: 247 return False 248 for field in struct.fields: 249 if mojom.IsMoveOnlyKind(field.kind): 250 return False 251 return True 252 253def GetArrayValidateParams(kind): 254 if not mojom.IsAnyArrayKind(kind) and not mojom.IsStringKind(kind): 255 return "mojo::internal::NoValidateParams" 256 257 if mojom.IsStringKind(kind): 258 expected_num_elements = 0 259 element_is_nullable = False 260 element_validate_params = "mojo::internal::NoValidateParams" 261 else: 262 expected_num_elements = generator.ExpectedArraySize(kind) 263 element_is_nullable = mojom.IsNullableKind(kind.kind) 264 element_validate_params = GetArrayValidateParams(kind.kind) 265 266 return "mojo::internal::ArrayValidateParams<%d, %s,\n%s> " % ( 267 expected_num_elements, 268 'true' if element_is_nullable else 'false', 269 element_validate_params) 270 271_HEADER_SIZE = 8 272 273class Generator(generator.Generator): 274 275 cpp_filters = { 276 "constant_value": ConstantValue, 277 "cpp_const_wrapper_type": GetCppConstWrapperType, 278 "cpp_field_type": GetCppFieldType, 279 "cpp_pod_type": GetCppPodType, 280 "cpp_result_type": GetCppResultWrapperType, 281 "cpp_type": GetCppType, 282 "cpp_wrapper_type": GetCppWrapperType, 283 "default_value": DefaultValue, 284 "expected_array_size": generator.ExpectedArraySize, 285 "expression_to_text": ExpressionToText, 286 "get_array_validate_params": GetArrayValidateParams, 287 "get_name_for_kind": GetNameForKind, 288 "get_pad": pack.GetPad, 289 "has_callbacks": mojom.HasCallbacks, 290 "should_inline": ShouldInlineStruct, 291 "is_any_array_kind": mojom.IsAnyArrayKind, 292 "is_enum_kind": mojom.IsEnumKind, 293 "is_move_only_kind": mojom.IsMoveOnlyKind, 294 "is_any_handle_kind": mojom.IsAnyHandleKind, 295 "is_interface_kind": mojom.IsInterfaceKind, 296 "is_interface_request_kind": mojom.IsInterfaceRequestKind, 297 "is_nullable_kind": mojom.IsNullableKind, 298 "is_object_kind": mojom.IsObjectKind, 299 "is_string_kind": mojom.IsStringKind, 300 "is_struct_with_handles": IsStructWithHandles, 301 "struct_size": lambda ps: ps.GetTotalSize() + _HEADER_SIZE, 302 "struct_from_method": generator.GetStructFromMethod, 303 "response_struct_from_method": generator.GetResponseStructFromMethod, 304 "stylize_method": generator.StudlyCapsToCamel, 305 "to_all_caps": generator.CamelCaseToAllCaps, 306 } 307 308 def GetJinjaExports(self): 309 return { 310 "module": self.module, 311 "namespace": self.module.namespace, 312 "namespaces_as_array": NamespaceToArray(self.module.namespace), 313 "imports": self.module.imports, 314 "kinds": self.module.kinds, 315 "enums": self.module.enums, 316 "structs": self.GetStructs(), 317 "interfaces": self.module.interfaces, 318 } 319 320 @UseJinja("cpp_templates/module.h.tmpl", filters=cpp_filters) 321 def GenerateModuleHeader(self): 322 return self.GetJinjaExports() 323 324 @UseJinja("cpp_templates/module-internal.h.tmpl", filters=cpp_filters) 325 def GenerateModuleInternalHeader(self): 326 return self.GetJinjaExports() 327 328 @UseJinja("cpp_templates/module.cc.tmpl", filters=cpp_filters) 329 def GenerateModuleSource(self): 330 return self.GetJinjaExports() 331 332 def GenerateFiles(self, args): 333 self.Write(self.GenerateModuleHeader(), "%s.h" % self.module.name) 334 self.Write(self.GenerateModuleInternalHeader(), 335 "%s-internal.h" % self.module.name) 336 self.Write(self.GenerateModuleSource(), "%s.cc" % self.module.name) 337