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 JavaScript 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
12 _kind_to_javascript_default_value = {
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",
35 mojom.NULLABLE_STRING: "null"
39 def JavaScriptType(kind):
40 if kind.imported_from:
41 return kind.imported_from["unique_name"] + "." + kind.name
45 def JavaScriptDefaultValue(field):
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):
55 if mojom.IsAnyArrayKind(field.kind):
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):
64 def JavaScriptPayloadSize(packed):
65 packed_fields = packed.packed_fields
68 last_field = packed_fields[-1]
69 offset = last_field.offset + last_field.size
70 pad = pack.GetPad(offset, 8)
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",
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) \
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]
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)
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)
150 def JavaScriptFieldOffset(packed_field):
151 return "offset + codec.kStructHeaderSize + %s" % packed_field.offset
154 def JavaScriptNullableParam(packed_field):
155 return "true" if mojom.IsNullableKind(packed_field.field.kind) else "false"
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)
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)
177 def JavaScriptValidateStringParams(packed_field):
178 nullable = JavaScriptNullableParam(packed_field)
179 return "%s, %s" % (JavaScriptFieldOffset(packed_field), nullable)
182 def JavaScriptValidateHandleParams(packed_field):
183 nullable = JavaScriptNullableParam(packed_field)
184 field_offset = JavaScriptFieldOffset(packed_field)
185 return "%s, %s" % (field_offset, nullable)
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
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)
202 if isinstance(token, mojom.BuiltinValue):
203 if token.value == "double.INFINITY" or token.value == "float.INFINITY":
205 if token.value == "double.NEGATIVE_INFINITY" or \
206 token.value == "float.NEGATIVE_INFINITY":
208 if token.value == "double.NAN" or token.value == "float.NAN":
214 def ExpressionToText(value):
215 return TranslateConstants(value)
218 def IsArrayPointerField(field):
219 return mojom.IsAnyArrayKind(field.kind)
221 def IsStringPointerField(field):
222 return mojom.IsStringKind(field.kind)
224 def IsStructPointerField(field):
225 return mojom.IsStructKind(field.kind)
227 def IsHandleField(field):
228 return mojom.IsAnyHandleKind(field.kind)
231 class Generator(generator.Generator):
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,
253 @UseJinja("js_templates/module.js.tmpl", filters=js_filters)
254 def GenerateJsModule(self):
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,
265 def GenerateFiles(self, args):
266 self.Write(self.GenerateJsModule(), "%s.js" % self.module.name)
268 def GetImports(self):
269 # Since each import is assigned a variable in JS, they need to have unique
272 for each in self.module.imports:
273 each["unique_name"] = "import" + str(counter)
275 return self.module.imports