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.
5 """Generates C++ source files from a mojom.Module."""
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
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",
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",
37 _kind_to_cpp_literal_suffix
= {
45 def ConstantValue(constant
):
46 return ExpressionToText(constant
.value
, kind
=constant
.kind
)
48 def DefaultValue(field
):
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
)
56 def NamespaceToArray(namespace
):
57 return namespace
.split('.') if namespace
else []
59 def GetNameForKind(kind
, internal
= False):
61 if kind
.imported_from
:
62 parts
.extend(NamespaceToArray(kind
.imported_from
["namespace"]))
64 parts
.append("internal")
66 parts
.append(kind
.parent_kind
.name
)
67 parts
.append(kind
.name
)
68 return "::".join(parts
)
71 if mojom
.IsArrayKind(kind
):
72 return "mojo::internal::Array_Data<%s>*" % GetCppType(kind
.kind
)
73 if mojom
.IsMapKind(kind
):
74 return "mojo::internal::Map_Data<%s, %s>*" % (
75 GetCppType(kind
.key_kind
), GetCppType(kind
.value_kind
))
76 if mojom
.IsStructKind(kind
):
77 return "%s_Data*" % GetNameForKind(kind
, internal
=True)
78 if mojom
.IsInterfaceKind(kind
) or mojom
.IsInterfaceRequestKind(kind
):
79 return "mojo::MessagePipeHandle"
80 if mojom
.IsEnumKind(kind
):
82 if mojom
.IsStringKind(kind
):
83 return "mojo::internal::String_Data*"
84 return _kind_to_cpp_type
[kind
]
86 def GetCppPodType(kind
):
87 if mojom
.IsStringKind(kind
):
89 return _kind_to_cpp_type
[kind
]
91 def GetCppArrayArgWrapperType(kind
):
92 if mojom
.IsEnumKind(kind
):
93 return GetNameForKind(kind
)
94 if mojom
.IsStructKind(kind
):
95 return "%sPtr" % GetNameForKind(kind
)
96 if mojom
.IsArrayKind(kind
):
97 return "mojo::Array<%s> " % GetCppArrayArgWrapperType(kind
.kind
)
98 if mojom
.IsMapKind(kind
):
99 return "mojo::Map<%s, %s> " % (GetCppArrayArgWrapperType(kind
.key_kind
),
100 GetCppArrayArgWrapperType(kind
.value_kind
))
101 if mojom
.IsInterfaceKind(kind
):
102 raise Exception("Arrays of interfaces not yet supported!")
103 if mojom
.IsInterfaceRequestKind(kind
):
104 raise Exception("Arrays of interface requests not yet supported!")
105 if mojom
.IsStringKind(kind
):
106 return "mojo::String"
107 if mojom
.IsHandleKind(kind
):
108 return "mojo::ScopedHandle"
109 if mojom
.IsDataPipeConsumerKind(kind
):
110 return "mojo::ScopedDataPipeConsumerHandle"
111 if mojom
.IsDataPipeProducerKind(kind
):
112 return "mojo::ScopedDataPipeProducerHandle"
113 if mojom
.IsMessagePipeKind(kind
):
114 return "mojo::ScopedMessagePipeHandle"
115 if mojom
.IsSharedBufferKind(kind
):
116 return "mojo::ScopedSharedBufferHandle"
117 return _kind_to_cpp_type
[kind
]
119 def GetCppResultWrapperType(kind
):
120 if mojom
.IsEnumKind(kind
):
121 return GetNameForKind(kind
)
122 if mojom
.IsStructKind(kind
):
123 return "%sPtr" % GetNameForKind(kind
)
124 if mojom
.IsArrayKind(kind
):
125 return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind
.kind
)
126 if mojom
.IsMapKind(kind
):
127 return "mojo::Map<%s, %s>" % (GetCppArrayArgWrapperType(kind
.key_kind
),
128 GetCppArrayArgWrapperType(kind
.value_kind
))
129 if mojom
.IsInterfaceKind(kind
):
130 return "%sPtr" % GetNameForKind(kind
)
131 if mojom
.IsInterfaceRequestKind(kind
):
132 return "mojo::InterfaceRequest<%s>" % GetNameForKind(kind
.kind
)
133 if mojom
.IsStringKind(kind
):
134 return "mojo::String"
135 if mojom
.IsHandleKind(kind
):
136 return "mojo::ScopedHandle"
137 if mojom
.IsDataPipeConsumerKind(kind
):
138 return "mojo::ScopedDataPipeConsumerHandle"
139 if mojom
.IsDataPipeProducerKind(kind
):
140 return "mojo::ScopedDataPipeProducerHandle"
141 if mojom
.IsMessagePipeKind(kind
):
142 return "mojo::ScopedMessagePipeHandle"
143 if mojom
.IsSharedBufferKind(kind
):
144 return "mojo::ScopedSharedBufferHandle"
145 return _kind_to_cpp_type
[kind
]
147 def GetCppWrapperType(kind
):
148 if mojom
.IsEnumKind(kind
):
149 return GetNameForKind(kind
)
150 if mojom
.IsStructKind(kind
):
151 return "%sPtr" % GetNameForKind(kind
)
152 if mojom
.IsArrayKind(kind
):
153 return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind
.kind
)
154 if mojom
.IsMapKind(kind
):
155 return "mojo::Map<%s, %s>" % (GetCppArrayArgWrapperType(kind
.key_kind
),
156 GetCppArrayArgWrapperType(kind
.value_kind
))
157 if mojom
.IsInterfaceKind(kind
):
158 return "%sPtr" % GetNameForKind(kind
)
159 if mojom
.IsInterfaceRequestKind(kind
):
160 raise Exception("InterfaceRequest fields not supported!")
161 if mojom
.IsStringKind(kind
):
162 return "mojo::String"
163 if mojom
.IsHandleKind(kind
):
164 return "mojo::ScopedHandle"
165 if mojom
.IsDataPipeConsumerKind(kind
):
166 return "mojo::ScopedDataPipeConsumerHandle"
167 if mojom
.IsDataPipeProducerKind(kind
):
168 return "mojo::ScopedDataPipeProducerHandle"
169 if mojom
.IsMessagePipeKind(kind
):
170 return "mojo::ScopedMessagePipeHandle"
171 if mojom
.IsSharedBufferKind(kind
):
172 return "mojo::ScopedSharedBufferHandle"
173 return _kind_to_cpp_type
[kind
]
175 def GetCppConstWrapperType(kind
):
176 if mojom
.IsStructKind(kind
):
177 return "%sPtr" % GetNameForKind(kind
)
178 if mojom
.IsArrayKind(kind
):
179 return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind
.kind
)
180 if mojom
.IsMapKind(kind
):
181 return "mojo::Map<%s, %s>" % (GetCppArrayArgWrapperType(kind
.key_kind
),
182 GetCppArrayArgWrapperType(kind
.value_kind
))
183 if mojom
.IsInterfaceKind(kind
):
184 return "%sPtr" % GetNameForKind(kind
)
185 if mojom
.IsInterfaceRequestKind(kind
):
186 return "mojo::InterfaceRequest<%s>" % GetNameForKind(kind
.kind
)
187 if mojom
.IsEnumKind(kind
):
188 return GetNameForKind(kind
)
189 if mojom
.IsStringKind(kind
):
190 return "const mojo::String&"
191 if mojom
.IsHandleKind(kind
):
192 return "mojo::ScopedHandle"
193 if mojom
.IsDataPipeConsumerKind(kind
):
194 return "mojo::ScopedDataPipeConsumerHandle"
195 if mojom
.IsDataPipeProducerKind(kind
):
196 return "mojo::ScopedDataPipeProducerHandle"
197 if mojom
.IsMessagePipeKind(kind
):
198 return "mojo::ScopedMessagePipeHandle"
199 if mojom
.IsSharedBufferKind(kind
):
200 return "mojo::ScopedSharedBufferHandle"
201 if not kind
in _kind_to_cpp_type
:
202 print "missing:", kind
.spec
203 return _kind_to_cpp_type
[kind
]
205 def GetCppFieldType(kind
):
206 if mojom
.IsStructKind(kind
):
207 return ("mojo::internal::StructPointer<%s_Data>" %
208 GetNameForKind(kind
, internal
=True))
209 if mojom
.IsArrayKind(kind
):
210 return "mojo::internal::ArrayPointer<%s>" % GetCppType(kind
.kind
)
211 if mojom
.IsMapKind(kind
):
212 return ("mojo::internal::StructPointer<mojo::internal::Map_Data<%s, %s>>" %
213 (GetCppType(kind
.key_kind
), GetCppType(kind
.value_kind
)))
214 if mojom
.IsInterfaceKind(kind
) or mojom
.IsInterfaceRequestKind(kind
):
215 return "mojo::MessagePipeHandle"
216 if mojom
.IsEnumKind(kind
):
217 return GetNameForKind(kind
)
218 if mojom
.IsStringKind(kind
):
219 return "mojo::internal::StringPointer"
220 return _kind_to_cpp_type
[kind
]
222 def IsStructWithHandles(struct
):
223 for pf
in struct
.packed
.packed_fields
:
224 if mojom
.IsAnyHandleKind(pf
.field
.kind
):
228 def TranslateConstants(token
, kind
):
229 if isinstance(token
, mojom
.NamedValue
):
230 # Both variable and enum constants are constructed like:
231 # Namespace::Struct::CONSTANT_NAME
232 # For enums, CONSTANT_NAME is ENUM_NAME_ENUM_VALUE.
234 if token
.imported_from
:
235 name
.extend(NamespaceToArray(token
.namespace
))
236 if token
.parent_kind
:
237 name
.append(token
.parent_kind
.name
)
238 if isinstance(token
, mojom
.EnumValue
):
240 "%s_%s" % (generator
.CamelCaseToAllCaps(token
.enum
.name
), token
.name
))
242 name
.append(token
.name
)
243 return "::".join(name
)
245 if isinstance(token
, mojom
.BuiltinValue
):
246 if token
.value
== "double.INFINITY" or token
.value
== "float.INFINITY":
248 if token
.value
== "double.NEGATIVE_INFINITY" or \
249 token
.value
== "float.NEGATIVE_INFINITY":
251 if token
.value
== "double.NAN" or token
.value
== "float.NAN":
254 if (kind
is not None and mojom
.IsFloatKind(kind
)):
255 return token
if token
.isdigit() else token
+ "f";
257 return '%s%s' % (token
, _kind_to_cpp_literal_suffix
.get(kind
, ''))
259 def ExpressionToText(value
, kind
=None):
260 return TranslateConstants(value
, kind
)
262 def ShouldInlineStruct(struct
):
263 # TODO(darin): Base this on the size of the wrapper class.
264 if len(struct
.fields
) > 4:
266 for field
in struct
.fields
:
267 if mojom
.IsMoveOnlyKind(field
.kind
):
271 def GetArrayValidateParams(kind
):
272 if (not mojom
.IsArrayKind(kind
) and not mojom
.IsMapKind(kind
) and
273 not mojom
.IsStringKind(kind
)):
274 return "mojo::internal::NoValidateParams"
276 if mojom
.IsStringKind(kind
):
277 expected_num_elements
= 0
278 element_is_nullable
= False
279 element_validate_params
= "mojo::internal::NoValidateParams"
280 elif mojom
.IsMapKind(kind
):
281 expected_num_elements
= 0
282 element_is_nullable
= mojom
.IsNullableKind(kind
.value_kind
)
283 element_validate_params
= GetArrayValidateParams(kind
.value_kind
)
285 expected_num_elements
= generator
.ExpectedArraySize(kind
) or 0
286 element_is_nullable
= mojom
.IsNullableKind(kind
.kind
)
287 element_validate_params
= GetArrayValidateParams(kind
.kind
)
289 return "mojo::internal::ArrayValidateParams<%d, %s,\n%s> " % (
290 expected_num_elements
,
291 'true' if element_is_nullable
else 'false',
292 element_validate_params
)
294 def GetMapValidateParams(value_kind
):
295 # Unlike GetArrayValidateParams, we are given the wrapped kind, instead of
296 # the raw array kind. So we wrap the return value of GetArrayValidateParams.
297 element_is_nullable
= mojom
.IsNullableKind(value_kind
)
298 return "mojo::internal::ArrayValidateParams<0, %s,\n%s> " % (
299 'true' if element_is_nullable
else 'false',
300 GetArrayValidateParams(value_kind
))
304 class Generator(generator
.Generator
):
307 "constant_value": ConstantValue
,
308 "cpp_const_wrapper_type": GetCppConstWrapperType
,
309 "cpp_field_type": GetCppFieldType
,
310 "cpp_pod_type": GetCppPodType
,
311 "cpp_result_type": GetCppResultWrapperType
,
312 "cpp_type": GetCppType
,
313 "cpp_wrapper_type": GetCppWrapperType
,
314 "default_value": DefaultValue
,
315 "expression_to_text": ExpressionToText
,
316 "get_array_validate_params": GetArrayValidateParams
,
317 "get_map_validate_params": GetMapValidateParams
,
318 "get_name_for_kind": GetNameForKind
,
319 "get_pad": pack
.GetPad
,
320 "has_callbacks": mojom
.HasCallbacks
,
321 "should_inline": ShouldInlineStruct
,
322 "is_array_kind": mojom
.IsArrayKind
,
323 "is_cloneable_kind": mojom
.IsCloneableKind
,
324 "is_enum_kind": mojom
.IsEnumKind
,
325 "is_move_only_kind": mojom
.IsMoveOnlyKind
,
326 "is_any_handle_kind": mojom
.IsAnyHandleKind
,
327 "is_interface_kind": mojom
.IsInterfaceKind
,
328 "is_interface_request_kind": mojom
.IsInterfaceRequestKind
,
329 "is_map_kind": mojom
.IsMapKind
,
330 "is_nullable_kind": mojom
.IsNullableKind
,
331 "is_object_kind": mojom
.IsObjectKind
,
332 "is_string_kind": mojom
.IsStringKind
,
333 "is_struct_kind": mojom
.IsStructKind
,
334 "is_struct_with_handles": IsStructWithHandles
,
335 "struct_size": lambda ps
: ps
.GetTotalSize() + _HEADER_SIZE
,
336 "struct_from_method": generator
.GetStructFromMethod
,
337 "response_struct_from_method": generator
.GetResponseStructFromMethod
,
338 "stylize_method": generator
.StudlyCapsToCamel
,
339 "to_all_caps": generator
.CamelCaseToAllCaps
,
342 def GetJinjaExports(self
):
344 "module": self
.module
,
345 "namespace": self
.module
.namespace
,
346 "namespaces_as_array": NamespaceToArray(self
.module
.namespace
),
347 "imports": self
.module
.imports
,
348 "kinds": self
.module
.kinds
,
349 "enums": self
.module
.enums
,
350 "structs": self
.GetStructs(),
351 "interfaces": self
.module
.interfaces
,
354 @UseJinja("cpp_templates/module.h.tmpl", filters
=cpp_filters
)
355 def GenerateModuleHeader(self
):
356 return self
.GetJinjaExports()
358 @UseJinja("cpp_templates/module-internal.h.tmpl", filters
=cpp_filters
)
359 def GenerateModuleInternalHeader(self
):
360 return self
.GetJinjaExports()
362 @UseJinja("cpp_templates/module.cc.tmpl", filters
=cpp_filters
)
363 def GenerateModuleSource(self
):
364 return self
.GetJinjaExports()
366 def GenerateFiles(self
, args
):
367 self
.Write(self
.GenerateModuleHeader(),
368 self
.MatchMojomFilePath("%s.h" % self
.module
.name
))
369 self
.Write(self
.GenerateModuleInternalHeader(),
370 self
.MatchMojomFilePath("%s-internal.h" % self
.module
.name
))
371 self
.Write(self
.GenerateModuleSource(),
372 self
.MatchMojomFilePath("%s.cc" % self
.module
.name
))