• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.INT64:        "int64_t",
28  mojom.UINT64:       "uint64_t",
29  mojom.DOUBLE:       "double",
30}
31
32def 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
40def NamespaceToArray(namespace):
41  return namespace.split('.') if namespace else []
42
43def 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
54def 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
68def GetCppPodType(kind):
69  if kind.spec == 's':
70    return "char*"
71  return _kind_to_cpp_type[kind]
72
73def 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
98def 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
123def 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
148def 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
175def 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
190def IsStructWithHandles(struct):
191  for pf in struct.packed.packed_fields:
192    if generator.IsHandleKind(pf.field.kind):
193      return True
194  return False
195
196def 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
209def ExpressionToText(value):
210  return TranslateConstants(value)
211
212def HasCallbacks(interface):
213  for method in interface.methods:
214    if method.response_parameters != None:
215      return True
216  return False
217
218def 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
229class 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