blob: 59208328e54b4d44c410d3f29c881cb9cec020c0 [file] [log] [blame]
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generates JavaScript source files from a mojom.Module."""
import mojom.generate.generator as generator
import mojom.generate.module as mojom
import mojom.generate.pack as pack
from mojom.generate.template_expander import UseJinja
_kind_to_javascript_default_value = {
mojom.BOOL: "false",
mojom.INT8: "0",
mojom.UINT8: "0",
mojom.INT16: "0",
mojom.UINT16: "0",
mojom.INT32: "0",
mojom.UINT32: "0",
mojom.FLOAT: "0",
mojom.HANDLE: "null",
mojom.DCPIPE: "null",
mojom.DPPIPE: "null",
mojom.MSGPIPE: "null",
mojom.SHAREDBUFFER: "null",
mojom.INT64: "0",
mojom.UINT64: "0",
mojom.DOUBLE: "0",
mojom.STRING: '""',
}
def JavaScriptDefaultValue(field):
if field.default:
if isinstance(field.kind, mojom.Struct):
assert field.default == "default"
return "new %s()" % JavascriptType(field.kind)
return ExpressionToText(field.default)
if field.kind in mojom.PRIMITIVES:
return _kind_to_javascript_default_value[field.kind]
if isinstance(field.kind, mojom.Struct):
return "null"
if isinstance(field.kind, mojom.Array):
return "null"
if isinstance(field.kind, mojom.Interface) or \
isinstance(field.kind, mojom.InterfaceRequest):
return _kind_to_javascript_default_value[mojom.MSGPIPE]
if isinstance(field.kind, mojom.Enum):
return "0"
def JavaScriptPayloadSize(packed):
packed_fields = packed.packed_fields
if not packed_fields:
return 0
last_field = packed_fields[-1]
offset = last_field.offset + last_field.size
pad = pack.GetPad(offset, 8)
return offset + pad
_kind_to_codec_type = {
mojom.BOOL: "codec.Uint8",
mojom.INT8: "codec.Int8",
mojom.UINT8: "codec.Uint8",
mojom.INT16: "codec.Int16",
mojom.UINT16: "codec.Uint16",
mojom.INT32: "codec.Int32",
mojom.UINT32: "codec.Uint32",
mojom.FLOAT: "codec.Float",
mojom.HANDLE: "codec.Handle",
mojom.DCPIPE: "codec.Handle",
mojom.DPPIPE: "codec.Handle",
mojom.MSGPIPE: "codec.Handle",
mojom.SHAREDBUFFER: "codec.Handle",
mojom.INT64: "codec.Int64",
mojom.UINT64: "codec.Uint64",
mojom.DOUBLE: "codec.Double",
mojom.STRING: "codec.String",
}
def CodecType(kind):
if kind in mojom.PRIMITIVES:
return _kind_to_codec_type[kind]
if isinstance(kind, mojom.Struct):
return "new codec.PointerTo(%s)" % CodecType(kind.name)
if isinstance(kind, mojom.Array) and kind.kind == mojom.BOOL:
return "new codec.ArrayOfBoolArrayPointers()"
if isinstance(kind, mojom.Array):
return "new codec.ArrayOf(%s)" % CodecType(kind.kind)
if isinstance(kind, mojom.Interface) or \
isinstance(kind, mojom.InterfaceRequest):
return CodecType(mojom.MSGPIPE)
if isinstance(kind, mojom.Enum):
return _kind_to_codec_type[mojom.INT32]
return kind
def JavaScriptDecodeSnippet(kind):
if kind in mojom.PRIMITIVES:
return "decodeStruct(%s)" % CodecType(kind)
if isinstance(kind, mojom.Struct):
return "decodeStructPointer(%s)" % CodecType(kind.name)
if isinstance(kind, mojom.Array) and kind.kind == mojom.BOOL:
return "decodeBoolArrayPointer()"
if isinstance(kind, mojom.Array):
return "decodeArrayPointer(%s)" % CodecType(kind.kind)
if isinstance(kind, mojom.Interface) or \
isinstance(kind, mojom.InterfaceRequest):
return JavaScriptDecodeSnippet(mojom.MSGPIPE)
if isinstance(kind, mojom.Enum):
return JavaScriptDecodeSnippet(mojom.INT32)
def JavaScriptEncodeSnippet(kind):
if kind in mojom.PRIMITIVES:
return "encodeStruct(%s, " % CodecType(kind)
if isinstance(kind, mojom.Struct):
return "encodeStructPointer(%s, " % CodecType(kind.name)
if isinstance(kind, mojom.Array) and kind.kind == mojom.BOOL:
return "encodeBoolArrayPointer(";
if isinstance(kind, mojom.Array):
return "encodeArrayPointer(%s, " % CodecType(kind.kind)
if isinstance(kind, mojom.Interface) or \
isinstance(kind, mojom.InterfaceRequest):
return JavaScriptEncodeSnippet(mojom.MSGPIPE)
if isinstance(kind, mojom.Enum):
return JavaScriptEncodeSnippet(mojom.INT32)
def TranslateConstants(token):
if isinstance(token, (mojom.EnumValue, mojom.NamedValue)):
# Both variable and enum constants are constructed like:
# NamespaceUid.Struct[.Enum].CONSTANT_NAME
name = []
if token.imported_from:
name.append(token.imported_from["unique_name"])
if token.parent_kind:
name.append(token.parent_kind.name)
if isinstance(token, mojom.EnumValue):
name.append(token.enum_name)
name.append(token.name)
return ".".join(name)
return token
def ExpressionToText(value):
return TranslateConstants(value)
def JavascriptType(kind):
if kind.imported_from:
return kind.imported_from["unique_name"] + "." + kind.name
return kind.name
class Generator(generator.Generator):
js_filters = {
"default_value": JavaScriptDefaultValue,
"payload_size": JavaScriptPayloadSize,
"decode_snippet": JavaScriptDecodeSnippet,
"encode_snippet": JavaScriptEncodeSnippet,
"expression_to_text": ExpressionToText,
"js_type": JavascriptType,
"stylize_method": generator.StudlyCapsToCamel,
}
@UseJinja("js_templates/module.js.tmpl", filters=js_filters)
def GenerateJsModule(self):
return {
"namespace": self.module.namespace,
"imports": self.GetImports(),
"kinds": self.module.kinds,
"enums": self.module.enums,
"module": self.module,
"structs": self.GetStructs() + self.GetStructsFromMethods(),
"interfaces": self.module.interfaces,
}
def GenerateFiles(self, args):
self.Write(self.GenerateJsModule(), "%s.js" % self.module.name)
def GetImports(self):
# Since each import is assigned a variable in JS, they need to have unique
# names.
counter = 1
for each in self.module.imports:
each["unique_name"] = "import" + str(counter)
counter += 1
return self.module.imports