Upstream version 10.39.225.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.IsAnyArrayKind(field.kind):
56     return "null"
57   if mojom.IsInterfaceKind(field.kind) or \
58      mojom.IsInterfaceRequestKind(field.kind):
59     return _kind_to_javascript_default_value[mojom.MSGPIPE]
60   if mojom.IsEnumKind(field.kind):
61     return "0"
62
63
64 def JavaScriptPayloadSize(packed):
65   packed_fields = packed.packed_fields
66   if not packed_fields:
67     return 0
68   last_field = packed_fields[-1]
69   offset = last_field.offset + last_field.size
70   pad = pack.GetPad(offset, 8)
71   return offset + pad
72
73
74 _kind_to_codec_type = {
75   mojom.BOOL:                  "codec.Uint8",
76   mojom.INT8:                  "codec.Int8",
77   mojom.UINT8:                 "codec.Uint8",
78   mojom.INT16:                 "codec.Int16",
79   mojom.UINT16:                "codec.Uint16",
80   mojom.INT32:                 "codec.Int32",
81   mojom.UINT32:                "codec.Uint32",
82   mojom.FLOAT:                 "codec.Float",
83   mojom.HANDLE:                "codec.Handle",
84   mojom.DCPIPE:                "codec.Handle",
85   mojom.DPPIPE:                "codec.Handle",
86   mojom.MSGPIPE:               "codec.Handle",
87   mojom.SHAREDBUFFER:          "codec.Handle",
88   mojom.NULLABLE_HANDLE:       "codec.NullableHandle",
89   mojom.NULLABLE_DCPIPE:       "codec.NullableHandle",
90   mojom.NULLABLE_DPPIPE:       "codec.NullableHandle",
91   mojom.NULLABLE_MSGPIPE:      "codec.NullableHandle",
92   mojom.NULLABLE_SHAREDBUFFER: "codec.NullableHandle",
93   mojom.INT64:                 "codec.Int64",
94   mojom.UINT64:                "codec.Uint64",
95   mojom.DOUBLE:                "codec.Double",
96   mojom.STRING:                "codec.String",
97   mojom.NULLABLE_STRING:       "codec.NullableString",
98 }
99
100
101 def CodecType(kind):
102   if kind in mojom.PRIMITIVES:
103     return _kind_to_codec_type[kind]
104   if mojom.IsStructKind(kind):
105     pointer_type = "NullablePointerTo" if mojom.IsNullableKind(kind) \
106         else "PointerTo"
107     return "new codec.%s(%s)" % (pointer_type, JavaScriptType(kind))
108   if mojom.IsAnyArrayKind(kind):
109     array_type = "NullableArrayOf" if mojom.IsNullableKind(kind) else "ArrayOf"
110     element_type = "codec.PackedBool" if mojom.IsBoolKind(kind.kind) \
111         else CodecType(kind.kind)
112     return "new codec.%s(%s)" % (array_type, element_type)
113   if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind):
114     return CodecType(mojom.MSGPIPE)
115   if mojom.IsEnumKind(kind):
116     return _kind_to_codec_type[mojom.INT32]
117   return kind
118
119
120 def JavaScriptDecodeSnippet(kind):
121   if kind in mojom.PRIMITIVES:
122     return "decodeStruct(%s)" % CodecType(kind)
123   if mojom.IsStructKind(kind):
124     return "decodeStructPointer(%s)" % JavaScriptType(kind)
125   if mojom.IsAnyArrayKind(kind) and mojom.IsBoolKind(kind.kind):
126     return "decodeArrayPointer(codec.PackedBool)"
127   if mojom.IsAnyArrayKind(kind):
128     return "decodeArrayPointer(%s)" % CodecType(kind.kind)
129   if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind):
130     return JavaScriptDecodeSnippet(mojom.MSGPIPE)
131   if mojom.IsEnumKind(kind):
132     return JavaScriptDecodeSnippet(mojom.INT32)
133
134
135 def JavaScriptEncodeSnippet(kind):
136   if kind in mojom.PRIMITIVES:
137     return "encodeStruct(%s, " % CodecType(kind)
138   if mojom.IsStructKind(kind):
139     return "encodeStructPointer(%s, " % JavaScriptType(kind)
140   if mojom.IsAnyArrayKind(kind) and mojom.IsBoolKind(kind.kind):
141     return "encodeArrayPointer(codec.PackedBool, ";
142   if mojom.IsAnyArrayKind(kind):
143     return "encodeArrayPointer(%s, " % CodecType(kind.kind)
144   if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind):
145     return JavaScriptEncodeSnippet(mojom.MSGPIPE)
146   if mojom.IsEnumKind(kind):
147     return JavaScriptEncodeSnippet(mojom.INT32)
148
149
150 def JavaScriptFieldOffset(packed_field):
151   return "offset + codec.kStructHeaderSize + %s" % packed_field.offset
152
153
154 def JavaScriptNullableParam(packed_field):
155   return "true" if mojom.IsNullableKind(packed_field.field.kind) else "false"
156
157
158 def JavaScriptValidateArrayParams(packed_field):
159   nullable = JavaScriptNullableParam(packed_field)
160   field_offset = JavaScriptFieldOffset(packed_field)
161   element_kind = packed_field.field.kind.kind
162   element_size = pack.PackedField.GetSizeForKind(element_kind)
163   element_count = generator.ExpectedArraySize(packed_field.field.kind)
164   element_type = "codec.PackedBool" if mojom.IsBoolKind(element_kind) \
165       else CodecType(element_kind)
166   return "%s, %s, %s, %s, %s" % \
167       (field_offset, element_size, element_count, element_type, nullable)
168
169
170 def JavaScriptValidateStructParams(packed_field):
171   nullable = JavaScriptNullableParam(packed_field)
172   field_offset = JavaScriptFieldOffset(packed_field)
173   struct_type = JavaScriptType(packed_field.field.kind)
174   return "%s, %s, %s" % (field_offset, struct_type, nullable)
175
176
177 def JavaScriptValidateStringParams(packed_field):
178   nullable = JavaScriptNullableParam(packed_field)
179   return "%s, %s" % (JavaScriptFieldOffset(packed_field), nullable)
180
181
182 def JavaScriptValidateHandleParams(packed_field):
183   nullable = JavaScriptNullableParam(packed_field)
184   field_offset = JavaScriptFieldOffset(packed_field)
185   return "%s, %s" % (field_offset, nullable)
186
187
188 def TranslateConstants(token):
189   if isinstance(token, (mojom.EnumValue, mojom.NamedValue)):
190     # Both variable and enum constants are constructed like:
191     # NamespaceUid.Struct[.Enum].CONSTANT_NAME
192     name = []
193     if token.imported_from:
194       name.append(token.imported_from["unique_name"])
195     if token.parent_kind:
196       name.append(token.parent_kind.name)
197     if isinstance(token, mojom.EnumValue):
198       name.append(token.enum.name)
199     name.append(token.name)
200     return ".".join(name)
201
202   if isinstance(token, mojom.BuiltinValue):
203     if token.value == "double.INFINITY" or token.value == "float.INFINITY":
204       return "Infinity";
205     if token.value == "double.NEGATIVE_INFINITY" or \
206        token.value == "float.NEGATIVE_INFINITY":
207       return "-Infinity";
208     if token.value == "double.NAN" or token.value == "float.NAN":
209       return "NaN";
210
211   return token
212
213
214 def ExpressionToText(value):
215   return TranslateConstants(value)
216
217
218 def IsArrayPointerField(field):
219   return mojom.IsAnyArrayKind(field.kind)
220
221 def IsStringPointerField(field):
222   return mojom.IsStringKind(field.kind)
223
224 def IsStructPointerField(field):
225   return mojom.IsStructKind(field.kind)
226
227 def IsHandleField(field):
228   return mojom.IsAnyHandleKind(field.kind)
229
230
231 class Generator(generator.Generator):
232
233   js_filters = {
234     "default_value": JavaScriptDefaultValue,
235     "payload_size": JavaScriptPayloadSize,
236     "decode_snippet": JavaScriptDecodeSnippet,
237     "encode_snippet": JavaScriptEncodeSnippet,
238     "expression_to_text": ExpressionToText,
239     "field_offset": JavaScriptFieldOffset,
240     "has_callbacks": mojom.HasCallbacks,
241     "is_array_pointer_field": IsArrayPointerField,
242     "is_struct_pointer_field": IsStructPointerField,
243     "is_string_pointer_field": IsStringPointerField,
244     "is_handle_field": IsHandleField,
245     "js_type": JavaScriptType,
246     "stylize_method": generator.StudlyCapsToCamel,
247     "validate_array_params": JavaScriptValidateArrayParams,
248     "validate_handle_params": JavaScriptValidateHandleParams,
249     "validate_string_params": JavaScriptValidateStringParams,
250     "validate_struct_params": JavaScriptValidateStructParams,
251   }
252
253   @UseJinja("js_templates/module.js.tmpl", filters=js_filters)
254   def GenerateJsModule(self):
255     return {
256       "namespace": self.module.namespace,
257       "imports": self.GetImports(),
258       "kinds": self.module.kinds,
259       "enums": self.module.enums,
260       "module": self.module,
261       "structs": self.GetStructs() + self.GetStructsFromMethods(),
262       "interfaces": self.module.interfaces,
263     }
264
265   def GenerateFiles(self, args):
266     self.Write(self.GenerateJsModule(), "%s.js" % self.module.name)
267
268   def GetImports(self):
269     # Since each import is assigned a variable in JS, they need to have unique
270     # names.
271     counter = 1
272     for each in self.module.imports:
273       each["unique_name"] = "import" + str(counter)
274       counter += 1
275     return self.module.imports