| 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.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 = ElementCodecType(kind.kind) | |
| 114 return "new codec.%s(%s%s)" % (array_type, element_type, array_length) | |
| 115 if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): | |
| 116 return CodecType(mojom.MSGPIPE) | |
| 117 if mojom.IsEnumKind(kind): | |
| 118 return _kind_to_codec_type[mojom.INT32] | |
| 119 if mojom.IsMapKind(kind): | |
| 120 map_type = "NullableMapOf" if mojom.IsNullableKind(kind) else "MapOf" | |
| 121 key_type = ElementCodecType(kind.key_kind) | |
| 122 value_type = ElementCodecType(kind.value_kind) | |
| 123 return "new codec.%s(%s, %s)" % (map_type, key_type, value_type) | |
| 124 return kind | |
| 125 | |
| 126 def ElementCodecType(kind): | |
| 127 return "codec.PackedBool" if mojom.IsBoolKind(kind) else CodecType(kind) | |
| 128 | |
| 129 def JavaScriptDecodeSnippet(kind): | |
| 130 if kind in mojom.PRIMITIVES: | |
| 131 return "decodeStruct(%s)" % CodecType(kind) | |
| 132 if mojom.IsStructKind(kind): | |
| 133 return "decodeStructPointer(%s)" % JavaScriptType(kind) | |
| 134 if mojom.IsMapKind(kind): | |
| 135 return "decodeMapPointer(%s, %s)" % \ | |
| 136 (ElementCodecType(kind.key_kind), ElementCodecType(kind.value_kind)) | |
| 137 if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind): | |
| 138 return "decodeArrayPointer(codec.PackedBool)" | |
| 139 if mojom.IsArrayKind(kind): | |
| 140 return "decodeArrayPointer(%s)" % CodecType(kind.kind) | |
| 141 if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): | |
| 142 return JavaScriptDecodeSnippet(mojom.MSGPIPE) | |
| 143 if mojom.IsEnumKind(kind): | |
| 144 return JavaScriptDecodeSnippet(mojom.INT32) | |
| 145 | |
| 146 | |
| 147 def JavaScriptEncodeSnippet(kind): | |
| 148 if kind in mojom.PRIMITIVES: | |
| 149 return "encodeStruct(%s, " % CodecType(kind) | |
| 150 if mojom.IsStructKind(kind): | |
| 151 return "encodeStructPointer(%s, " % JavaScriptType(kind) | |
| 152 if mojom.IsMapKind(kind): | |
| 153 return "encodeMapPointer(%s, %s, " % \ | |
| 154 (ElementCodecType(kind.key_kind), ElementCodecType(kind.value_kind)) | |
| 155 if mojom.IsArrayKind(kind) and mojom.IsBoolKind(kind.kind): | |
| 156 return "encodeArrayPointer(codec.PackedBool, "; | |
| 157 if mojom.IsArrayKind(kind): | |
| 158 return "encodeArrayPointer(%s, " % CodecType(kind.kind) | |
| 159 if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): | |
| 160 return JavaScriptEncodeSnippet(mojom.MSGPIPE) | |
| 161 if mojom.IsEnumKind(kind): | |
| 162 return JavaScriptEncodeSnippet(mojom.INT32) | |
| 163 | |
| 164 | |
| 165 def JavaScriptFieldOffset(packed_field): | |
| 166 return "offset + codec.kStructHeaderSize + %s" % packed_field.offset | |
| 167 | |
| 168 | |
| 169 def JavaScriptNullableParam(packed_field): | |
| 170 return "true" if mojom.IsNullableKind(packed_field.field.kind) else "false" | |
| 171 | |
| 172 | |
| 173 def GetArrayExpectedDimensionSizes(kind): | |
| 174 expected_dimension_sizes = [] | |
| 175 while mojom.IsArrayKind(kind): | |
| 176 expected_dimension_sizes.append(generator.ExpectedArraySize(kind) or 0) | |
| 177 kind = kind.kind | |
| 178 # Strings are serialized as variable-length arrays. | |
| 179 if (mojom.IsStringKind(kind)): | |
| 180 expected_dimension_sizes.append(0) | |
| 181 return expected_dimension_sizes | |
| 182 | |
| 183 | |
| 184 def JavaScriptValidateArrayParams(packed_field): | |
| 185 nullable = JavaScriptNullableParam(packed_field) | |
| 186 field_offset = JavaScriptFieldOffset(packed_field) | |
| 187 element_kind = packed_field.field.kind.kind | |
| 188 element_size = pack.PackedField.GetSizeForKind(element_kind) | |
| 189 expected_dimension_sizes = GetArrayExpectedDimensionSizes( | |
| 190 packed_field.field.kind) | |
| 191 element_type = ElementCodecType(element_kind) | |
| 192 return "%s, %s, %s, %s, %s, 0" % \ | |
| 193 (field_offset, element_size, element_type, nullable, | |
| 194 expected_dimension_sizes) | |
| 195 | |
| 196 | |
| 197 def JavaScriptValidateStructParams(packed_field): | |
| 198 nullable = JavaScriptNullableParam(packed_field) | |
| 199 field_offset = JavaScriptFieldOffset(packed_field) | |
| 200 struct_type = JavaScriptType(packed_field.field.kind) | |
| 201 return "%s, %s, %s" % (field_offset, struct_type, nullable) | |
| 202 | |
| 203 | |
| 204 def JavaScriptValidateMapParams(packed_field): | |
| 205 nullable = JavaScriptNullableParam(packed_field) | |
| 206 field_offset = JavaScriptFieldOffset(packed_field) | |
| 207 keys_type = ElementCodecType(packed_field.field.kind.key_kind) | |
| 208 values_kind = packed_field.field.kind.value_kind; | |
| 209 values_type = ElementCodecType(values_kind) | |
| 210 values_nullable = "true" if mojom.IsNullableKind(values_kind) else "false" | |
| 211 return "%s, %s, %s, %s, %s" % \ | |
| 212 (field_offset, nullable, keys_type, values_type, values_nullable) | |
| 213 | |
| 214 | |
| 215 def JavaScriptValidateStringParams(packed_field): | |
| 216 nullable = JavaScriptNullableParam(packed_field) | |
| 217 return "%s, %s" % (JavaScriptFieldOffset(packed_field), nullable) | |
| 218 | |
| 219 | |
| 220 def JavaScriptValidateHandleParams(packed_field): | |
| 221 nullable = JavaScriptNullableParam(packed_field) | |
| 222 field_offset = JavaScriptFieldOffset(packed_field) | |
| 223 return "%s, %s" % (field_offset, nullable) | |
| 224 | |
| 225 | |
| 226 | |
| 227 | |
| 228 def JavaScriptProxyMethodParameterValue(parameter): | |
| 229 name = parameter.name; | |
| 230 if (IsInterfaceParameter(parameter)): | |
| 231 type = JavaScriptType(parameter.kind) | |
| 232 return "core.isHandle(%s) ? %s : connection.bindProxyClient" \ | |
| 233 "(%s, %s, %s.client)" % (name, name, name, type, type) | |
| 234 if (IsInterfaceRequestParameter(parameter)): | |
| 235 type = JavaScriptType(parameter.kind.kind) | |
| 236 return "core.isHandle(%s) ? %s : connection.bindProxyClient" \ | |
| 237 "(%s, %s.client, %s)" % (name, name, name, type, type) | |
| 238 return name; | |
| 239 | |
| 240 def JavaScriptStubMethodParameterValue(parameter): | |
| 241 name = parameter.name; | |
| 242 if (IsInterfaceParameter(parameter)): | |
| 243 type = JavaScriptType(parameter.kind) | |
| 244 return "connection.bindProxyHandle(%s, %s.client, %s)" % (name, type, type) | |
| 245 if (IsInterfaceRequestParameter(parameter)): | |
| 246 type = JavaScriptType(parameter.kind.kind) | |
| 247 return "connection.bindProxyHandle(%s, %s, %s.client)" % (name, type, type) | |
| 248 return name; | |
| 249 | |
| 250 def TranslateConstants(token): | |
| 251 if isinstance(token, (mojom.EnumValue, mojom.NamedValue)): | |
| 252 # Both variable and enum constants are constructed like: | |
| 253 # NamespaceUid.Struct[.Enum].CONSTANT_NAME | |
| 254 name = [] | |
| 255 if token.imported_from: | |
| 256 name.append(token.imported_from["unique_name"]) | |
| 257 if token.parent_kind: | |
| 258 name.append(token.parent_kind.name) | |
| 259 if isinstance(token, mojom.EnumValue): | |
| 260 name.append(token.enum.name) | |
| 261 name.append(token.name) | |
| 262 return ".".join(name) | |
| 263 | |
| 264 if isinstance(token, mojom.BuiltinValue): | |
| 265 if token.value == "double.INFINITY" or token.value == "float.INFINITY": | |
| 266 return "Infinity"; | |
| 267 if token.value == "double.NEGATIVE_INFINITY" or \ | |
| 268 token.value == "float.NEGATIVE_INFINITY": | |
| 269 return "-Infinity"; | |
| 270 if token.value == "double.NAN" or token.value == "float.NAN": | |
| 271 return "NaN"; | |
| 272 | |
| 273 return token | |
| 274 | |
| 275 | |
| 276 def ExpressionToText(value): | |
| 277 return TranslateConstants(value) | |
| 278 | |
| 279 def IsArrayPointerField(field): | |
| 280 return mojom.IsArrayKind(field.kind) | |
| 281 | |
| 282 def IsStringPointerField(field): | |
| 283 return mojom.IsStringKind(field.kind) | |
| 284 | |
| 285 def IsStructPointerField(field): | |
| 286 return mojom.IsStructKind(field.kind) | |
| 287 | |
| 288 def IsMapPointerField(field): | |
| 289 return mojom.IsMapKind(field.kind) | |
| 290 | |
| 291 def IsHandleField(field): | |
| 292 return mojom.IsAnyHandleKind(field.kind) | |
| 293 | |
| 294 def IsInterfaceRequestParameter(parameter): | |
| 295 return mojom.IsInterfaceRequestKind(parameter.kind) | |
| 296 | |
| 297 def IsInterfaceParameter(parameter): | |
| 298 return mojom.IsInterfaceKind(parameter.kind) | |
| 299 | |
| 300 | |
| 301 class Generator(generator.Generator): | |
| 302 | |
| 303 js_filters = { | |
| 304 "default_value": JavaScriptDefaultValue, | |
| 305 "payload_size": JavaScriptPayloadSize, | |
| 306 "decode_snippet": JavaScriptDecodeSnippet, | |
| 307 "encode_snippet": JavaScriptEncodeSnippet, | |
| 308 "expression_to_text": ExpressionToText, | |
| 309 "field_offset": JavaScriptFieldOffset, | |
| 310 "has_callbacks": mojom.HasCallbacks, | |
| 311 "is_array_pointer_field": IsArrayPointerField, | |
| 312 "is_map_pointer_field": IsMapPointerField, | |
| 313 "is_struct_pointer_field": IsStructPointerField, | |
| 314 "is_string_pointer_field": IsStringPointerField, | |
| 315 "is_handle_field": IsHandleField, | |
| 316 "js_type": JavaScriptType, | |
| 317 "is_interface_request_parameter": IsInterfaceRequestParameter, | |
| 318 "is_interface_parameter": IsInterfaceParameter, | |
| 319 "js_proxy_method_parameter_value": JavaScriptProxyMethodParameterValue, | |
| 320 "js_stub_method_parameter_value": JavaScriptStubMethodParameterValue, | |
| 321 "stylize_method": generator.StudlyCapsToCamel, | |
| 322 "validate_array_params": JavaScriptValidateArrayParams, | |
| 323 "validate_handle_params": JavaScriptValidateHandleParams, | |
| 324 "validate_map_params": JavaScriptValidateMapParams, | |
| 325 "validate_string_params": JavaScriptValidateStringParams, | |
| 326 "validate_struct_params": JavaScriptValidateStructParams, | |
| 327 } | |
| 328 | |
| 329 def GetParameters(self): | |
| 330 return { | |
| 331 "namespace": self.module.namespace, | |
| 332 "imports": self.GetImports(), | |
| 333 "kinds": self.module.kinds, | |
| 334 "enums": self.module.enums, | |
| 335 "module": self.module, | |
| 336 "structs": self.GetStructs() + self.GetStructsFromMethods(), | |
| 337 "interfaces": self.module.interfaces, | |
| 338 "imported_interfaces": self.GetImportedInterfaces(), | |
| 339 } | |
| 340 | |
| 341 @UseJinja("js_templates/module.amd.tmpl", filters=js_filters) | |
| 342 def GenerateAMDModule(self): | |
| 343 return self.GetParameters() | |
| 344 | |
| 345 @UseJinja("js_templates/module.sky.tmpl", filters=js_filters) | |
| 346 def GenerateHTMLModule(self): | |
| 347 return self.GetParameters() | |
| 348 | |
| 349 def GenerateFiles(self, args): | |
| 350 self.Write(self.GenerateAMDModule(), | |
| 351 self.MatchMojomFilePath("%s.js" % self.module.name)) | |
| 352 self.Write(self.GenerateHTMLModule(), | |
| 353 self.MatchMojomFilePath("%s.sky" % self.module.name)) | |
| 354 | |
| 355 def GetImports(self): | |
| 356 used_names = set() | |
| 357 for each_import in self.module.imports: | |
| 358 simple_name = each_import["module_name"].split(".")[0] | |
| 359 | |
| 360 # Since each import is assigned a variable in JS, they need to have unique | |
| 361 # names. | |
| 362 unique_name = simple_name | |
| 363 counter = 0 | |
| 364 while unique_name in used_names: | |
| 365 counter += 1 | |
| 366 unique_name = simple_name + str(counter) | |
| 367 | |
| 368 used_names.add(unique_name) | |
| 369 each_import["unique_name"] = unique_name + "$" | |
| 370 counter += 1 | |
| 371 return self.module.imports | |
| 372 | |
| 373 def GetImportedInterfaces(self): | |
| 374 interface_to_import = {}; | |
| 375 for each_import in self.module.imports: | |
| 376 for each_interface in each_import["module"].interfaces: | |
| 377 name = each_interface.name | |
| 378 interface_to_import[name] = each_import["unique_name"] + "." + name | |
| 379 return interface_to_import; | |
| 380 | |
| OLD | NEW |