OLD | NEW |
| (Empty) |
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 JavaScript 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 _kind_to_javascript_default_value = { | |
13 mojom.BOOL: "false", | |
14 mojom.INT8: "0", | |
15 mojom.UINT8: "0", | |
16 mojom.INT16: "0", | |
17 mojom.UINT16: "0", | |
18 mojom.INT32: "0", | |
19 mojom.UINT32: "0", | |
20 mojom.FLOAT: "0", | |
21 mojom.HANDLE: "null", | |
22 mojom.DCPIPE: "null", | |
23 mojom.DPPIPE: "null", | |
24 mojom.MSGPIPE: "null", | |
25 mojom.SHAREDBUFFER: "null", | |
26 mojom.NULLABLE_HANDLE: "null", | |
27 mojom.NULLABLE_DCPIPE: "null", | |
28 mojom.NULLABLE_DPPIPE: "null", | |
29 mojom.NULLABLE_MSGPIPE: "null", | |
30 mojom.NULLABLE_SHAREDBUFFER: "null", | |
31 mojom.INT64: "0", | |
32 mojom.UINT64: "0", | |
33 mojom.DOUBLE: "0", | |
34 mojom.STRING: "null", | |
35 mojom.NULLABLE_STRING: "null" | |
36 } | |
37 | |
38 | |
39 def JavaScriptType(kind): | |
40 if kind.imported_from: | |
41 return kind.imported_from["unique_name"] + "." + kind.name | |
42 return kind.name | |
43 | |
44 | |
45 def JavaScriptDefaultValue(field): | |
46 if field.default: | |
47 if mojom.IsStructKind(field.kind): | |
48 assert field.default == "default" | |
49 return "new %s()" % JavaScriptType(field.kind) | |
50 return ExpressionToText(field.default) | |
51 if field.kind in mojom.PRIMITIVES: | |
52 return _kind_to_javascript_default_value[field.kind] | |
53 if mojom.IsStructKind(field.kind): | |
54 return "null" | |
55 if mojom.IsUnionKind(field.kind): | |
56 return "null" | |
57 if mojom.IsArrayKind(field.kind): | |
58 return "null" | |
59 if mojom.IsMapKind(field.kind): | |
60 return "null" | |
61 if mojom.IsInterfaceKind(field.kind) or \ | |
62 mojom.IsInterfaceRequestKind(field.kind): | |
63 return _kind_to_javascript_default_value[mojom.MSGPIPE] | |
64 if mojom.IsEnumKind(field.kind): | |
65 return "0" | |
66 raise Exception("No valid default: %s" % field) | |
67 | |
68 | |
69 def JavaScriptPayloadSize(packed): | |
70 packed_fields = packed.packed_fields | |
71 if not packed_fields: | |
72 return 0 | |
73 last_field = packed_fields[-1] | |
74 offset = last_field.offset + last_field.size | |
75 pad = pack.GetPad(offset, 8) | |
76 return offset + pad | |
77 | |
78 | |
79 _kind_to_codec_type = { | |
80 mojom.BOOL: "codec.Uint8", | |
81 mojom.INT8: "codec.Int8", | |
82 mojom.UINT8: "codec.Uint8", | |
83 mojom.INT16: "codec.Int16", | |
84 mojom.UINT16: "codec.Uint16", | |
85 mojom.INT32: "codec.Int32", | |
86 mojom.UINT32: "codec.Uint32", | |
87 mojom.FLOAT: "codec.Float", | |
88 mojom.HANDLE: "codec.Handle", | |
89 mojom.DCPIPE: "codec.Handle", | |
90 mojom.DPPIPE: "codec.Handle", | |
91 mojom.MSGPIPE: "codec.Handle", | |
92 mojom.SHAREDBUFFER: "codec.Handle", | |
93 mojom.NULLABLE_HANDLE: "codec.NullableHandle", | |
94 mojom.NULLABLE_DCPIPE: "codec.NullableHandle", | |
95 mojom.NULLABLE_DPPIPE: "codec.NullableHandle", | |
96 mojom.NULLABLE_MSGPIPE: "codec.NullableHandle", | |
97 mojom.NULLABLE_SHAREDBUFFER: "codec.NullableHandle", | |
98 mojom.INT64: "codec.Int64", | |
99 mojom.UINT64: "codec.Uint64", | |
100 mojom.DOUBLE: "codec.Double", | |
101 mojom.STRING: "codec.String", | |
102 mojom.NULLABLE_STRING: "codec.NullableString", | |
103 } | |
104 | |
105 | |
106 def CodecType(kind): | |
107 if kind in mojom.PRIMITIVES: | |
108 return _kind_to_codec_type[kind] | |
109 if mojom.IsStructKind(kind): | |
110 pointer_type = "NullablePointerTo" if mojom.IsNullableKind(kind) \ | |
111 else "PointerTo" | |
112 return "new codec.%s(%s)" % (pointer_type, JavaScriptType(kind)) | |
113 if mojom.IsUnionKind(kind): | |
114 return JavaScriptType(kind) | |
115 if mojom.IsArrayKind(kind): | |
116 array_type = "NullableArrayOf" if mojom.IsNullableKind(kind) else "ArrayOf" | |
117 array_length = "" if kind.length is None else ", %d" % kind.length | |
118 element_type = ElementCodecType(kind.kind) | |
119 return "new codec.%s(%s%s)" % (array_type, element_type, array_length) | |
120 if mojom.IsInterfaceKind(kind): | |
121 return "codec.%s" % ("NullableInterface" if mojom.IsNullableKind(kind) | |
122 else "Interface") | |
123 if mojom.IsInterfaceRequestKind(kind): | |
124 return CodecType(mojom.MSGPIPE) | |
125 if mojom.IsEnumKind(kind): | |
126 return _kind_to_codec_type[mojom.INT32] | |
127 if mojom.IsMapKind(kind): | |
128 map_type = "NullableMapOf" if mojom.IsNullableKind(kind) else "MapOf" | |
129 key_type = ElementCodecType(kind.key_kind) | |
130 value_type = ElementCodecType(kind.value_kind) | |
131 return "new codec.%s(%s, %s)" % (map_type, key_type, value_type) | |
132 raise Exception("No codec type for %s" % kind) | |
133 | |
134 | |
135 def ElementCodecType(kind): | |
136 if mojom.IsUnionKind(kind): | |
137 wrapper_type = "NullableUnionWrapper" if mojom.IsNullableKind(kind) \ | |
138 else "UnionWrapper" | |
139 return "new codec.%s(%s)" % (wrapper_type, JavaScriptType(kind)) | |
140 return "codec.PackedBool" if mojom.IsBoolKind(kind) else CodecType(kind) | |
141 | |
142 def JavaScriptDecodeSnippet(kind): | |
143 if kind in mojom.PRIMITIVES or mojom.IsUnionKind(kind): | |
144 return "decodeStruct(%s)" % CodecType(kind) | |
145 if mojom.IsStructKind(kind): | |
146 return "decodeStructPointer(%s)" % JavaScriptType(kind) | |
147 if mojom.IsMapKind(kind): | |
148 return "decodeMapPointer(%s, %s)" % \ | |
149 (ElementCodecType(kind.key_kind), ElementCodecType(kind.value_kind)) | |
150 if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind): | |
151 return "decodeArrayPointer(codec.PackedBool)" | |
152 if mojom.IsArrayKind(kind): | |
153 return "decodeArrayPointer(%s)" % CodecType(kind.kind) | |
154 if mojom.IsInterfaceKind(kind): | |
155 return "decodeStruct(%s)" % CodecType(kind) | |
156 if mojom.IsUnionKind(kind): | |
157 return "decodeUnion(%s)" % CodecType(kind) | |
158 if mojom.IsInterfaceRequestKind(kind): | |
159 return JavaScriptDecodeSnippet(mojom.MSGPIPE) | |
160 if mojom.IsEnumKind(kind): | |
161 return JavaScriptDecodeSnippet(mojom.INT32) | |
162 raise Exception("No decode snippet for %s" % kind) | |
163 | |
164 | |
165 def JavaScriptEncodeSnippet(kind): | |
166 if kind in mojom.PRIMITIVES or mojom.IsUnionKind(kind): | |
167 return "encodeStruct(%s, " % CodecType(kind) | |
168 if mojom.IsUnionKind(kind): | |
169 return "encodeStruct(%s, " % JavaScriptType(kind) | |
170 if mojom.IsStructKind(kind): | |
171 return "encodeStructPointer(%s, " % JavaScriptType(kind) | |
172 if mojom.IsMapKind(kind): | |
173 return "encodeMapPointer(%s, %s, " % \ | |
174 (ElementCodecType(kind.key_kind), ElementCodecType(kind.value_kind)) | |
175 if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind): | |
176 return "encodeArrayPointer(codec.PackedBool, "; | |
177 if mojom.IsArrayKind(kind): | |
178 return "encodeArrayPointer(%s, " % CodecType(kind.kind) | |
179 if mojom.IsInterfaceKind(kind): | |
180 return "encodeStruct(%s, " % CodecType(kind) | |
181 if mojom.IsInterfaceRequestKind(kind): | |
182 return JavaScriptEncodeSnippet(mojom.MSGPIPE) | |
183 if mojom.IsEnumKind(kind): | |
184 return JavaScriptEncodeSnippet(mojom.INT32) | |
185 raise Exception("No encode snippet for %s" % kind) | |
186 | |
187 | |
188 def JavaScriptUnionDecodeSnippet(kind): | |
189 if mojom.IsUnionKind(kind): | |
190 return "decodeStructPointer(%s)" % JavaScriptType(kind) | |
191 return JavaScriptDecodeSnippet(kind) | |
192 | |
193 | |
194 def JavaScriptUnionEncodeSnippet(kind): | |
195 if mojom.IsUnionKind(kind): | |
196 return "encodeStructPointer(%s, " % JavaScriptType(kind) | |
197 return JavaScriptEncodeSnippet(kind) | |
198 | |
199 | |
200 def JavaScriptFieldOffset(packed_field): | |
201 return "offset + codec.kStructHeaderSize + %s" % packed_field.offset | |
202 | |
203 | |
204 def JavaScriptNullableParam(field): | |
205 return "true" if mojom.IsNullableKind(field.kind) else "false" | |
206 | |
207 | |
208 def GetArrayExpectedDimensionSizes(kind): | |
209 expected_dimension_sizes = [] | |
210 while mojom.IsArrayKind(kind): | |
211 expected_dimension_sizes.append(generator.ExpectedArraySize(kind) or 0) | |
212 kind = kind.kind | |
213 # Strings are serialized as variable-length arrays. | |
214 if (mojom.IsStringKind(kind)): | |
215 expected_dimension_sizes.append(0) | |
216 return expected_dimension_sizes | |
217 | |
218 | |
219 def JavaScriptValidateArrayParams(field): | |
220 nullable = JavaScriptNullableParam(field) | |
221 element_kind = field.kind.kind | |
222 element_size = pack.PackedField.GetSizeForKind(element_kind) | |
223 expected_dimension_sizes = GetArrayExpectedDimensionSizes( | |
224 field.kind) | |
225 element_type = ElementCodecType(element_kind) | |
226 return "%s, %s, %s, %s, 0" % \ | |
227 (element_size, element_type, nullable, | |
228 expected_dimension_sizes) | |
229 | |
230 | |
231 def JavaScriptValidateStructParams(field): | |
232 nullable = JavaScriptNullableParam(field) | |
233 struct_type = JavaScriptType(field.kind) | |
234 return "%s, %s" % (struct_type, nullable) | |
235 | |
236 def JavaScriptValidateUnionParams(field): | |
237 nullable = JavaScriptNullableParam(field) | |
238 union_type = JavaScriptType(field.kind) | |
239 return "%s, %s" % (union_type, nullable) | |
240 | |
241 def JavaScriptValidateMapParams(field): | |
242 nullable = JavaScriptNullableParam(field) | |
243 keys_type = ElementCodecType(field.kind.key_kind) | |
244 values_kind = field.kind.value_kind; | |
245 values_type = ElementCodecType(values_kind) | |
246 values_nullable = "true" if mojom.IsNullableKind(values_kind) else "false" | |
247 return "%s, %s, %s, %s" % \ | |
248 (nullable, keys_type, values_type, values_nullable) | |
249 | |
250 | |
251 def JavaScriptValidateStringParams(field): | |
252 nullable = JavaScriptNullableParam(field) | |
253 return "%s" % (nullable) | |
254 | |
255 | |
256 def JavaScriptValidateHandleParams(field): | |
257 nullable = JavaScriptNullableParam(field) | |
258 return "%s" % (nullable) | |
259 | |
260 def JavaScriptValidateInterfaceParams(field): | |
261 return JavaScriptValidateHandleParams(field) | |
262 | |
263 def JavaScriptProxyMethodParameterValue(parameter): | |
264 name = parameter.name; | |
265 if (mojom.IsInterfaceKind(parameter.kind)): | |
266 type = JavaScriptType(parameter.kind) | |
267 return "core.isHandle(%s) ? %s : connection.bindImpl" \ | |
268 "(%s, %s)" % (name, name, name, type) | |
269 if (mojom.IsInterfaceRequestKind(parameter.kind)): | |
270 type = JavaScriptType(parameter.kind.kind) | |
271 return "core.isHandle(%s) ? %s : connection.bindProxy" \ | |
272 "(%s, %s)" % (name, name, name, type) | |
273 return name; | |
274 | |
275 | |
276 def JavaScriptStubMethodParameterValue(parameter): | |
277 name = parameter.name; | |
278 if (mojom.IsInterfaceKind(parameter.kind)): | |
279 type = JavaScriptType(parameter.kind) | |
280 return "connection.bindHandleToProxy(%s, %s)" % (name, type) | |
281 if (mojom.IsInterfaceRequestKind(parameter.kind)): | |
282 type = JavaScriptType(parameter.kind.kind) | |
283 return "connection.bindHandleToStub(%s, %s)" % (name, type) | |
284 return name; | |
285 | |
286 | |
287 def TranslateConstants(token): | |
288 if isinstance(token, (mojom.EnumValue, mojom.NamedValue)): | |
289 # Both variable and enum constants are constructed like: | |
290 # NamespaceUid.Struct[.Enum].CONSTANT_NAME | |
291 name = [] | |
292 if token.imported_from: | |
293 name.append(token.imported_from["unique_name"]) | |
294 if token.parent_kind: | |
295 name.append(token.parent_kind.name) | |
296 if isinstance(token, mojom.EnumValue): | |
297 name.append(token.enum.name) | |
298 name.append(token.name) | |
299 return ".".join(name) | |
300 | |
301 if isinstance(token, mojom.BuiltinValue): | |
302 if token.value == "double.INFINITY" or token.value == "float.INFINITY": | |
303 return "Infinity"; | |
304 if token.value == "double.NEGATIVE_INFINITY" or \ | |
305 token.value == "float.NEGATIVE_INFINITY": | |
306 return "-Infinity"; | |
307 if token.value == "double.NAN" or token.value == "float.NAN": | |
308 return "NaN"; | |
309 | |
310 return token | |
311 | |
312 | |
313 def ExpressionToText(value): | |
314 return TranslateConstants(value) | |
315 | |
316 def IsArrayPointerField(field): | |
317 return mojom.IsArrayKind(field.kind) | |
318 | |
319 def IsStringPointerField(field): | |
320 return mojom.IsStringKind(field.kind) | |
321 | |
322 def IsStructPointerField(field): | |
323 return mojom.IsStructKind(field.kind) | |
324 | |
325 def IsMapPointerField(field): | |
326 return mojom.IsMapKind(field.kind) | |
327 | |
328 def IsHandleField(field): | |
329 return mojom.IsAnyHandleKind(field.kind) | |
330 | |
331 def IsInterfaceField(field): | |
332 return mojom.IsInterfaceKind(field.kind) | |
333 | |
334 def IsUnionField(field): | |
335 return mojom.IsUnionKind(field.kind) | |
336 | |
337 | |
338 class Generator(generator.Generator): | |
339 | |
340 js_filters = { | |
341 "default_value": JavaScriptDefaultValue, | |
342 "payload_size": JavaScriptPayloadSize, | |
343 "decode_snippet": JavaScriptDecodeSnippet, | |
344 "encode_snippet": JavaScriptEncodeSnippet, | |
345 "union_decode_snippet": JavaScriptUnionDecodeSnippet, | |
346 "union_encode_snippet": JavaScriptUnionEncodeSnippet, | |
347 "expression_to_text": ExpressionToText, | |
348 "field_offset": JavaScriptFieldOffset, | |
349 "has_callbacks": mojom.HasCallbacks, | |
350 "is_array_pointer_field": IsArrayPointerField, | |
351 "is_map_pointer_field": IsMapPointerField, | |
352 "is_struct_pointer_field": IsStructPointerField, | |
353 "is_string_pointer_field": IsStringPointerField, | |
354 "is_union_field": IsUnionField, | |
355 "is_handle_field": IsHandleField, | |
356 "is_interface_field": IsInterfaceField, | |
357 "js_type": JavaScriptType, | |
358 "js_proxy_method_parameter_value": JavaScriptProxyMethodParameterValue, | |
359 "js_stub_method_parameter_value": JavaScriptStubMethodParameterValue, | |
360 "stylize_method": generator.StudlyCapsToCamel, | |
361 "validate_array_params": JavaScriptValidateArrayParams, | |
362 "validate_handle_params": JavaScriptValidateHandleParams, | |
363 "validate_interface_params": JavaScriptValidateInterfaceParams, | |
364 "validate_map_params": JavaScriptValidateMapParams, | |
365 "validate_string_params": JavaScriptValidateStringParams, | |
366 "validate_struct_params": JavaScriptValidateStructParams, | |
367 "validate_union_params": JavaScriptValidateUnionParams, | |
368 } | |
369 | |
370 def GetParameters(self): | |
371 return { | |
372 "namespace": self.module.namespace, | |
373 "imports": self.GetImports(), | |
374 "kinds": self.module.kinds, | |
375 "enums": self.module.enums, | |
376 "module": self.module, | |
377 "structs": self.GetStructs() + self.GetStructsFromMethods(), | |
378 "unions": self.GetUnions(), | |
379 "interfaces": self.GetInterfaces(), | |
380 "imported_interfaces": self.GetImportedInterfaces(), | |
381 } | |
382 | |
383 @UseJinja("js_templates/module.amd.tmpl", filters=js_filters) | |
384 def GenerateAMDModule(self): | |
385 return self.GetParameters() | |
386 | |
387 def GenerateFiles(self, args): | |
388 self.Write(self.GenerateAMDModule(), | |
389 self.MatchMojomFilePath("%s.js" % self.module.name)) | |
390 | |
391 def GetImports(self): | |
392 used_names = set() | |
393 for each_import in self.module.transitive_imports: | |
394 simple_name = each_import["module_name"].split(".")[0] | |
395 | |
396 # Since each import is assigned a variable in JS, they need to have unique | |
397 # names. | |
398 unique_name = simple_name | |
399 counter = 0 | |
400 while unique_name in used_names: | |
401 counter += 1 | |
402 unique_name = simple_name + str(counter) | |
403 | |
404 used_names.add(unique_name) | |
405 each_import["unique_name"] = unique_name + "$" | |
406 counter += 1 | |
407 return self.module.imports | |
408 | |
409 def GetImportedInterfaces(self): | |
410 interface_to_import = {}; | |
411 for each_import in self.module.transitive_imports: | |
412 for each_interface in each_import["module"].interfaces: | |
413 name = each_interface.name | |
414 interface_to_import[name] = each_import["unique_name"] + "." + name | |
415 return interface_to_import; | |
416 | |
OLD | NEW |