summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-20 21:33:12 +0000
committerabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-20 21:33:12 +0000
commitd2eafd1bfcfe59e1d81d3f73a4473d1f1dd9e4b2 (patch)
tree43824a87f7664602c42eaf6eec012c70374b10af
parent659fe72aab8116c77a2dc46b38368ad8d02bdf8a (diff)
downloadchromium_src-d2eafd1bfcfe59e1d81d3f73a4473d1f1dd9e4b2.zip
chromium_src-d2eafd1bfcfe59e1d81d3f73a4473d1f1dd9e4b2.tar.gz
chromium_src-d2eafd1bfcfe59e1d81d3f73a4473d1f1dd9e4b2.tar.bz2
Add JavaScript support to Mojo's bindings generator
This CL contains a first iteration of a JavaScript backend for Mojo's IPC bindings generator. The generated code closely matches the hand-written bindings for simple_service.js, although the generated message is off in a few places. This backend successfully generates code for hello_world_service.mojom and math_calculator.mojom, but do not appear to be computing implicit ordinals yet, which means these generated files not yet work. I'll fix these issues in the next iteration. Unlike the CPP backend, this JS backend uses jinja2 templates. If we're happy with this approach, we'll likely port the CPP backend to jinja2 as well. R=davemoore@chromium.org BUG=317398 Review URL: https://codereview.chromium.org/77153003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@236304 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--mojo/public/bindings/generators/js_templates/module.js.tmpl125
-rw-r--r--mojo/public/bindings/generators/mojom_cpp_generator.py53
-rw-r--r--mojo/public/bindings/generators/mojom_generator.py31
-rw-r--r--mojo/public/bindings/generators/mojom_js_generator.py176
-rw-r--r--mojo/public/bindings/generators/mojom_pack.py33
-rw-r--r--mojo/public/bindings/generators/template_expander.py41
-rw-r--r--mojo/public/bindings/js/codec.js21
-rw-r--r--mojo/public/bindings/mojom_bindings_generator.gypi7
-rwxr-xr-xmojo/public/bindings/mojom_bindings_generator.py4
9 files changed, 452 insertions, 39 deletions
diff --git a/mojo/public/bindings/generators/js_templates/module.js.tmpl b/mojo/public/bindings/generators/js_templates/module.js.tmpl
new file mode 100644
index 0000000..b13aaab7
--- /dev/null
+++ b/mojo/public/bindings/generators/js_templates/module.js.tmpl
@@ -0,0 +1,125 @@
+// 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.
+
+define([
+ "mojo/public/bindings/js/core",
+ "mojo/public/bindings/js/codec",
+ ], function(core, codec) {
+{%- for struct in structs %}
+
+ function {{struct.name}}() {
+{%- for packed_field in struct.packed.packed_fields %}
+ this.{{packed_field.field.name}} = {{packed_field.field|default_value}};
+{%- endfor %}
+ }
+
+ {{struct.name}}.encodedSize = codec.kStructHeaderSize + {{struct.packed|payload_size}};
+
+ {{struct.name}}.decode = function(decoder) {
+ var packed;
+ var val = new {{struct.name}}();
+ var numberOfBytes = decoder.read32();
+ var numberOfFields = decoder.read32();
+{%- for byte in struct.bytes %}
+{%- if byte.packed_fields|length > 1 %}
+ packed = decoder.read8();
+{%- for packed_field in byte.packed_fields %}
+ val.{{packed_field.field.name}} = (packed >> {{packed_field.bit}}) & 1 ? true : false;
+{%- endfor %}
+{%- else %}
+{%- for packed_field in byte.packed_fields %}
+ val.{{packed_field.field.name}} = decoder.{{packed_field.field.kind|decode_snippet}};
+{%- endfor %}
+{%- endif %}
+{%- if byte.is_padding %}
+ decoder.skip(1);
+{%- endif %}
+{%- endfor %}
+ return val;
+ };
+
+ {{struct.name}}.encode = function(encoder, val) {
+ var packed;
+ encoder.write32({{struct.name}}.encodedSize);
+ encoder.write32({{struct.packed.packed_fields|length}});
+
+{%- for byte in struct.bytes %}
+{%- if byte.packed_fields|length > 1 %}
+ packed = 0;
+{%- for packed_field in byte.packed_fields %}
+ packed |= (val.{{packed_field.field.name}} & 1) << {{packed_field.bit}}
+{%- endfor %}
+ encoder.write8(packed);
+{%- else %}
+{%- for packed_field in byte.packed_fields %}
+ encoder.{{packed_field.field.kind|encode_snippet}}val.{{packed_field.field.name}});
+{%- endfor %}
+{%- endif %}
+{%- if byte.is_padding %}
+ encoder.skip(1);
+{%- endif %}
+{%- endfor %}
+ };
+{%- endfor %}
+
+{%- for interface in interfaces %}
+{%- for method in interface.methods %}
+ var k{{interface.name}}_{{method.name}}_Name = {{method.ordinal}};
+{%- endfor %}
+
+ function {{interface.name}}Proxy(receiver) {
+ this.receiver_ = receiver;
+ }
+
+{%- for method in interface.methods %}
+ {{interface.name}}Proxy.prototype.{{method.name}} = function(
+{%- for parameter in method.parameters -%}
+{{parameter.name}}{% if not loop.last %}, {% endif %}
+{%- endfor %}) {
+ var params = new {{interface.name}}_{{method.name}}_Params();
+{%- for parameter in method.parameters %}
+ params.{{parameter.name}} = {{parameter.name}};
+{%- endfor %}
+
+ var builder = new codec.MessageBuilder(
+ k{{interface.name}}_{{method.name}}_Name,
+ codec.align({{interface.name}}_{{method.name}}_Params.encodedSize));
+ builder.encodeStruct({{interface.name}}_{{method.name}}_Params, params);
+ var message = builder.finish();
+ this.receiver_.accept(message);
+ };
+{%- endfor %}
+
+ function {{interface.name}}Stub() {
+ }
+
+ {{interface.name}}Stub.prototype.accept = function(message) {
+ var reader = new codec.MessageReader(message);
+ switch (reader.messageName) {
+{%- for method in interface.methods %}
+ case k{{interface.name}}_{{method.name}}_Name:
+ var params = reader.decodeStruct({{interface.name}}_{{method.name}}_Params);
+ this.{{method.name}}(
+{%- for parameter in method.parameters -%}
+params.{{parameter.name}}{% if not loop.last %}, {% endif %}
+{%- endfor %});
+ return true;
+{%- endfor %}
+ default:
+ return false;
+ }
+ };
+
+{%- endfor %}
+
+ var exports = {};
+{%- for struct in structs if struct.exported %}
+ exports.{{struct.name}} = {{struct.name}};
+{%- endfor %}
+{%- for interface in interfaces %}
+ exports.{{interface.name}}Proxy = {{interface.name}}Proxy;
+ exports.{{interface.name}}Stub = {{interface.name}}Stub;
+{%- endfor %}
+ return exports;
+});
diff --git a/mojo/public/bindings/generators/mojom_cpp_generator.py b/mojo/public/bindings/generators/mojom_cpp_generator.py
index a34a5b5..813491c 100644
--- a/mojo/public/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/bindings/generators/mojom_cpp_generator.py
@@ -6,6 +6,7 @@
import datetime
import mojom
+import mojom_generator
import mojom_pack
import os
import re
@@ -39,22 +40,7 @@ class Lines(object):
return '\n'.join(self.lines)
-def GetStructFromMethod(interface, method):
- """Converts a method's parameters into the fields of a struct."""
- params_class = "%s_%s_Params" % (interface.name, method.name)
- struct = mojom.Struct(params_class)
- for param in method.parameters:
- struct.AddField(param.name, param.kind, param.ordinal)
- return struct
-
-def IsPointerKind(kind):
- return isinstance(kind, (mojom.Struct, mojom.Array)) or kind.spec == 's'
-
-def CamelToUnderscores(camel):
- s = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', camel)
- return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s).lower()
-
-class CPPGenerator(object):
+class CPPGenerator(mojom_generator.Generator):
struct_serialization_compute_template = \
Template(" +\n mojo::internal::ComputeSizeOf($NAME->$FIELD())")
@@ -139,7 +125,7 @@ class CPPGenerator(object):
@classmethod
def GetGetterLine(cls, field):
subs = {'FIELD': field.name, 'TYPE': cls.GetType(field.kind)}
- if IsPointerKind(field.kind):
+ if mojom_generator.IsPointerKind(field.kind):
return cls.ptr_getter_template.substitute(subs)
else:
return cls.getter_template.substitute(subs)
@@ -147,7 +133,7 @@ class CPPGenerator(object):
@classmethod
def GetSetterLine(cls, field):
subs = {'FIELD': field.name, 'TYPE': cls.GetType(field.kind)}
- if IsPointerKind(field.kind):
+ if mojom_generator.IsPointerKind(field.kind):
return cls.ptr_setter_template.substitute(subs)
else:
return cls.setter_template.substitute(subs)
@@ -182,7 +168,7 @@ class CPPGenerator(object):
def GetSerializedFields(cls, ps):
fields = []
for pf in ps.packed_fields:
- if IsPointerKind(pf.field.kind):
+ if mojom_generator.IsPointerKind(pf.field.kind):
fields.append(pf.field)
return fields
@@ -199,21 +185,14 @@ class CPPGenerator(object):
(self.module.name.upper(), name.upper())
def GetHeaderFile(self, *components):
- components = map(lambda c: CamelToUnderscores(c), components)
+ components = map(mojom_generator.CamelToUnderscores, components)
component_string = '_'.join(components)
return os.path.join(self.header_dir, "%s.h" % component_string)
- # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all files
- # to stdout.
- def __init__(self, module, header_dir, output_dir=None):
- self.module = module
- self.header_dir = header_dir
- self.output_dir = output_dir
-
def WriteTemplateToFile(self, template_name, **substitutions):
template = self.GetTemplate(template_name)
- filename = \
- template_name.replace("module", CamelToUnderscores(self.module.name))
+ filename = template_name.replace(
+ "module", mojom_generator.CamelToUnderscores(self.module.name))
substitutions['YEAR'] = datetime.date.today().year
substitutions['NAMESPACE'] = self.module.namespace
if self.output_dir is None:
@@ -252,15 +231,13 @@ class CPPGenerator(object):
if pad > 0:
fields.append(self.pad_template.substitute(COUNT=pad_count, PAD=pad))
pad_count += 1
- size = offset + pad
- else:
- size = 0
+
subs.update(
CLASS = name,
SETTERS = '\n'.join(setters),
GETTERS = '\n'.join(getters),
FIELDS = '\n'.join(fields),
- SIZE = size + self.HEADER_SIZE)
+ SIZE = ps.GetTotalSize() + self.HEADER_SIZE)
return template.substitute(subs)
def GetStructSerialization(
@@ -345,7 +322,7 @@ class CPPGenerator(object):
INTERFACE_STUB_DECLARATIONS = self.GetInterfaceStubDeclarations())
def GetParamsDefinition(self, interface, method, next_id):
- struct = GetStructFromMethod(interface, method)
+ struct = mojom_generator.GetStructFromMethod(interface, method)
method_name = "k%s_%s_Name" % (interface.name, method.name)
if method.ordinal is not None:
next_id = method.ordinal
@@ -372,7 +349,7 @@ class CPPGenerator(object):
sets = []
computes = Lines(self.param_struct_compute_template)
for param in method.parameters:
- if IsPointerKind(param.kind):
+ if mojom_generator.IsPointerKind(param.kind):
sets.append(
self.param_struct_set_template.substitute(NAME=param.name))
computes.Add(NAME=param.name)
@@ -406,7 +383,7 @@ class CPPGenerator(object):
def GetStructSerializationDefinition(self, struct):
ps = mojom_pack.PackedStruct(struct)
- param_name = CamelToUnderscores(struct.name)
+ param_name = mojom_generator.CamelToUnderscores(struct.name)
clones = Lines(self.struct_serialization_clone_template)
sizes = " return sizeof(*%s)" % param_name
@@ -435,7 +412,7 @@ class CPPGenerator(object):
serializations = []
for interface in self.module.interfaces:
for method in interface.methods:
- struct = GetStructFromMethod(interface, method)
+ struct = mojom_generator.GetStructFromMethod(interface, method)
ps = mojom_pack.PackedStruct(struct)
serializations.append(self.GetStructSerialization(
struct.name,
@@ -470,7 +447,7 @@ class CPPGenerator(object):
def GenerateModuleInternalHeader(self):
traits = map(
lambda s: self.GetTemplate("struct_serialization_traits").substitute(
- NAME = CamelToUnderscores(s.name),
+ NAME = mojom_generator.CamelToUnderscores(s.name),
FULL_CLASS = "%s::%s" % (self.module.namespace, s.name)),
self.module.structs);
self.WriteTemplateToFile("module_internal.h",
diff --git a/mojo/public/bindings/generators/mojom_generator.py b/mojo/public/bindings/generators/mojom_generator.py
new file mode 100644
index 0000000..06c59e4
--- /dev/null
+++ b/mojo/public/bindings/generators/mojom_generator.py
@@ -0,0 +1,31 @@
+# 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.
+
+"""Code shared by the various language-specific code generators."""
+
+import mojom
+import re
+
+def GetStructFromMethod(interface, method):
+ """Converts a method's parameters into the fields of a struct."""
+ params_class = "%s_%s_Params" % (interface.name, method.name)
+ struct = mojom.Struct(params_class)
+ for param in method.parameters:
+ struct.AddField(param.name, param.kind, param.ordinal)
+ return struct
+
+def IsPointerKind(kind):
+ return isinstance(kind, (mojom.Struct, mojom.Array)) or kind.spec == 's'
+
+def CamelToUnderscores(camel):
+ s = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', camel)
+ return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s).lower()
+
+class Generator(object):
+ # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all files
+ # to stdout.
+ def __init__(self, module, header_dir, output_dir=None):
+ self.module = module
+ self.header_dir = header_dir
+ self.output_dir = output_dir
diff --git a/mojo/public/bindings/generators/mojom_js_generator.py b/mojo/public/bindings/generators/mojom_js_generator.py
new file mode 100644
index 0000000..e1099be
--- /dev/null
+++ b/mojo/public/bindings/generators/mojom_js_generator.py
@@ -0,0 +1,176 @@
+# 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 JS source files from a mojom.Module."""
+
+import os
+import mojom
+import mojom_pack
+
+from functools import partial
+from template_expander import UseJinja
+from mojom_generator import Generator, GetStructFromMethod, CamelToUnderscores
+
+_kind_to_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: "codec.kInvalidHandle",
+ mojom.INT64: "0",
+ mojom.UINT64: "0",
+ mojom.DOUBLE: "0",
+ mojom.STRING: '""',
+}
+
+
+def DefaultValue(field):
+ if field.default:
+ return field.default
+ if field.kind in mojom.PRIMITIVES:
+ return _kind_to_default_value[field.kind]
+ if isinstance(field.kind, mojom.Struct):
+ return "null";
+ if isinstance(field.kind, mojom.Array):
+ return "[]";
+
+
+def PayloadSize(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 = mojom_pack.GetPad(offset, 8)
+ return offset + pad;
+
+
+_kind_to_javascript_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.INT64: "codec.Int64",
+ mojom.UINT64: "codec.Uint64",
+ mojom.DOUBLE: "codec.Double",
+ mojom.STRING: "codec.String",
+}
+
+
+def GetJavaScriptType(kind):
+ if kind in mojom.PRIMITIVES:
+ return _kind_to_javascript_type[kind]
+ if isinstance(kind, mojom.Struct):
+ return "new codec.PointerTo(%s)" % GetJavaScriptType(kind.name)
+ if isinstance(kind, mojom.Array):
+ return "new codec.ArrayOf(%s)" % GetJavaScriptType(kind.kind)
+ return kind
+
+
+_kind_to_decode_snippet = {
+ mojom.BOOL: "read8() & 1",
+ mojom.INT8: "read8()",
+ mojom.UINT8: "read8()",
+ mojom.INT16: "read16()",
+ mojom.UINT16: "read16()",
+ mojom.INT32: "read32()",
+ mojom.UINT32: "read32()",
+ mojom.FLOAT: "decodeFloat()",
+ mojom.HANDLE: "decodeHandle()",
+ mojom.INT64: "read64()",
+ mojom.UINT64: "read64()",
+ mojom.DOUBLE: "decodeDouble()",
+ mojom.STRING: "decodeString()",
+}
+
+
+def DecodeSnippet(kind):
+ if kind in mojom.PRIMITIVES:
+ return _kind_to_decode_snippet[kind]
+ if isinstance(kind, mojom.Struct):
+ return "decodeStructPointer(%s)" % GetJavaScriptType(kind.name);
+ if isinstance(kind, mojom.Array):
+ return "decodeArrayPointer(%s)" % GetJavaScriptType(kind.kind);
+
+
+_kind_to_encode_snippet = {
+ mojom.BOOL: "write8(1 & ",
+ mojom.INT8: "write8(",
+ mojom.UINT8: "write8(",
+ mojom.INT16: "write16(",
+ mojom.UINT16: "write16(",
+ mojom.INT32: "write32(",
+ mojom.UINT32: "write32(",
+ mojom.FLOAT: "encodeFloat(",
+ mojom.HANDLE: "encodeHandle(",
+ mojom.INT64: "write64(",
+ mojom.UINT64: "write64(",
+ mojom.DOUBLE: "encodeDouble(",
+ mojom.STRING: "encodeString(",
+}
+
+
+def EncodeSnippet(kind):
+ if kind in mojom.PRIMITIVES:
+ return _kind_to_encode_snippet[kind]
+ if isinstance(kind, mojom.Struct):
+ return "encodeStructPointer(%s, " % GetJavaScriptType(kind.name);
+ if isinstance(kind, mojom.Array):
+ return "encodeArrayPointer(%s, " % GetJavaScriptType(kind.kind);
+
+
+def GetStructInfo(exported, struct):
+ packed_struct = mojom_pack.PackedStruct(struct)
+ return {
+ "name": struct.name,
+ "packed": packed_struct,
+ "bytes": mojom_pack.GetByteLayout(packed_struct),
+ "exported": exported,
+ }
+
+
+class JSGenerator(Generator):
+ filters = {
+ "default_value": DefaultValue,
+ "payload_size": PayloadSize,
+ "decode_snippet": DecodeSnippet,
+ "encode_snippet": EncodeSnippet,
+ }
+
+ def GetStructsFromMethods(self):
+ result = []
+ for interface in self.module.interfaces:
+ for method in interface.methods:
+ result.append(GetStructFromMethod(interface, method))
+ return map(partial(GetStructInfo, False), result)
+
+ def GetStructs(self):
+ return map(partial(GetStructInfo, True), self.module.structs)
+
+ @UseJinja("js_templates/module.js.tmpl", filters=filters)
+ def GenerateModule(self):
+ return {
+ "structs": self.GetStructs() + self.GetStructsFromMethods(),
+ "interfaces": self.module.interfaces,
+ }
+
+ def Write(self, contents):
+ if self.output_dir is None:
+ print contents
+ return
+ filename = "%s.js" % CamelToUnderscores(self.module.name)
+ with open(os.path.join(self.output_dir, filename), "w+") as f:
+ f.write(contents)
+
+ def GenerateFiles(self):
+ self.Write(self.GenerateModule())
diff --git a/mojo/public/bindings/generators/mojom_pack.py b/mojo/public/bindings/generators/mojom_pack.py
index 521dc14..3bf47ff 100644
--- a/mojo/public/bindings/generators/mojom_pack.py
+++ b/mojo/public/bindings/generators/mojom_pack.py
@@ -41,10 +41,12 @@ class PackedField(object):
self.offset = None
self.bit = None
+
# Returns the pad necessary to reserve space for alignment of |size|.
def GetPad(offset, size):
return (size - (offset % size)) % size
+
# Returns a 2-tuple of the field offset and bit (for BOOLs)
def GetFieldOffset(field, last_field):
if field.field.kind == mojom.BOOL and \
@@ -100,3 +102,34 @@ class PackedStruct(object):
# Add to end
src_field.offset, src_field.bit = GetFieldOffset(src_field, last_field)
dst_fields.append(src_field)
+
+ def GetTotalSize(self):
+ if not self.packed_fields:
+ return 0;
+ last_field = self.packed_fields[-1]
+ offset = last_field.offset + last_field.size
+ pad = GetPad(offset, 8)
+ return offset + pad;
+
+
+class ByteInfo(object):
+ def __init__(self):
+ self.is_padding = False
+ self.packed_fields = []
+
+
+def GetByteLayout(packed_struct):
+ bytes = [ByteInfo() for i in xrange(packed_struct.GetTotalSize())]
+
+ limit_of_previous_field = 0
+ for packed_field in packed_struct.packed_fields:
+ for i in xrange(limit_of_previous_field, packed_field.offset):
+ bytes[i].is_padding = True
+ bytes[packed_field.offset].packed_fields.append(packed_field)
+ limit_of_previous_field = packed_field.offset + packed_field.size
+
+ for byte in bytes:
+ # A given byte cannot both be padding and have a fields packed into it.
+ assert not (byte.is_padding and byte.packed_fields)
+
+ return bytes
diff --git a/mojo/public/bindings/generators/template_expander.py b/mojo/public/bindings/generators/template_expander.py
new file mode 100644
index 0000000..41c3cc7
--- /dev/null
+++ b/mojo/public/bindings/generators/template_expander.py
@@ -0,0 +1,41 @@
+# 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.
+
+# Based on:
+# http://src.chromium.org/viewvc/blink/trunk/Source/build/scripts/template_expander.py
+
+import os
+import sys
+
+_current_dir = os.path.dirname(os.path.realpath(__file__))
+# jinja2 is in the third_party directory.
+# Insert at front to override system libraries, and after path[0] == script dir
+sys.path.insert(1, os.path.join(_current_dir,
+ os.pardir,
+ os.pardir,
+ os.pardir,
+ os.pardir,
+ 'third_party'))
+import jinja2
+
+
+def ApplyTemplate(path_to_template, params, filters=None):
+ template_directory, template_name = os.path.split(path_to_template)
+ path_to_templates = os.path.join(_current_dir, template_directory)
+ loader = jinja2.FileSystemLoader([path_to_templates])
+ jinja_env = jinja2.Environment(loader=loader, keep_trailing_newline=True)
+ if filters:
+ jinja_env.filters.update(filters)
+ template = jinja_env.get_template(template_name)
+ return template.render(params)
+
+
+def UseJinja(path_to_template, filters=None):
+ def RealDecorator(generator):
+ def GeneratorInternal(*args, **kwargs):
+ parameters = generator(*args, **kwargs)
+ return ApplyTemplate(path_to_template, parameters, filters=filters)
+ GeneratorInternal.func_name = generator.func_name
+ return GeneratorInternal
+ return RealDecorator
diff --git a/mojo/public/bindings/js/codec.js b/mojo/public/bindings/js/codec.js
index d2d108a..2b3f86c 100644
--- a/mojo/public/bindings/js/codec.js
+++ b/mojo/public/bindings/js/codec.js
@@ -382,6 +382,12 @@ define(function() {
this.cls = cls;
};
+ // TODO(abarth): Add missing types:
+ // * String
+ // * Float
+ // * Double
+ // * Signed integers
+
PointerTo.prototype.encodedSize = 8;
PointerTo.prototype.decode = function(decoder) {
@@ -393,6 +399,20 @@ define(function() {
this.cls.encode(objectEncoder, val);
};
+ function ArrayOf(cls) {
+ this.cls = cls;
+ };
+
+ ArrayOf.prototype.encodedSize = 8;
+
+ ArrayOf.prototype.decode = function(decoder) {
+ return decoder.decodeArrayPointer(self.cls);
+ };
+
+ ArrayOf.prototype.encode = function(encoder, val) {
+ encoder.encodeArrayPointer(self.cls, val);
+ };
+
function Handle() {
}
@@ -418,6 +438,7 @@ define(function() {
exports.Uint32 = Uint32;
exports.Uint64 = Uint64;
exports.PointerTo = PointerTo;
+ exports.ArrayOf = ArrayOf;
exports.Handle = Handle;
return exports;
});
diff --git a/mojo/public/bindings/mojom_bindings_generator.gypi b/mojo/public/bindings/mojom_bindings_generator.gypi
index 099e3eb7..8ed8ec49 100644
--- a/mojo/public/bindings/mojom_bindings_generator.gypi
+++ b/mojo/public/bindings/mojom_bindings_generator.gypi
@@ -18,10 +18,15 @@
'<(mojom_bindings_generator)',
'<(DEPTH)/mojo/public/bindings/parse/mojo_parser.py',
'<(DEPTH)/mojo/public/bindings/parse/mojo_translate.py',
+ # TODO(abarth): We should list the cpp_templates here too.
+ '<(DEPTH)/mojo/public/bindings/generators/js_templates/module.js.tmpl',
'<(DEPTH)/mojo/public/bindings/generators/mojom.py',
+ '<(DEPTH)/mojo/public/bindings/generators/mojom_cpp_generator.py',
'<(DEPTH)/mojo/public/bindings/generators/mojom_data.py',
+ '<(DEPTH)/mojo/public/bindings/generators/mojom_generator.py',
+ '<(DEPTH)/mojo/public/bindings/generators/mojom_js_generator.py',
'<(DEPTH)/mojo/public/bindings/generators/mojom_pack.py',
- '<(DEPTH)/mojo/public/bindings/generators/mojom_cpp_generator.py',
+ '<(DEPTH)/mojo/public/bindings/generators/template_expander.py',
],
'outputs': [
'<(output_dir)/<(RULE_INPUT_ROOT).h',
diff --git a/mojo/public/bindings/mojom_bindings_generator.py b/mojo/public/bindings/mojom_bindings_generator.py
index 16cd9e6..41e2615 100755
--- a/mojo/public/bindings/mojom_bindings_generator.py
+++ b/mojo/public/bindings/mojom_bindings_generator.py
@@ -12,6 +12,7 @@ from optparse import OptionParser
from parse import mojo_parser
from parse import mojo_translate
from generators import mojom_data
+from generators import mojom_js_generator
from generators import mojom_cpp_generator
@@ -40,6 +41,9 @@ def Main():
cpp = mojom_cpp_generator.CPPGenerator(
module, options.include_dir, options.output_dir)
cpp.GenerateFiles()
+ js = mojom_js_generator.JSGenerator(
+ module, options.include_dir, options.output_dir)
+ js.GenerateFiles()
if __name__ == '__main__':