Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / mojo / public / tools / bindings / generators / mojom_js_generator.py
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.IsArrayKind(field.kind):
56     return "null"
57   if mojom.IsMapKind(field.kind):
58     return "null"
59   if mojom.IsInterfaceKind(field.kind) or \
60      mojom.IsInterfaceRequestKind(field.kind):
61     return _kind_to_javascript_default_value[mojom.MSGPIPE]
62   if mojom.IsEnumKind(field.kind):
63     return "0"
64
65
66 def JavaScriptPayloadSize(packed):
67   packed_fields = packed.packed_fields
68   if not packed_fields:
69     return 0
70   last_field = packed_fields[-1]
71   offset = last_field.offset + last_field.size
72   pad = pack.GetPad(offset, 8)
73   return offset + pad
74
75
76 _kind_to_codec_type = {
77   mojom.BOOL:                  "codec.Uint8",
78   mojom.INT8:                  "codec.Int8",
79   mojom.UINT8:                 "codec.Uint8",
80   mojom.INT16:                 "codec.Int16",
81   mojom.UINT16:                "codec.Uint16",
82   mojom.INT32:                 "codec.Int32",
83   mojom.UINT32:                "codec.Uint32",
84   mojom.FLOAT:                 "codec.Float",
85   mojom.HANDLE:                "codec.Handle",
86   mojom.DCPIPE:                "codec.Handle",
87   mojom.DPPIPE:                "codec.Handle",
88   mojom.MSGPIPE:               "codec.Handle",
89   mojom.SHAREDBUFFER:          "codec.Handle",
90   mojom.NULLABLE_HANDLE:       "codec.NullableHandle",
91   mojom.NULLABLE_DCPIPE:       "codec.NullableHandle",
92   mojom.NULLABLE_DPPIPE:       "codec.NullableHandle",
93   mojom.NULLABLE_MSGPIPE:      "codec.NullableHandle",
94   mojom.NULLABLE_SHAREDBUFFER: "codec.NullableHandle",
95   mojom.INT64:                 "codec.Int64",
96   mojom.UINT64:                "codec.Uint64",
97   mojom.DOUBLE:                "codec.Double",
98   mojom.STRING:                "codec.String",
99   mojom.NULLABLE_STRING:       "codec.NullableString",
100 }
101
102
103 def CodecType(kind):
104   if kind in mojom.PRIMITIVES:
105     return _kind_to_codec_type[kind]
106   if mojom.IsStructKind(kind):
107     pointer_type = "NullablePointerTo" if mojom.IsNullableKind(kind) \
108         else "PointerTo"
109     return "new codec.%s(%s)" % (pointer_type, JavaScriptType(kind))
110   if mojom.IsArrayKind(kind):
111     array_type = "NullableArrayOf" if mojom.IsNullableKind(kind) else "ArrayOf"
112     array_length = "" if kind.length is None else ", %d" % kind.length
113     element_type = "codec.PackedBool" if mojom.IsBoolKind(kind.kind) \
114         else CodecType(kind.kind)
115     return "new codec.%s(%s%s)" % (array_type, element_type, array_length)
116   if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind):
117     return CodecType(mojom.MSGPIPE)
118   if mojom.IsEnumKind(kind):
119     return _kind_to_codec_type[mojom.INT32]
120   return kind
121
122 def MapCodecType(kind):
123   return "codec.PackedBool" if mojom.IsBoolKind(kind) else CodecType(kind)
124
125 def JavaScriptDecodeSnippet(kind):
126   if kind in mojom.PRIMITIVES:
127     return "decodeStruct(%s)" % CodecType(kind)
128   if mojom.IsStructKind(kind):
129     return "decodeStructPointer(%s)" % JavaScriptType(kind)
130   if mojom.IsMapKind(kind):
131     return "decodeMapPointer(%s, %s)" % \
132         (MapCodecType(kind.key_kind), MapCodecType(kind.value_kind))
133   if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind):
134     return "decodeArrayPointer(codec.PackedBool)"
135   if mojom.IsArrayKind(kind):
136     return "decodeArrayPointer(%s)" % CodecType(kind.kind)
137   if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind):
138     return JavaScriptDecodeSnippet(mojom.MSGPIPE)
139   if mojom.IsEnumKind(kind):
140     return JavaScriptDecodeSnippet(mojom.INT32)
141
142
143 def JavaScriptEncodeSnippet(kind):
144   if kind in mojom.PRIMITIVES:
145     return "encodeStruct(%s, " % CodecType(kind)
146   if mojom.IsStructKind(kind):
147     return "encodeStructPointer(%s, " % JavaScriptType(kind)
148   if mojom.IsMapKind(kind):
149     return "encodeMapPointer(%s, %s, " % \
150         (MapCodecType(kind.key_kind), MapCodecType(kind.value_kind))
151   if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind):
152     return "encodeArrayPointer(codec.PackedBool, ";
153   if mojom.IsArrayKind(kind):
154     return "encodeArrayPointer(%s, " % CodecType(kind.kind)
155   if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind):
156     return JavaScriptEncodeSnippet(mojom.MSGPIPE)
157   if mojom.IsEnumKind(kind):
158     return JavaScriptEncodeSnippet(mojom.INT32)
159
160
161 def JavaScriptFieldOffset(packed_field):
162   return "offset + codec.kStructHeaderSize + %s" % packed_field.offset
163
164
165 def JavaScriptNullableParam(packed_field):
166   return "true" if mojom.IsNullableKind(packed_field.field.kind) else "false"
167
168
169 def GetArrayExpectedDimensionSizes(kind):
170   expected_dimension_sizes = []
171   while mojom.IsArrayKind(kind):
172     expected_dimension_sizes.append(generator.ExpectedArraySize(kind) or 0)
173     kind = kind.kind
174   # Strings are serialized as variable-length arrays.
175   if (mojom.IsStringKind(kind)):
176     expected_dimension_sizes.append(0)
177   return expected_dimension_sizes
178
179
180 def JavaScriptValidateArrayParams(packed_field):
181   nullable = JavaScriptNullableParam(packed_field)
182   field_offset = JavaScriptFieldOffset(packed_field)
183   element_kind = packed_field.field.kind.kind
184   element_size = pack.PackedField.GetSizeForKind(element_kind)
185   expected_dimension_sizes = GetArrayExpectedDimensionSizes(
186       packed_field.field.kind)
187   element_type = "codec.PackedBool" if mojom.IsBoolKind(element_kind) \
188       else CodecType(element_kind)
189   return "%s, %s, %s, %s, %s, 0" % \
190       (field_offset, element_size, element_type, nullable,
191        expected_dimension_sizes)
192
193
194 def JavaScriptValidateStructParams(packed_field):
195   nullable = JavaScriptNullableParam(packed_field)
196   field_offset = JavaScriptFieldOffset(packed_field)
197   struct_type = JavaScriptType(packed_field.field.kind)
198   return "%s, %s, %s" % (field_offset, struct_type, nullable)
199
200
201 def JavaScriptValidateMapParams(packed_field):
202   nullable = JavaScriptNullableParam(packed_field)
203   field_offset = JavaScriptFieldOffset(packed_field)
204   keys_type = MapCodecType(packed_field.field.kind.key_kind)
205   values_kind = packed_field.field.kind.value_kind;
206   values_type = MapCodecType(values_kind)
207   values_nullable = "true" if mojom.IsNullableKind(values_kind) else "false"
208   return "%s, %s, %s, %s, %s" % \
209       (field_offset, nullable, keys_type, values_type, values_nullable)
210
211
212 def JavaScriptValidateStringParams(packed_field):
213   nullable = JavaScriptNullableParam(packed_field)
214   return "%s, %s" % (JavaScriptFieldOffset(packed_field), nullable)
215
216
217 def JavaScriptValidateHandleParams(packed_field):
218   nullable = JavaScriptNullableParam(packed_field)
219   field_offset = JavaScriptFieldOffset(packed_field)
220   return "%s, %s" % (field_offset, nullable)
221
222
223 def TranslateConstants(token):
224   if isinstance(token, (mojom.EnumValue, mojom.NamedValue)):
225     # Both variable and enum constants are constructed like:
226     # NamespaceUid.Struct[.Enum].CONSTANT_NAME
227     name = []
228     if token.imported_from:
229       name.append(token.imported_from["unique_name"])
230     if token.parent_kind:
231       name.append(token.parent_kind.name)
232     if isinstance(token, mojom.EnumValue):
233       name.append(token.enum.name)
234     name.append(token.name)
235     return ".".join(name)
236
237   if isinstance(token, mojom.BuiltinValue):
238     if token.value == "double.INFINITY" or token.value == "float.INFINITY":
239       return "Infinity";
240     if token.value == "double.NEGATIVE_INFINITY" or \
241        token.value == "float.NEGATIVE_INFINITY":
242       return "-Infinity";
243     if token.value == "double.NAN" or token.value == "float.NAN":
244       return "NaN";
245
246   return token
247
248
249 def ExpressionToText(value):
250   return TranslateConstants(value)
251
252
253 def IsArrayPointerField(field):
254   return mojom.IsArrayKind(field.kind)
255
256 def IsStringPointerField(field):
257   return mojom.IsStringKind(field.kind)
258
259 def IsStructPointerField(field):
260   return mojom.IsStructKind(field.kind)
261
262 def IsMapPointerField(field):
263   return mojom.IsMapKind(field.kind)
264
265 def IsHandleField(field):
266   return mojom.IsAnyHandleKind(field.kind)
267
268
269 class Generator(generator.Generator):
270
271   js_filters = {
272     "default_value": JavaScriptDefaultValue,
273     "payload_size": JavaScriptPayloadSize,
274     "decode_snippet": JavaScriptDecodeSnippet,
275     "encode_snippet": JavaScriptEncodeSnippet,
276     "expression_to_text": ExpressionToText,
277     "field_offset": JavaScriptFieldOffset,
278     "has_callbacks": mojom.HasCallbacks,
279     "is_array_pointer_field": IsArrayPointerField,
280     "is_map_pointer_field": IsMapPointerField,
281     "is_struct_pointer_field": IsStructPointerField,
282     "is_string_pointer_field": IsStringPointerField,
283     "is_handle_field": IsHandleField,
284     "js_type": JavaScriptType,
285     "stylize_method": generator.StudlyCapsToCamel,
286     "validate_array_params": JavaScriptValidateArrayParams,
287     "validate_handle_params": JavaScriptValidateHandleParams,
288     "validate_map_params": JavaScriptValidateMapParams,
289     "validate_string_params": JavaScriptValidateStringParams,
290     "validate_struct_params": JavaScriptValidateStructParams,
291   }
292
293   def GetParameters(self):
294     return {
295       "namespace": self.module.namespace,
296       "imports": self.GetImports(),
297       "kinds": self.module.kinds,
298       "enums": self.module.enums,
299       "module": self.module,
300       "structs": self.GetStructs() + self.GetStructsFromMethods(),
301       "interfaces": self.module.interfaces,
302       "imported_interfaces": self.GetImportedInterfaces(),
303     }
304
305   @UseJinja("js_templates/module.amd.tmpl", filters=js_filters)
306   def GenerateAMDModule(self):
307     return self.GetParameters()
308
309   @UseJinja("js_templates/module.sky.tmpl", filters=js_filters)
310   def GenerateHTMLModule(self):
311     return self.GetParameters()
312
313   def GenerateFiles(self, args):
314     self.Write(self.GenerateAMDModule(),
315         self.MatchMojomFilePath("%s.js" % self.module.name))
316     self.Write(self.GenerateHTMLModule(),
317         self.MatchMojomFilePath("%s.sky" % self.module.name))
318
319   def GetImports(self):
320     used_names = set()
321     for each_import in self.module.imports:
322       simple_name = each_import["module_name"].split(".")[0]
323
324       # Since each import is assigned a variable in JS, they need to have unique
325       # names.
326       unique_name = simple_name
327       counter = 0
328       while unique_name in used_names:
329         counter += 1
330         unique_name = simple_name + str(counter)
331
332       used_names.add(unique_name)
333       each_import["unique_name"] = unique_name
334       counter += 1
335     return self.module.imports
336
337   def GetImportedInterfaces(self):
338     interface_to_import = {};
339     for each_import in self.module.imports:
340       for each_interface in each_import["module"].interfaces:
341         name = each_interface.name
342         interface_to_import[name] = each_import["unique_name"] + "." + name
343     return interface_to_import;
344