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.INT64: "0", 27 mojom.UINT64: "0", 28 mojom.DOUBLE: "0", 29 mojom.STRING: '""', 30 } 31 32 33 def JavaScriptDefaultValue(field): 34 if field.default: 35 if isinstance(field.kind, mojom.Struct): 36 assert field.default == "default" 37 return "new %s()" % JavascriptType(field.kind) 38 return ExpressionToText(field.default) 39 if field.kind in mojom.PRIMITIVES: 40 return _kind_to_javascript_default_value[field.kind] 41 if isinstance(field.kind, mojom.Struct): 42 return "null" 43 if isinstance(field.kind, mojom.Array): 44 return "[]" 45 if isinstance(field.kind, mojom.Interface) or \ 46 isinstance(field.kind, mojom.InterfaceRequest): 47 return _kind_to_javascript_default_value[mojom.MSGPIPE] 48 if isinstance(field.kind, mojom.Enum): 49 return "0" 50 51 52 def JavaScriptPayloadSize(packed): 53 packed_fields = packed.packed_fields 54 if not packed_fields: 55 return 0 56 last_field = packed_fields[-1] 57 offset = last_field.offset + last_field.size 58 pad = pack.GetPad(offset, 8) 59 return offset + pad 60 61 62 _kind_to_codec_type = { 63 mojom.BOOL: "codec.Uint8", 64 mojom.INT8: "codec.Int8", 65 mojom.UINT8: "codec.Uint8", 66 mojom.INT16: "codec.Int16", 67 mojom.UINT16: "codec.Uint16", 68 mojom.INT32: "codec.Int32", 69 mojom.UINT32: "codec.Uint32", 70 mojom.FLOAT: "codec.Float", 71 mojom.HANDLE: "codec.Handle", 72 mojom.DCPIPE: "codec.Handle", 73 mojom.DPPIPE: "codec.Handle", 74 mojom.MSGPIPE: "codec.Handle", 75 mojom.SHAREDBUFFER: "codec.Handle", 76 mojom.INT64: "codec.Int64", 77 mojom.UINT64: "codec.Uint64", 78 mojom.DOUBLE: "codec.Double", 79 mojom.STRING: "codec.String", 80 } 81 82 83 def CodecType(kind): 84 if kind in mojom.PRIMITIVES: 85 return _kind_to_codec_type[kind] 86 if isinstance(kind, mojom.Struct): 87 return "new codec.PointerTo(%s)" % CodecType(kind.name) 88 if isinstance(kind, mojom.Array): 89 return "new codec.ArrayOf(%s)" % CodecType(kind.kind) 90 if isinstance(kind, mojom.Interface) or \ 91 isinstance(kind, mojom.InterfaceRequest): 92 return CodecType(mojom.MSGPIPE) 93 if isinstance(kind, mojom.Enum): 94 return _kind_to_codec_type[mojom.INT32] 95 return kind 96 97 98 def JavaScriptDecodeSnippet(kind): 99 if kind in mojom.PRIMITIVES: 100 return "decodeStruct(%s)" % CodecType(kind) 101 if isinstance(kind, mojom.Struct): 102 return "decodeStructPointer(%s)" % CodecType(kind.name) 103 if isinstance(kind, mojom.Array): 104 return "decodeArrayPointer(%s)" % CodecType(kind.kind) 105 if isinstance(kind, mojom.Interface) or \ 106 isinstance(kind, mojom.InterfaceRequest): 107 return JavaScriptDecodeSnippet(mojom.MSGPIPE) 108 if isinstance(kind, mojom.Enum): 109 return JavaScriptDecodeSnippet(mojom.INT32) 110 111 112 def JavaScriptEncodeSnippet(kind): 113 if kind in mojom.PRIMITIVES: 114 return "encodeStruct(%s, " % CodecType(kind) 115 if isinstance(kind, mojom.Struct): 116 return "encodeStructPointer(%s, " % CodecType(kind.name) 117 if isinstance(kind, mojom.Array): 118 return "encodeArrayPointer(%s, " % CodecType(kind.kind) 119 if isinstance(kind, mojom.Interface) or \ 120 isinstance(kind, mojom.InterfaceRequest): 121 return JavaScriptEncodeSnippet(mojom.MSGPIPE) 122 if isinstance(kind, mojom.Enum): 123 return JavaScriptEncodeSnippet(mojom.INT32) 124 125 126 def TranslateConstants(token): 127 if isinstance(token, (mojom.EnumValue, mojom.NamedValue)): 128 # Both variable and enum constants are constructed like: 129 # NamespaceUid.Struct[.Enum].CONSTANT_NAME 130 name = [] 131 if token.imported_from: 132 name.append(token.imported_from["unique_name"]) 133 if token.parent_kind: 134 name.append(token.parent_kind.name) 135 if isinstance(token, mojom.EnumValue): 136 name.append(token.enum_name) 137 name.append(token.name) 138 return ".".join(name) 139 return token 140 141 142 def ExpressionToText(value): 143 return TranslateConstants(value) 144 145 146 def JavascriptType(kind): 147 if kind.imported_from: 148 return kind.imported_from["unique_name"] + "." + kind.name 149 return kind.name 150 151 152 class Generator(generator.Generator): 153 154 js_filters = { 155 "default_value": JavaScriptDefaultValue, 156 "payload_size": JavaScriptPayloadSize, 157 "decode_snippet": JavaScriptDecodeSnippet, 158 "encode_snippet": JavaScriptEncodeSnippet, 159 "expression_to_text": ExpressionToText, 160 "js_type": JavascriptType, 161 "stylize_method": generator.StudlyCapsToCamel, 162 } 163 164 @UseJinja("js_templates/module.js.tmpl", filters=js_filters) 165 def GenerateJsModule(self): 166 return { 167 "namespace": self.module.namespace, 168 "imports": self.GetImports(), 169 "kinds": self.module.kinds, 170 "enums": self.module.enums, 171 "module": self.module, 172 "structs": self.GetStructs() + self.GetStructsFromMethods(), 173 "interfaces": self.module.interfaces, 174 } 175 176 def GenerateFiles(self, args): 177 self.Write(self.GenerateJsModule(), "%s.js" % self.module.name) 178 179 def GetImports(self): 180 # Since each import is assigned a variable in JS, they need to have unique 181 # names. 182 counter = 1 183 for each in self.module.imports: 184 each["unique_name"] = "import" + str(counter) 185 counter += 1 186 return self.module.imports 187