• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7import mojom.generate.generator as generator
8import mojom.generate.module as mojom
9import mojom.generate.pack as pack
10from 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
33def 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
52def 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
83def 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
98def 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
112def 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
126def 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
142def ExpressionToText(value):
143  return TranslateConstants(value)
144
145
146def JavascriptType(kind):
147  if kind.imported_from:
148    return kind.imported_from["unique_name"] + "." + kind.name
149  return kind.name
150
151
152class 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