| 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 |